在 Ada Last_Chance_Handler 中打印异常消息

Printing the exception message in an Ada Last_Chance_Handler

我正在使用 GNAT 编译器学习 Ada,使用 AdaCore GPS (GPL) IDE,针对 ARM "bare board" 硬件(STM32F4 使用 Ravenscar SFP 运行时)。

对于基于 ARM 的嵌入式工作,我有 C/C++ 背景。

无论如何,我实现了一个"last chance handler",定义如下,

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

这是实际过程(来自 .adb 文件的片段),

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;

Msg 参数记录如下,

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.

我一直在试图弄清楚如何将 null 终止的 Msg 字节转换为 Ada 字符串,以便我可以使用 Put_Line() 调用显示它(调试时我可以通过 semihosting 机制访问这种类型的输出。

我之前通过将 Ada 记录(代表设备寄存器等)的 'Address 属性设置为常量值来将它们映射到物理内存地址。但是,这是我第一次尝试通过变量中保存的 System.Address 值访问内存。

谁能建议我如何实施 Address_To_String() 程序?

我试验过 Ada 字节数组和它们与 System.Address 之间未经检查的转换,也试验过 Ada 指针,但到目前为止我还没有取得任何成功。

如有任何帮助或建议,我们将不胜感激!

非常感谢,

...最大

您要查找的操作可能是Interfaces.C.Strings.Value。它采用 Interfaces.C.Strings.chars_ptr 类型的参数(相当于 C 中的 char * )和 returns a String.

以防万一 不清楚,您完全可以自由声明

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

牢记 Msg 的文档描述。

如果你遇到 last_chance_handler 可能有什么东西坏了,你不应该过分依赖你的环境。 Ada.Text_IO 是一个很重的包裹。你应该尽量避免它,尤其是在这里。

您可以尝试这样的操作:

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;