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

时间:2018-07-30 13:26:58

标签: c linux debugging gcc stack-trace

对于一个较大的项目,我从一个小项目开始,对一个模块进行编程,该模块在stderr上向我打印堆栈跟踪。我可以捕获异常(信号)并查看堆栈,但是,当我使用addr2line时,我的函数仅打印??:0。我读到您需要使用-g编译程序以获取调试信息。当前,我始终使用-g3进行编译,因此应包括所有调试信息(对吗?)。由于gdb还需要调试信息,因此我测试了我的小程序,并且可以正确地回溯信号。函数名称,行号,一切正常。我还知道,不同的include不会有输出,因为它们没有带有-g标志。

这是我的代码:

引起灾难和异常处理的源代码(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);
}

用于异常处理和打印堆栈跟踪的源代码:

#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"); }
  }
}

这是调用程序时控制台中的输出:

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

我正在将Eclipse用于该项目和自生成的makefile(带有hello world示例的新C代码项目)。这个问题以某种方式与eclipse和makefile有关吗?还是代码有问题?

这是编译器的输出:

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

我正在使用Ubuntu 18.04。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

使用了错误的地址。

例如,当消息[0]包含:

'"'

然后传递给0x5555557599c0 "/home/richard/Documents/forum/untitled(+0x1058) [0x555555555058]" 的参数应该是:

addr2line()

然后输出将是:

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

既然您具有正确的参数信息,就可以对参数进行一些试验。