Use backtrace to solve major problems

Source: Internet
Author: User

When you get an error message such as segmentation fault, it jumps out without reservation. It is very painful to encounter such a problem. It is no less difficult to find the problem than you have worked hard to write the code for more than N days. Is there a better way to obtain debugging information when generating the SIGSEGV signal? Let's take a look at the following routine!

SIGSEGV. h

# Ifndef _ sigsegv_h __< br/> # DEFINE _ sigsegv_h __< br/> # ifdef _ cplusplus <br/> extern "C" {<br/> # endif <br/> int setup_sigsegv (); <br/> # ifdef _ cplusplus <br/>}< br/> # endif <br/> # endif/* _ sigsegv_h __*/

SIGSEGV. c

# Ifndef _ gnu_source <br/> # DEFINE _ gnu_source <br/> # endif <br/> # include <memory. h> <br/> # include <stdlib. h> <br/> # include <stdio. h> <br/> # include <signal. h> <br/> # include <ucontext. h> <br/> # include <dlfcn. h> <br/> # include <execinfo. h> <br/> # ifndef no_cpp_demangle <br/> # include <cxxabi. h> <br/> # ifdef _ cplusplus <br/> using _ cxxabiv1 ::__ cxa_demangle; <br/> # endif <br/> # If defined (reg_rip) <Br/> # define sigsegv_stack_ia64 <br/> # define regformat "% 016lx" <br/> # Elif defined (reg_eip) <br/> # define sigsegv_stack_x86 <br/> # define regformat "% 08x" <br/> # else <br/> # define sigsegv_stack_generic <br/> # define regformat "% X "<br/> # endif <br/> static void signal_segv (int signum, siginfo_t * info, void * PTR) {<br/> static const char * si_codes [3] = {"", "segv_maperr", "segv_accerr"}; <br/> size_t I; <br/> ucontext_t * ucontext = (ucontext_t *) PTR; <br/> # If defined (sigsegv_stack_x86) | defined (sigsegv_stack_ia64) <br/> int f = 0; <br/> dl_info dlinfo; <br/> void ** BP = 0; <br/> void * IP = 0; <br/> # else <br/> void * BT [20]; <br/> char ** strings; <br/> size_t SZ; <br/> # endif <br/> fprintf (stderr, "segmentation fault! /N "); <br/> fprintf (stderr," info. si_signo = % d/N ", SIGNUM); <br/> fprintf (stderr," info. si_errno = % d/N ", info-> si_errno); <br/> fprintf (stderr," info. si_code = % d (% s)/n ", info-> si_code, si_codes [Info-> si_code]); <br/> fprintf (stderr," info. si_addr = % P/N ", info-> si_addr); <br/> for (I = 0; I <ngreg; I ++) <br/>{< br/> fprintf (stderr, "Reg [% 02d] = 0x" regformat "/N", I, ucontext-> uc_mcontext.gregs [I]); <BR/>}< br/> # If defined (sigsegv_stack_x86) | defined (sigsegv_stack_ia64) <br/> # If defined (sigsegv_stack_ia64) <br/> IP = (void *) ucontext-> uc_mcontext.gregs [reg_rip]; <br/> BP = (void **) ucontext-> uc_mcontext.gregs [reg_rbp]; <br/> # Elif defined (sigsegv_stack_x86) <br/> IP = (void *) ucontext-> uc_mcontext.gregs [reg_eip]; <br/> BP = (void **) ucontext-> uc_mcontext.gregs [reg_ebp]; <br/> # endif <br/> fprintf (S Tderr, "stack trace:/N"); <br/> while (BP & IP) <br/>{< br/> If (! Dladdr (IP, & dlinfo) <br/> break; <br/> const char * symname = dlinfo. dli_sname; <br/> # ifndef no_cpp_demangle <br/> int status; <br/> char * TMP = _ cxa_demangle (symname, null, 0, & status ); <br/> If (status = 0 & TMP) <br/>{< br/> symname = TMP; <br/>}< br/> # endif <br/> fprintf (stderr, "% 2D: % P <% S + % u> (% s)/n ", <br/> ++ F, <br/> ip, <br/> symname, <br/> (unsigned long) IP-(unsigned long) dlinfo. dli_saddr, <br/> Dlinfo. dli_fname); <br/> # ifndef no_cpp_demangle <br/> If (TMP) <br/> free (TMP ); <br/> # endif <br/> If (dlinfo. dli_sname &&! Strcmp (dlinfo. dli_sname, "Main") <br/> break; <br/> IP = BP [1]; <br/> BP = (void **) BP [0]; <br/>}< br/> # else <br/> fprintf (stderr, "stack trace (non-dedicated):/N "); <br/> SZ = backtrace (BT, 20); <br/> strings = backtrace_symbols (BT, SZ); <br/> for (I = 0; I <SZ; ++ I) <br/> fprintf (stderr, "% s/n", strings [I]); <br/> # endif <br/> fprintf (stderr, "End of stack trace/N"); <br/> exit (-1); <br/>}< br/> int setup_sigsegv () <br/>{< br/> struct sigaction; <br/> memset (& Action, 0, sizeof (Action); <br/> action. sa_sigaction = signal_segv; <br/> action. sa_flags = sa_siginfo; <br/> If (SIGSEGV, & Action, null) <0) <br/>{< br/> perror ("sigaction "); <br/> return 0; <br/>}< br/> return 1; <br/>}< br/> # ifndef sigsegv_no_auto_init <br/> static void _ attribute (constructor) Init (void) <br/>{< br/> setup_sigsegv (); <br/>}< br/> # endif <br/>

Main. c

# Include "SIGSEGV. H "<br/> # include <string. h> <br/> int die () {<br/> char * err = NULL; <br/> strcpy (ERR, "gonner "); <br/> return 0; <br/>}< br/> int main () {<br/> return die (); <br/>}< br/>

Compile the above main. C program to see what information will be generated, but note that if you want to reference SIGSEGV in your program. h. SIGSEGV. if C gets the stack information, add the-rdynamic-LDL parameter.

 

/data/codes/c/test/backtraces $ gcc -o test -rdynamic -ldl -ggdb -g sigsegv.c main.c/data/codes/c/test/backtraces $ ./testSegmentation Fault!info.si_signo = 11info.si_errno = 0info.si_code  = 1 (SEGV_MAPERR)info.si_addr  = (nil)reg[00]       = 0x00000033reg[01]       = 0x00000000reg[02]       = 0xc010007breg[03]       = 0x0000007breg[04]       = 0x00000000reg[05]       = 0xb7fc8ca0reg[06]       = 0xbff04c2creg[07]       = 0xbff04c1creg[08]       = 0xb7f8cff4reg[09]       = 0x00000001reg[10]       = 0xbff04c50reg[11]       = 0x00000000reg[12]       = 0x0000000ereg[13]       = 0x00000006reg[14]       = 0x080489ecreg[15]       = 0x00000073reg[16]       = 0x00010282reg[17]       = 0xbff04c1creg[18]       = 0x0000007bStack trace: 1: 0x80489ec <die+16> (/data/codes/c/test/backtraces/test) 2: 0x8048a16 <main+19> (/data/codes/c/test/backtraces/test)End of stack trace/data/codes/c/test/backtraces $ 

Next we will use GDB to check the code about the error:

/data/codes/c/test/backtraces $ gdb ./testgdb> disassemble die+16Dump of assembler code for function die:0x080489dc <die+0>:     push   %ebp0x080489dd <die+1>:     mov    %esp,%ebp0x080489df <die+3>:     sub    $0x10,%esp0x080489e2 <die+6>:     movl   $0x0,0xfffffffc(%ebp)0x080489e9 <die+13>:    mov    0xfffffffc(%ebp),%eax0x080489ec <die+16>:    movl   $0x6e6e6f67,(%eax)0x080489f2 <die+22>:    movw   $0x7265,0x4(%eax)0x080489f8 <die+28>:    movb   $0x0,0x6(%eax)0x080489fc <die+32>:    mov    $0x0,%eax0x08048a01 <die+37>:    leave  0x08048a02 <die+38>:    ret    End of assembler dump.

You can also directly debug the break * die + 16 to see the stack before an error occurs. Next let's take a look at what the code problem is.

/data/codes/c/test/backtraces $ gdb ./testgdb> break *die+16
Breakpoint 1 at 0x80489f2: file main.c, line 6.
gdb>list *die+16
0x80489f2 is in die (main.c:6).
1 #include "sigsegv.h"
2 #include <string.h>
3
4 int die() {
5 char *err = NULL;
6 strcpy(err, "gonner");
7 return 0;
8 }
9
10 int main() {

Now let's take a look at how easy it will be to locate the error. Break is not required before the list in the preceding debugging command. It just allows you to see which line of code break has actually pointed out.
Segmentation fault. If you want to release your program, you will not attach debugging information to reduce the volume (that is, do not add-ggdb
-G parameter), but it doesn't matter. You can get the stack-trace information above, and you only need to add the debugging information before debugging.

Source Document

>

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.