1

如何在崩溃时获取包含加载的 ada 共享库的 C++ 应用程序以生成核心转储?

我有一个加载 ada 共享库的 C++ 应用程序,在 ada 代码中出现堆栈溢出错误,导致程序终止以及控制台输出:

raised STORAGE ERROR

即使您在启动应用程序之前发出了“ulimit -c unlimited”,也不会生成核心转储文件。

如果我向应用程序发送 kill SIGSEGV也会发生同样的事情 。

将kill SIGSEGV发送到另一个不使用 ada dll 的应用程序会按照我想要的方式生成核心转储文件。

在这里找到了一些信息:http: //objectmix.com/ada/301203-gnat-fstack-check-does-work.html

更新!正如 Adrien 所说,没有矛盾,-s设置堆栈限制,而-c设置核心文件限制。

问题仍然存在。我在构建 ada 库时检查了这些标志,但未设置fstack-check标志,因此它应该生成核心转储。

虽然我还没有尝试过,但它似乎有些奇怪。它提到了 -fstack-check 编译器选项 + 设置 GNAT_STACK_LIMIT 变量,但同时提到了 ulimit 命令,这似乎是一个矛盾,设置“ulimit -c”是我知道生成核心转储的唯一方法在崩溃时,如果这通过 fstack-check 选项推断,那么我们有一个 catch 22。

4

4 回答 4

7

现在,差不多 2 年后(仍然在 Kristofer 提出问题时在同一家公司工作),再次提出问题 - 最后我想我明白为什么没有生成核心转储!

这个问题是由 Ada 运行时引起的,它默认为一些 POSIX 信号实现信号处理程序(对于 Linux:SIGABRT、SIGFPE、SIGILL、SIGSEGV 和 SIGBUS)。对于 GNAT/linux,信号处理程序在a-init.c中称为__gnat_error_handler,如下所示:

static void
__gnat_error_handler (int sig)
{
  struct Exception_Data *exception;
  char *msg;
  static int recurse = 0;
  ...
  switch (sig)
    {
    case SIGSEGV:

      if (recurse)
      {
        exception = &constraint_error;
        msg = "SIGSEGV";
      }
      else
      {
        ...
        msg = "stack overflow (or erroneous memory access)";
        exception = &storage_error;
      }
      break;
     }
    recurse = 0;
    Raise_From_Signal_Handler (exception, msg);
 }

这个处理程序是“进程范围的”,并且将被任何触发信号调用,无论它来自进程的哪个部分(无论是否以 Ada/C/C++ 编码......)。

调用时,处理程序会引发 Ada 异常并将其留给 Ada 运行时以查找适当的异常处理程序 - 如果未找到此类处理程序(例如,当 C++ 代码的任何部分生成 SIGSEGV 时),Ada -runtime 退回到只是终止进程并从__gnat_error_handler留下一个简单的打印输出(例如“堆栈溢出(或错误的内存访问)”)。

http://www2.adacore.com/gap-static/GNAT_Book/html/node25.htm

为了防止 Ada 运行时处理 POSIX 信号并将其转换为 Ada 异常,可以通过使用禁用默认行为

pragma Interrupt_State (Name => value, State => SYSTEM | RUNTIME | USER); ,

例如。要禁用 SIGSEGV 处理,请定义

Pragma Interrupt_State(SIGSEGV, SYSTEM);

在您的 Ada 代码中 - 现在系统的默认行为将在引发 SIGSEGV 时触发,并且将生成一个核心转储,以便您追踪问题的根源!

我认为这是在 *NIX 平台上混合 Ada 和 C/C++ 时需要注意的一个非常重要的问题,因为它可能会误导您认为问题源于 Ada 代码(因为打印输出表明从 Ada 生成的异常) 当问题的真正根源在于 C/C++ 代码时...

尽管禁用 SIGSEGV 的 Ada 运行时默认处理可能是安全的(我猜没有理智的程序员在任何“预期的”错误处理中使用它......好吧,也许在航空软件或类似软件中使用,当某种“最后的手段" 需要维护功能以避免发生真正糟糕的事情..) 我想应该小心一点,然后“覆盖”信号的 Ada 运行时处理。

一个问题可能是 SIGFPE 信号,默认情况下也会引发 Ada Constraint_Error 异常。Ada 代码可以将这种类型的异常用作“预期行为”。通过 Pragma Interrupt_State 禁用 SIGFPE 可能会严重影响 Ada 代码的执行,并在“正常情况下”使您的应用程序崩溃 - 另一方面,C/C++ 代码中的任何除零都会触发 Ada 异常处理机制,并且让您无法真正找到问题的根源......

于 2012-10-22T15:11:19.323 回答
1

在我看来,这对您的AdaCore支持非常有用。您不可能在该公司之外找到很多熟悉 Gnu Ada 运行时和 C++ 之间交互含义的人。

我建议调试 Ada 代码,您尝试在所有内容周围放置一个最后的异常处理程序,这反过来会转储异常堆栈。大多数供应商都有一些方法可以做到这一点,通常基于 Ada.Exceptions.Exception_Information 和 Ada.Exceptions.Exception_Message。

于 2010-02-10T18:32:30.917 回答
0

我从安全角度(查找恶意软件)找到了一个讨论。基本上有 10 个信号可以尝试,SIGSEGV只是其中之一。

于 2010-02-11T11:13:07.197 回答
0

看来您可以简单地调用sigaction(SIGSEGV, 0, SIG_DFL);来恢复默认信号行为。

于 2010-02-12T10:34:54.990 回答