Sunday, January 5, 2014

gdb debugger for Linux

          GDB is the debugger in the gnu package for debugging programs in unix environment.
These notes will be useful for those who have a faulty program and want to get to the bottom of the issue and fix the problem. I am mentioning only those commands which i have often used in my programming experience. But, they are enough to get one started.

General commands :

Invocation of gdb :
  •  Live process analysis :    If you have a process which has hanged or which is in an infinite loop then you want to debug this program live. So, you need to attach this process to gdb. 
                        gdb -p <processid> <program>

            NOTE : When  you attach the program to gdb it stops executing.
  •   Core dump analysis : If you have a coredump to analyze then you invoke as  
                       gdb -c <path of coredump> <program>

This will invoke the gdb prompt on which you can type different gdb commands.
The most important one is of course 'help'.

gdb help :
       Each person will provide you with a list of gdb commands which that person has used. But, that can only get you started. Often there are situations which require use of commands not generally mentioned or used by people. In such circumstances 'help' is the only utility you can resort to.
        If you give 'help' in gdb it will give you the classes of commands in help. To get a list of commands from each class you have to give :
          (gdb) help <class>
  
      eg : help stack

      
To inspect the current thread/stack :
     To look at the current thread in case of a live program or  the thread which crashed in case of dump give following command
          (gdb) bt

To look at global variables :
     To inspect global variables it is essential that the program is compiled with '-g' option.
       (gdb) <variable name>

To look at local variables :
    To inspect local variables it is essential that the program is compiled with '-g' option.
        (gdb) info locals

To print stucture:
   
      (gdb) p <var which is a struct>-><member>
                    or
      (gdb) p ((struct def *) (addr))-><member>

To examine data if program not compiled with debugging symbols:
      When you test a program before shipping it to the customer  you need to test the nondebug version or a program without any debugging symbols. In such a case it is crucial that you are still able to inspect the data. For such cases use following command :
     (gdb) x <address>

   You can also specify the format to display the information at the memory address as well as the count.
   eg : (gdb) x/2xw 0x8c89ee0
           0x8c89ee0:      0x08c96f10      0x00000000
   This displays two words in hex format at the specified address.

To print long strings in gdb:
           Often the number of characters are more than the default limit in such a case  you can reset the limit. Before printing the information give following command
        (gdb) set print elements <large enough number>

 To move across the stack :       
           The different functions in the stack trace are considered frames, to move to a particular frame you can use :
       (gdb) frame <frameid>
 'frameid' is the number to the leftside of the functions in the stacktrace. eg : #1,#2 etc

            One can also go to the previous frame or the next frame using commands :
       (gdb) up                                             
                and
      (gdb) down

To see the assembly code :
      (gdb) disassemble

To look at the source code :
      (gdb) list

Setting breakpoints:
     Breakpoint is a point in the code where we want the debugger to stop while executing.
To run a program through debugger invoke gdb in following manner :
      gdb <program>

Then on the gdb prompt you can execute the following command so that the program runs:
     (gdb) run

Now if you want the program to stop executing when it calls a particular function then use following
command before running the program :
    (gdb) break <function name>

To continue execution from where you left off  use :
    (gdb) continue

Conditional breakpoints :

        These are breakpoints which will break the execution only when the given condition is met. These are especially useful in debugging loops/if/while conditions.

eg: If you want to break when variable i reaches value 5 then use following command 
        (gdb) condition 1 i=5

Stepping :
      Once the breakpoint is reached you may need to go to the next step or rather go through the program one step at a time. In such scenario following command is used :
         (gdb) step
      However, the above command also steps line by line through all the functions that get called. If you want to only step through the current function without stepping through calling functions then you use following command :
         (gdb) next


Threads
      Debugging multithreaded programs is never easy. Below is a list of commands i think are absolutely essential. But, there are so many scenarios that you may end up going to 'gdb help' every time you solve a issue.

      List threads :
            You can get a list of threads which were executing by following command
            (gdb) info threads

     To go to a particular thread :
            To look at the stacktrace of a particular thread 
              (gdb) thread <threadno>
  
    To run particular thread :
          When debugging a live multithreaded program if you execute the command 'continue' then it will start running all the threads. But, there are scenarios when one wishes to run a particular thread.
          (gdb) thread apply <threadno> <command>