This blog is under construction

Saturday, 2 February 2013

backtrace_symbols_fd example in C


Header file:
    execinfo.h

Synopsis:
     void backtrace_symbols_fd (void *const *buffer, int size, int fd);

Description:
     backtrace() function gives us set of backtrace symbols(set of addresses).  Those addresses can be translated to set of strings and write those strings to the given file descriptor fd using backtrace_symbols_fd() function.  Argument buffer indicates the set of address(backtrace symbols) from backtrace() and size indicates the number of entries in the array.  And this function does not use malloc.


backtrace_symbols_fd function C example:



  #include<stdio.h>
  #include<execinfo.h>
  #include<stdlib.h>

  FILE *fp;
  void func5() {
        void *array[12];
        int size, i, fd;
        char **str;
        fp = fopen("./backtrace_info.txt", "a");
        fd = fileno(fp);
        fseek(fp, 0, SEEK_END);
        size = backtrace(array, 12);
        printf("Backtrace:\n");
        for (i = 0; i < size; i++) {
                printf("0x%08x\n", (int)array[i]); // printing symbols on output screen
        }

        /* converts address to string and writes the o/p to a file */
        backtrace_symbols_fd(array, size, fd);
        printf("No of level in backtrace:%d\n", size);
  }

  void func4() {
        func5();
  }

  void func3() {
        func4();
  }

  void func2() {
        func3();
  }

  void func1() {
        func2();
  }


  int main() {
        func1();
        return 0;
  }



  Output:

  jp@jp-VirtualBox:$ ls
  backtrace.c  backtrace_symbols.c  backtrace_symbols_fd.c
  jp@jp-VirtualBox:$ gcc -rdynamic backtrace_symbols_fd.c 
  jp@jp-VirtualBox:$ ./a.out
  Backtrace:
  0x080487d5
  0x0804884d
  0x0804885a
  0x08048867
  0x08048874
  0x08048881
  0x0015fce7
  0x080486e1
  No of level in backtrace:8
  jp@jp-VirtualBox:$ ls
  backtrace.c  backtrace_info.txt  backtrace_symbols.c  backtrace_symbols_fd.c 

  jp@jp-VirtualBox:$ cat backtrace_info.txt 
  ./a.out(func5+0x61)[0x80487d5]
  ./a.out(func4+0xb)[0x804884d]
  ./a.out(func3+0xb)[0x804885a]
  ./a.out(func2+0xb)[0x8048867]
  ./a.out(func1+0xb)[0x8048874]
  ./a.out(main+0xb)[0x8048881]
  /lib/libc.so.6(__libc_start_main+0xe7)[0x15fce7]
  ./a.out[0x80486e1]


Note:
why rdynamic option?
Eg: gcc -rdynamic backtrace_symbols.c
rdynamic is the linker option that makes the function names available to the program.  Basically, it instructs the linker to add all the symbols to the dynamic symbol table.

1 comment:

  1. Really nice post.
    What about inducing a segfault in func5(lets say we try to access an array index which is out of bound or we try to access some other restricted memory address).
    1> Can I record the segfault in fd(3rd arg of backtrace_symbols_fd()).
    2> How can I generate a core file in-case of segfault.

    How can we modify your above code to accommodate 1 & 2.

    ReplyDelete