adagnateabi

Printing the exception message in an Ada Last_Chance_Handler


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


Solution

  • 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;