简体   繁体   English

即使使用-g3进行编译,addr2line仍返回??:0,gdb backtrace可以工作

[英]addr2line returns ??:0 even when compiled with -g3, gdb backtrace works

For a larger project, I started a small one to program a module which prints me the stack trace on stderr. 对于一个较大的项目,我从一个小项目开始,对一个模块进行编程,该模块在stderr上向我显示堆栈跟踪。 I can catch the exception(signal) and see the stack, however, when I use addr2line my function just prints ??:0. 我可以捕获异常(信号)并查看堆栈,但是,当我使用addr2line时,我的函数仅打印??:0。 I read that you need to compile your programs with -g to get the debug information. 我读到您需要使用-g编译程序以获取调试信息。 Currently, I am always compiling with -g3 so all debug information should be included (right?). 当前,我始终使用-g3进行编译,因此应包括所有调试信息(对吗?)。 Since gdb also need the debug information I tested my small program and I can backtrace my signals correctly. 由于gdb还需要调试信息,因此我测试了我的小程序,并且可以正确地回溯信号。 The function name, the line number, everything works fine. 函数名称,行号,一切正常。 I am also aware that there will be no output for the different includes, since they are not compilled with the -g flag. 我还知道,不同的include将没有输出,因为它们未使用-g标志进行编译。

Here is my code: 这是我的代码:

Source code to cause calamity and the exception handling (set_signal_handler): 引起灾难和异常处理的源代码(set_signal_handler):

#include <stdio.h>
#include <signal.h>
#include <assert.h>
#include <stdbool.h>
#include "Backtrace.h"

int
divide_by_zero();
void
cause_segfault();
void
stack_overflow();
void
infinite_loop();
void
illegal_instruction();
void
cause_calamity();


int main(int argc, char * argv[])
{
    (void) argc;

    set_signal_handler();

    cause_calamity();

    puts("OMG! Nothing bad happend!");
    return 0;
}

void cause_calamity()
{
    /* uncomment one of the following error conditions to cause a calamity of
     your choosing! */

//   (void)divide_by_zero();
     cause_segfault();
//   assert(false);
//   infinite_loop();
//   illegal_instruction();
//   stack_overflow();
}

int divide_by_zero()
{
    int a = 1;
    int b = 0;
    return a / b;
}

void cause_segfault()
{
    int * p = (int*) 0x12345678;
    *p = 0;
}

void
stack_overflow();
void stack_overflow()
{
    int foo[1000]; //allocate something big on the stack
    (void) foo;
    stack_overflow();
}

/* break out with ctrl+c to test SIGINT handling */
void infinite_loop()
{
    while (1)
    {
    };
}

void illegal_instruction()
{
    raise(SIGILL);
}

Source code for exception handling and printing stack trace: 异常处理和打印堆栈跟踪的源代码:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <err.h>
#include <inttypes.h>
#include <execinfo.h>
#include "backtrace.h"

#define MAX_STACK_FRAMES 64

static void *stack_traces[MAX_STACK_FRAMES];


int addr2line(void const * const addr)
{
  char addr2line_cmd[512] = {0};

  /* have addr2line map the address to the relent line in the code */
    sprintf(addr2line_cmd,"addr2line -f -e StackTrace %p", addr);

  /* This will print a nicely formatted string specifying the
     function and source line of the address */
  return system(addr2line_cmd);
}

void posix_print_stack_trace()
{
  int i, trace_size = 0;
  char **messages = (char **)NULL;

  trace_size = backtrace(stack_traces, MAX_STACK_FRAMES);
  messages = backtrace_symbols(stack_traces, trace_size);

  /* skip the first couple stack frames (as they are this function and
     our handler) and also skip the last frame as it's (always?) junk. */
  // for (i = 3; i < (trace_size - 1); ++i)

  for (i = 0; i < trace_size; ++i) //just for testing
  {
    if (addr2line(stack_traces[i]) != 0)
    {
        printf("  error determining line # for: %s\n", messages[i]);
    }
  }
  if (messages) { free(messages); }
}

void posix_signal_handler(int sig, siginfo_t *siginfo, void *context)
{
  (void)context;
  switch(sig)
  {
    case SIGSEGV:
      fputs("Caught SIGSEGV: Segmentation Fault\n", stderr);
      break;
    case SIGINT:
      fputs("Caught SIGINT: Interactive attention signal, (usually ctrl+c)\n",
            stderr);
      break;
    case SIGFPE:
      switch(siginfo->si_code)
      {
        case FPE_INTDIV:
          fputs("Caught SIGFPE: (integer divide by zero)\n", stderr);
          break;
        case FPE_INTOVF:
          fputs("Caught SIGFPE: (integer overflow)\n", stderr);
          break;
        case FPE_FLTDIV:
          fputs("Caught SIGFPE: (floating-point divide by zero)\n", stderr);
          break;
        case FPE_FLTOVF:
          fputs("Caught SIGFPE: (floating-point overflow)\n", stderr);
          break;
        case FPE_FLTUND:
          fputs("Caught SIGFPE: (floating-point underflow)\n", stderr);
          break;
        case FPE_FLTRES:
          fputs("Caught SIGFPE: (floating-point inexact result)\n", stderr);
          break;
        case FPE_FLTINV:
          fputs("Caught SIGFPE: (floating-point invalid operation)\n", stderr);
          break;
        case FPE_FLTSUB:
          fputs("Caught SIGFPE: (subscript out of range)\n", stderr);
          break;
        default:
          fputs("Caught SIGFPE: Arithmetic Exception\n", stderr);
          break;
      }
      break;
    case SIGILL:
      switch(siginfo->si_code)
      {
        case ILL_ILLOPC:
          fputs("Caught SIGILL: (illegal opcode)\n", stderr);
          break;
        case ILL_ILLOPN:
          fputs("Caught SIGILL: (illegal operand)\n", stderr);
          break;
        case ILL_ILLADR:
          fputs("Caught SIGILL: (illegal addressing mode)\n", stderr);
          break;
        case ILL_ILLTRP:
          fputs("Caught SIGILL: (illegal trap)\n", stderr);
          break;
        case ILL_PRVOPC:
          fputs("Caught SIGILL: (privileged opcode)\n", stderr);
          break;
        case ILL_PRVREG:
          fputs("Caught SIGILL: (privileged register)\n", stderr);
          break;
        case ILL_COPROC:
          fputs("Caught SIGILL: (coprocessor error)\n", stderr);
          break;
        case ILL_BADSTK:
          fputs("Caught SIGILL: (internal stack error)\n", stderr);
          break;
        default:
          fputs("Caught SIGILL: Illegal Instruction\n", stderr);
          break;
      }
      break;
    case SIGTERM:
      fputs("Caught SIGTERM: a termination request was sent to the program\n",
            stderr);
      break;
    case SIGABRT:
      fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr);
      break;
    default:
      break;
  }
   posix_print_stack_trace();
  _Exit(1);
}

static uint8_t alternate_stack[SIGSTKSZ];
void set_signal_handler()
{
  /* setup alternate stack */
  {
    stack_t ss = {};
    /* malloc is usually used here, I'm not 100% sure my static allocation
       is valid but it seems to work just fine. */
    ss.ss_sp = (void*)alternate_stack;
    ss.ss_size = SIGSTKSZ;
    ss.ss_flags = 0;

    if (sigaltstack(&ss, NULL) != 0) { err(1, "sigaltstack"); }
  }

  /* register our signal handlers */
  {
    struct sigaction sig_action = {};
    sig_action.sa_sigaction = posix_signal_handler;
    sigemptyset(&sig_action.sa_mask);

        sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;

    if (sigaction(SIGSEGV, &sig_action, NULL) != 0) { err(1, "sigaction"); }
    if (sigaction(SIGFPE,  &sig_action, NULL) != 0) { err(1, "sigaction"); }
    if (sigaction(SIGINT,  &sig_action, NULL) != 0) { err(1, "sigaction"); }
    if (sigaction(SIGILL,  &sig_action, NULL) != 0) { err(1, "sigaction"); }
    if (sigaction(SIGTERM, &sig_action, NULL) != 0) { err(1, "sigaction"); }
    if (sigaction(SIGABRT, &sig_action, NULL) != 0) { err(1, "sigaction"); }
  }
}

This is the output in console when calling the program: 这是调用程序时控制台中的输出:

Caught SIGSEGV: Segmentation Fault
??
??:0
??
??:0
??
??:0
??
??:0
??
??:0
??
??:0
??
??:0
??
??:0

I am using Eclipse for this project and the self-generated makefiles (new c-code project with hello world example). 我为此项目和自生成的makefile(带有hello world示例的新C代码项目)使用Eclipse。 IS this problem somehow connected to eclipse and the makefiles? 这个问题以某种方式与eclipse和makefile有关吗? Or is there an issue with the code? 还是代码有问题?

This is the compiler output: 这是编译器的输出:

make all 
Building file: ../src/Backtrace.c
Invoking: GCC C Compiler
gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/Backtrace.d" -MT"src/Backtrace.o" -o "src/Backtrace.o" "../src/Backtrace.c"
Finished building: ../src/Backtrace.c

Building file: ../src/StackTrace.c
Invoking: GCC C Compiler
gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/StackTrace.d" -MT"src/StackTrace.o" -o "src/StackTrace.o" "../src/StackTrace.c"
Finished building: ../src/StackTrace.c

Building target: StackTrace
Invoking: GCC C Linker
gcc  -o "StackTrace"  ./src/Backtrace.o ./src/StackTrace.o   
Finished building target: StackTrace

I am using Ubuntu 18.04. 我正在使用Ubuntu 18.04。 Any help is appreciated. 任何帮助表示赞赏。

The incorrect address is being used. 使用了不正确的地址。

for instance when messages[0] contains: 例如,当message [0]包含以下内容时:

0x5555557599c0 "/home/richard/Documents/forum/untitled(+0x1058) [0x555555555058]"

Then the parameters passed to addr2line() should be: 然后,传递给addr2line()的参数应为:

-a -f --exe=/home/richard/Documents/forum/untitled +0x1058

then the output will be: 那么输出将是:

0x0000000000001058
posix_signal_handler
/home/richard/Documents/forum/untitled.c:209

You could experiment a bit with the parameters, now that you have the correct parameter info. 现在,有了正确的参数信息,您可以尝试一下参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM