Linux c user-mode debugging tracking function call stacks and locating segment errors [Reproduced], linux Stack

Source: Internet
Author: User

Linux c user-mode debugging tracking function call stacks and locating segment errors [Reproduced], linux Stack

Generally, the method to view the stack when a function is running is to use an external debugger such as GDB (bt command). However, in some cases, to analyze program bugs, (mainly for analysis of long-running programs), it is very useful to print the function call stack when a program error occurs.

In the glibc header file "execinfo. h", three functions are declared to obtain the function call stack of the current thread.

Int backtrace (void ** buffer, int size)

This function is used to obtain the call stack of the current thread. The obtained information will be stored in the buffer, which is a pointer list. The size parameter is used to specify how many void * elements can be stored in the buffer. The Return Value of the function is the number of actually obtained pointers. The maximum value is not greater than the size.

The pointer in the buffer is actually the return address obtained from the stack. Each stack framework has a return address.

Note: The Optimization Options of Some compilers interfere with obtaining the correct call stack. In addition, the inline function does not have a stack framework. Deleting the framework pointer will also cause failure to parse the stack content correctly.

Char ** backtrace_symbols (void * const * buffer, int size)

Backtrace_symbols converts the information obtained from the backtrace function into a string array. The buffer parameter should be a pointer array obtained from the backtrace function, and the size is the number of elements in the array (the return value of backtrace)

The Return Value of the function is a pointer to a string array, which is the same size as the buffer. each string contains a printable information relative to the corresponding elements in the buffer. it includes the function name, function offset address, and actual return address.

Currently, only programs in the ELF binary format can obtain the function name and offset address. in other systems, only the return address in hexadecimal format can be obtained. in addition, you may need to pass the corresponding symbols to the linker to support the function name function (for example, in a system using the GNU ld linker, you need to pass (-rdynamic ), -rdynamic can be used to notify the linker to add all the symbols to the dynamic symbol table. If your linker supports-rdynamic, we recommend that you add it !)

The return value of this function is the space applied through the malloc function. Therefore, the caller must use the free function to release the pointer.

Note: if you cannot obtain sufficient space for a string, the return value of the function will be NULL.

Void backtrace_symbols_fd (void * const * buffer, int size, int fd)

Backtrace_symbols_fd has the same function as the backtrace_symbols function. The difference is that it does not return a string array to the caller, but writes the result to the file with the file descriptor fd. Each function corresponds to a row. it does not need to call the malloc function, so it is applicable to situations where the function may fail to be called.

The following is an instance in glibc (slightly modified ):

 1 #include <execinfo.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4  5 /* Obtain a backtrace and print it to @code{stdout}. */ 6 void print_trace (void) 7 { 8     void    * array[10]; 9     size_t  size;10     char    ** strings;11     size_t  i;12 13     size = backtrace(array, 10);14     strings = backtrace_symbols (array, size);15     if (NULL == strings)16     {17         perror("backtrace_synbols");18         Exit(EXIT_FAILURE);19     }20 21     printf ("Obtained %zd stack frames.\n", size);22 23     for (i = 0; i < size; i++)24         printf ("%s\n", strings[i]);25 26     free (strings);27       strings = NULL;28 }29 30 /* A dummy function to make the backtrace more interesting. */31 void dummy_function (void)32 {33     print_trace ();34 }35 36 int main (int argc, char *argv[])37 {38     dummy_function ();39     return 0;                                                 40 }

 

The output is as follows:

Obtained 4 stack frames.
./Execinfo () [0x80484dd]
./Execinfo () [0x8048549]
./Execinfo () [0x8048556]
/Lib/i386-linux-gnu/libc. so.6 (_ libc_start_main + 0xf3) [0x70a113]

We can also use this backtrace to locate a segment error.

Generally, the system sends a SIGSEGV signal to the program when a segment error occurs. The default process is to exit the function. We can use the signal (SIGSEGV, & your_function); function to take over the processing of SIGSEGV signals. After a segment error occurs, the program automatically calls the functions we have prepared, to obtain the current function call stack from that function.

Example:

 1 #include <stdio.h>                                           2 #include <stdlib.h> 3 #include <stddef.h> 4 #include <execinfo.h> 5 #include <signal.h> 6  7 void dump(int signo) 8 { 9     void *buffer[30] = {0};10     size_t size;11     char **strings = NULL;12     size_t i = 0;13 14     size = backtrace(buffer, 30);15     fprintf(stdout, "Obtained %zd stack frames.nm\n", size);16     strings = backtrace_symbols(buffer, size);17     if (strings == NULL)18     {19         perror("backtrace_symbols.");20         exit(EXIT_FAILURE);21     }22 23     for (i = 0; i < size; i++)24     {25         fprintf(stdout, "%s\n", strings[i]);26     }27     free(strings);28     strings = NULL;29     exit(0);30 }31 32 void func_c()33 {34     *((volatile char *)0x0) = 0x9999;35 }36 37 void func_b()38 {39     func_c();40 }41 42 void func_a()43 {44     func_b();45 }46 47 int main(int argc, const char *argv[])48 {49     if (signal(SIGSEGV, dump) == SIG_ERR)50         perror("can't catch SIGSEGV");51     func_a();52     return 0;53 }                                               

 

Compile the program:
Gcc-g-rdynamic test. c-o test;./test
The output is as follows:

Obtained6stackframes. nm
./Backstrace_debug (dump + 0x45) [0x801_c9]
[0x468400]
./Backstrace_debug (func_ B + 0x8) [0x804888c]
./Backstrace_debug (func_a + 0x8) [0x8048896]
./Backstrace_debug (main + 0x33) [0x80488cb]
/Lib/i386-linux-gnu/libc. so.6 (_ libc_start_main + 0xf3) [0x129113]

Next:
Objdump-d test> test. s
Search for 804888c in test. s as follows:

8048884 <func_ B>:
8048884: 55 push % ebp
8048885: 89 e5 mov % esp, % ebp
8048887: e8 eb ff call 8048877 <func_c>
804888c: 5d pop % ebp
804888d: c3 ret

The address after the 80488c call (call 8048877) C function is called. Although the C function is not directly located, basically, the C function has a problem (the pop Command won't cause a segment error ).
We can also use addr2line to view

Addr2line 0x804888c-e backstrace_debug-f

Output:

Func_ B
/Home/astrol/c/backstrace_debug.c: 57

 

Reference: http://blog.csdn.net/jasonchen_gbd/article/details/44066815

Reference code: https://github.com/castoz/backtrace

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.