Revision: 2013-02-16
In fact, you can also use the Backtrace_symbols function of glibc to translate the digital address inside the return address of the stack frame into the symbolic description.
Revision: 2011-06-11
Background knowledge:
· The signal processing mechanism in Linux/unix, knowing the difference between signal function and sigaction
· The concept of segment error, CPU interrupt processing steps, interrupt vector table classification
· Know that CPU exception are divided into fault, traps, and abort to understand their basic differences
· Segment errors and floating-point errors are fault, and when the fault is generated, the address of the error instruction is placed in the stack instead of the address of the next executing instruction
· In Linux/unix, you can call Backstrace to get information about the stack frame.
· The article uses several header files and functions, all belong to glibc, so do not have to worry about finding the wrong file and link error situation
· Addr2line is a system-brought gadget used to convert compiled addresses and source line numbers
Background knowledge we can read books, Google, read the manual (suggested can simply read the resources listed in this article) ..., here do not want to paste a lot of background knowledge, this article mainly introduces in Linux/unix, how to catch a segment error and output the code execution path when error occurs, Finally, a well-encapsulated header file is provided.
OK, here's a straight-down topic:
--Grab the section error first, and don't let it run.
The way to capture a segment error is simple, to call sigaction for a segment error to register a handler function.
struct Sigaction Act;
int sig = SIGSEGV;
Sigemptyset (&act.sa_mask);
Act.sa_sigaction = ONSIGSEGV;
Act.sa_flags = Sa_siginfo;
if (Sigaction (SIG, &act, NULL) <0)
{
Perror ("sigaction:");
}
Signal processing functions
void onsigsegv (int signum, siginfo_t *info, void *ptr)
{
To do: output stack information
Abort ();
}
--Next, the function call path when parsing an error
When a segment error occurs, the function call relationship is reflected on the stack frame, you can get the stack frame information by calling Backstrace in the signal processing function, backstrace the specific description can be Google's/reading header file execinfo.h. The modified handler functions are as follows:
void onsigsegv (int signum, siginfo_t *info, void *ptr)
{
void * ARRAY[25]; /* 25 layers, too much:), you can also set a different value * *
int nSize = backtrace (array, sizeof (array)/sizeof (array[0]));
for (int i=nsize-3; i>=2; i--) {/* Several addresses do not have to be output, crossing if you are curious, you will know if you lose them.
/* Fix the array to point to the code that is executing */[F1]
printf ("SIGSEGV catched when running code at%x\n", (char*) array[i]-1);
}
Abort ();
}
--Further positioning to the exact location of the error
To output the exact location of the error, the third parameter of the signal processing function must be used, and in the Linux/unix environment, the pointer points to a UCONTEXT_T structure. The specifics of this structure can be learned by reading the header file ucontext.h. This structure contains the register site where a segment error occurred, including an EIP register, which is the address of the instruction at the time of the error (because the segment error is a fault).
The further modified signal processing functions are as follows:
void onsigsegv (int signum, siginfo_t *info, void *ptr)
{
void * ARRAY[25];
int nSize = backtrace (array, sizeof (array)/sizeof (array[0]));
for (int i=nsize-3; i>2; i--) {/*/Kinsoku several addresses do not have to output */
/* Fix the array so that the address points to the code that is executing */
printf ("signal[%d] catched when running code at%x\n", Signum, (char*) array[i]-1);
}
if (NULL! = ptr) {
ucontext_t* Ptruc = (ucontext_t*) ptr;
int *pgregs = (int*) (& (Ptruc->uc_mcontext.gregs));
int EIP = Pgregs[reg_eip];
if (EIP! = Array[i]) {/* Some processors will also stack the EIP on the error */
printf ("signal[%d] catched when running code at%x\n", Signum, (char*) array[i]-1);
}
printf ("signal[%d] catched when running code at%x\n", Signum, EIP); /* ERROR Address */
}else{
printf ("signal[%d] catched when running code at unknown address\n", Signum);
}
Abort ();
}
--The path of the calling function and the location of the error are output, but can you read the output?
OK, now the address of the stack frame and the address of the error location have been output in 16, but this is the compiled address, not the source line number, you can read it? So we need to use a Linux/unix gadget addr2line to convert these printed instruction addresses to line numbers, function names.
An example of a performance:
[Email protected] tcpbreak]#./a.out
SIGNAL[11] catched When running code at 804861D
SIGNAL[11] catched When running code at 8048578
SIGNAL[11] catched When running code at 804855A
[Email protected] SuSE tcpbreak]# addr2line 804861d 8048578 804855a-s-c-f-E a.out
Main
Newsig.cpp:55
Oops ()
Newsig.cpp:32
Error (int)
Newsig.cpp:27
The contents of the above output, the specific meaning is:
The captured signal sequence number is one (SIGSEGV)
Execution path is line 52nd-line 32nd-line 27th
The call relationship is Main--oops--error, where a segment error occurs inside the error function, which is the 27th line of the file.
--A little discussion
· You may have read the execinfo.h and found that there is a backtrace_symbols that would like to output the function name above the stack frame by calling it ... You might as well try
· Subtract 1 from the array address element obtained by BackTrace to get the call location? This is true, minus 1 does not guarantee that the address falls to the beginning of the function call when the jump instruction, but can be guaranteed to point to the last byte of the instruction, and the instruction address after addr2line conversion [F2], corresponding to the occurrence of the function call line number.
· Can I not call backstrace to get the contents of the stack frame? Yes, because the content is in the stack, if you know the offset explicitly, you can learn the function call stack, but it takes a lot of thought, and estimates that you write your own copy of Backstrace code, portability becomes a problem.
· Is it necessary to debug a core file through GdB without looking directly at the memory image? In general, needless to do, the advantages of the solutions listed above can be reflected in situations where the core file cannot normally be produced [F3].
· Need to add option-G at compile time? Of course, you do not have to record line number information in the executable file, where to find the line number on the Addr2line. Otherwise, only the function name can be obtained and the line number information cannot be obtained.
--headache, want to use directly, can you get a code that can be used directly?
A header file is provided here (see Attachment Segvcatch.rar), but there is no guarantee that there is no bug. Using the method is simple, just need to include the header file in the source file where the main function is located.
The header file captures floating-point errors and segment errors, as the above example says, in the case of an error, after outputting a series of addresses to STDOUT, and then using Addr2line to convert the address of the output, bingo, the call path at a glance display in front of you!
Marking:
When [F1] invokes a function, it returns the address to the stack, which is the address of the instruction to be executed after the return address.
[F2] In fact, test () is translated into several assembly instructions, and all addresses that point to the corresponding region of these directives will be addr2line converted to the line number corresponding to the call to test ().
[F3] Insufficient permissions, Ulimit not open, the core file is too large ... and other conditions
Resources:
Interrupts and exceptions
Http://blog.csdn.net/shaohaigod1981/archive/2009/11/04/4767915.aspx
Http://hi.baidu.com/hilyjiang/blog/item/cdd7ebb417f8be728bd4b2a1.html
Http://www.logix.cz/michal/doc/i386/chp09-08.htm
ucontext_t Description http://www.gnu.org/s/libc/manual/html_node/System-V-contexts.html
Signal Overview http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html?ca=drs-
Backstrace http://hi.baidu.com/sunkang_2/blog/item/e7dd68df51db585c94ee378f.html
Mans 7 Signal
C + + Capture segment error, print the exact location of the error (exactly to which line)