GDB – Debugging Examples

  • Post author:
  • Post category:GDB
  • Post comments:0 Comments

Go through the following examples to understand the procedure of debugging a program and core dumped.

  • Debugging Example 1
  • Let us write a program to generate a core dump.

    #include <iostream>
    using namespace std;  
    
    int divint(int, int);  
    int main() 
    { 
       int x = 5, y = 2; 
       cout << divint(x, y); 
       
       x =3; y = 0; 
       cout << divint(x, y); 
       
       return 0; 
    }  
    
    int divint(int a, int b) 
    { 
       return a / b; 
    }   

    To enable debugging, the program must be compiled with the -g option.

    $g++ -g crash.cc -o crash 

    NOTE: We are using g++ compiler because we have used C++ source code.

    Now, when you run this program on your linux machine, it will produce the following result:

    Floating point exception (core dumped) 

    You will find a core file in your current directory.

    Now to debug the problem, start gdb debugger at the command prompt:

    $gdb crash 
    # Gdb prints summary information and then the (gdb) prompt
      
    (gdb) r 
    Program received signal SIGFPE, Arithmetic exception. 
    0x08048681 in divint(int, int) (a=3, b=0) at crash.cc:21 
    21        return a / b; 
    
    # 'r' runs the program inside the debugger 
    # In this case the program crashed and gdb prints out some 
    # relevant information.  In particular, it crashed trying 
    # to execute line 21 of crash.cc.  The function parameters 
    # 'a' and 'b' had values 3 and 0 respectively.  
    
    (gdb) l 
    # l is short for 'list'.  Useful for seeing the context of 
    # the crash, lists code lines near around 21 of crash.cc  
    
    (gdb) where 
    #0  0x08048681 in divint(int, int) (a=3, b=0) at crash.cc:21 
    #1  0x08048654 in main () at crash.cc:13 
    # Equivalent to 'bt' or backtrace.  Produces what is known 
    # as a 'stack trace'.  Read this as follows:  The crash occurred 
    # in the function divint at line 21 of crash.cc.  This, in turn, 
    # was called from the function main at line 13 of crash.cc  
    
    (gdb) up 
    # Move from the default level '0' of the stack trace up one level 
    # to level 1.  
    
    (gdb) list 
    # list now lists the code lines near line 13 of crash.cc  
    
    (gdb) p x 
    # print the value of the local (to main) variable x 

    In this example, it is fairly obvious that the crash occurs because of the attempt to divide an integer by 0.

    To debug a program ‘crash’ that has crashed and produced a core file named ‘core’, type the following at the command line:

    gdb crash core 

    As this is mostly equivalent to starting gdb and typing the ‘r’ command, all of the commands above could now be used to debug the file.

  • Debugging Example 2
  • Let us write another program that will cause a core dump due to non-initialized memory.

    #include <iostream>  
    using namespace std; 
    
    void setint(int*, int); 
    int main() 
    { 
       int a; 
       setint(&a, 10); 
       cout << a << endl; 
       
       int* b; 
       setint(b, 10); 
       cout << *b << endl; 
       
       return 0; 
    } 
    
    void setint(int* ip, int i)
    {
       *ip = i; 
    }

    To enable debugging, the program must be compiled with the -g option.

    $g++ -g crash.cc -o crash 

    NOTE: We are using g++ compiler because we have used C++ source code.

    When you run this program on your linux machine, it will produce the following result:

    segmentation fault (core dumped) 

    Now let us debug it using gdb:

    $ gdb crash 
    (gdb) r 
    Starting program: /home/tmp/crash 
    10 
    10 
    Program received signal SIGSEGV, Segmentation fault. 
    0x4000b4d9 in _dl_fini () from /lib/ld-linux.so.2 
    
    (gdb) where 
    #0  0x4000b4d9 in _dl_fini () from /lib/ld-linux.so.2 
    #1  0x40132a12 in exit () from /lib/libc.so.6 
    #2  0x4011cdc6 in __libc_start_main () from /lib/libc.so.6 
    
    #3  0x080485f1 in _start () 
    (gdb) 

    Unfortunately, the program will not crash in either of the user-defined functions, main or setint, so there is no useful trace or local variable information. In this case, it may be more useful to single-step through the program.

    (gdb) b main 
    # Set a breakpoint at the beginning of the function main 
    
    (gdb) r 
    # Run the program, but break immediately due to the breakpoint. 
    
    (gdb) n 
    # n = next, runs one line of the program 
    
    (gdb) n 
    (gdb) s 
    setint(int*, int) (ip=0x400143e0, i=10) at crash2.C:20 
    # s = step, is like next, but it will step into functions. 
    # In this case the function stepped into is setint. 
    
    (gdb) p ip 
    $3 = (int *) 0x400143e0 
    
    (gdb) p *ip 
    1073827128 

    The value of *ip is the value of the integer pointed to by ip. In this case, it is an unusual value and is strong evidence that there is a problem. The problem in this case is that the pointer was never properly initialized, so it is pointing to some random area in memory (the address 0x40014e0). By pure luck, the process of assigning a value to *ip does not crash the program, but it creates some problem that crashes the program when it finishes.

    Both the programs are written in C++ and generate core dump due to different reasons. After going through these two examples, you should be in a position to debug your C or C++ programs generating core dumps.

    Leave a Reply