addr2line returns ??:0 即使在使用 -g3 编译时,gdb 回溯仍然有效
addr2line returns ??:0 even when compiled with -g3, gdb backtrace works
对于一个更大的项目,我开始了一个小项目来编写一个模块,该模块在 stderr 上打印堆栈跟踪。我可以捕获异常(信号)并查看堆栈,但是,当我使用 addr2line 时,我的函数只打印 ??:0。我读到您需要使用 -g 编译您的程序以获取调试信息。目前,我总是使用 -g3 进行编译,因此应该包含所有调试信息(对吗?)。因为 gdb 也需要调试信息,所以我测试了我的小程序,我可以正确地回溯我的信号。函数名称、行号,一切正常。我也知道不同的包含不会有输出,因为它们没有使用 -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。感谢任何帮助。
使用的地址不正确。
例如当 messages[0] 包含:
0x5555557599c0 "/home/richard/Documents/forum/untitled(+0x1058) [0x555555555058]"
那么传给addr2line()
的参数应该是:
-a -f --exe=/home/richard/Documents/forum/untitled +0x1058
那么输出将是:
0x0000000000001058
posix_signal_handler
/home/richard/Documents/forum/untitled.c:209
既然您拥有正确的参数信息,您可以对参数进行一些试验。
对于一个更大的项目,我开始了一个小项目来编写一个模块,该模块在 stderr 上打印堆栈跟踪。我可以捕获异常(信号)并查看堆栈,但是,当我使用 addr2line 时,我的函数只打印 ??:0。我读到您需要使用 -g 编译您的程序以获取调试信息。目前,我总是使用 -g3 进行编译,因此应该包含所有调试信息(对吗?)。因为 gdb 也需要调试信息,所以我测试了我的小程序,我可以正确地回溯我的信号。函数名称、行号,一切正常。我也知道不同的包含不会有输出,因为它们没有使用 -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。感谢任何帮助。
使用的地址不正确。
例如当 messages[0] 包含:
0x5555557599c0 "/home/richard/Documents/forum/untitled(+0x1058) [0x555555555058]"
那么传给addr2line()
的参数应该是:
-a -f --exe=/home/richard/Documents/forum/untitled +0x1058
那么输出将是:
0x0000000000001058
posix_signal_handler
/home/richard/Documents/forum/untitled.c:209
既然您拥有正确的参数信息,您可以对参数进行一些试验。