3
votes

I'm in the process of learning Ada using the GNAT compiler using the AdaCore GPS (GPL) IDE, aimed at ARM "bare board" hardware (STM32F4 using a Ravenscar SFP runtime).

For my ARM based embedded work I've come from a C/C++ background.

Anyway, I've implemented a "last chance handler" that's defined as follows,

procedure Last_Chance_Handler (Msg : System.Address; Line : Integer);
pragma Export (C, Last_Chance_Handler, "__gnat_last_chance_handler");

Here's the actual procedure (a snippet from the .adb file),

procedure Last_Chance_Handler (Msg : System.Address; Line : Integer) is
begin
   LEDs_All_On;
   -- Put_Line("Detail :" & Address_To_String(Msg));
   Put_Line("Line   :" & Line'Image);

   loop
      null;
   end loop;
end Last_Chance_Handler;

The Msg argument is documented as follows,

The Msg parameter is a C null-terminated string representing the source location of the raise statement, as generated by the compiler, or a zero-length string if pragma Suppress_Exception_Locations is used.

I've been trying to figure out how to convert the null terminated Msg bytes to an Ada string so that I can display it using a Put_Line() call (when debugging I can access this type of output via the semihosting mechanism).

I've previously mapped Ada records (representing device registers etc.) to physical memory addresses by setting their 'Address attribute to a constant value. However, this is the first time I've tried access memory via a System.Address value held in a variable.

Can anyone suggest how I might go about implementing the Address_To_String() procedure?

I have experimented with Ada byte arrays and unchecked conversions between them and System.Address, also with Ada pointers, but so far I've not had any success.

Any help or suggestions would be greatly appreciated!

Many thanks,

...Max

3

3 Answers

4
votes

Just in case it wasn’t clear from Jacob’s answer, you’re perfectly at liberty to declare

with Interfaces.C.Strings;
procedure Last_Chance_Handler
  (Msg : Interfaces.C.Strings.chars_ptr; Line : Integer);

bearing in mind the documented description of Msg.

3
votes

If you come to a last_chance_handler something is probably broken and you shouldnt rely too much on your environment. Ada.Text_IO is a very heavy package. You should try to avoid it generally and especially here.

You could try something like this:

with GNAT.IO;
with System.Storage_Elements;
procedure Last_Chance_Handler
   (Msg : System.Address; Line : Integer)
is
   use System.Storage_Elements; -- make "+" visible for System.Address

   function Peek (Addr : System.Address) return Character
   is
      C : Character with Address => Addr;
   begin
      return C;
   end Peek; 
   A : System.Address := Msg;
begin
   GNAT.IO.Put ("line :");
   GNAT.IO.Put (line); -- avoid the secondary stack for Line'Image
   GNAT.IO.New_Line;
   while Peek(A) /= ASCII.NUL loop
      GNAT.IO.Put (Peek(A));
      A := A + 1;
   end loop;
   GNAT.IO.New_Line;
end;
3
votes

The operation you are looking for is probably Interfaces.C.Strings.Value. It takes an argument of the type Interfaces.C.Strings.chars_ptr (equivalent to char * in C) and returns a String.