Latest

6/recent/ticker-posts

How to debug codes? Debug using GDB

 

How to debug codes? Debug using GDB

GNU DEBUGGER

Debugging is the process of detecting and removing existing and potential errors (also called ‘bugs’) in a software code that can cause it to behave unexpectedly or crash. To prevent incorrect operation of a software or system, debugging is used to find and resolve bugs or defects. When various subsystems or modules are tightly coupled, debugging becomes harder as any change in one module may cause more bugs to appear in another. Sometimes it takes more time to debug a program than to code it.

To debug a program, the user has to start with a problem, isolate the source code of the problem, and then fix it. A user of a program must know how to fix the problem as knowledge about problem analysis is expected. When the bug is fixed, then the software is ready to use. Debugging tools (called debuggers) are used to identify coding errors at various development stages. They are used to reproduce the conditions in which error has occurred, then examine the program state at that time and locate the cause. Programmers can trace the program execution step-by-step by evaluating the value of variables and stop the execution wherever required to get the value of variables or reset the program variables. Some programming language packages provide a debugger for checking the code for errors while it is being written at run time.

Here’s the debugging process:

1. Reproduce the problem.

2. Describe the bug. Try to get as much input from the user as to get the exact reason.

3. Capture the program snapshot when the bug appears. Try to get all the variable values and states of the program at that time.

4. Analyze the snapshot based on the state and action. Based on that we try to find the cause of the bug.

5. Fix the existing bug, but also check that any new bug does not occur.

 

What is GDB?

GDB stands for GNU Project Debugger and is a powerful debugging tool for C (along with other languages like C++). It helps you to poke around inside your C programs while they are executing and also allows you to see what exactly happens when your program crashes. GDB operates on executable files which are binary files produced by the compilation process.

How to debug C++ program using GDB?

First, you need to compile the objects of your C++ library with the -g flag, for instance:

$ g++ -g -std=c++0x -Wall -fPIC main.cpp bis.cpp

Then, you can run GDB on your executable directly. In the case of a Python script calling C++ functions, you can use the following syntax:

$ gdb --args python script.py

The most frequently used GDB commands are the following (adapted from the GDB manpage):

·   r: start the program

·   bt: backtrace: display the program stack

·   b file.cpp:42: set a breakpoint at line 42 of file file.cpp

·   c: resume execution (after stopping, e.g. at a breakpoint)

·   s (step): execute next program line (after stopping); step into any function calls in the line

·   n (next): execute next program line (after stopping); step over any function calls in the line

·   d: delete breakpoints

·   p expr: print the value of an expression expr (maybe a single variable)

·   f n: go to frame n (see bt)

When using the STL, you may want to include the following to your gdbinit script (authors: Dan Marinescu, Anders Elton). This script provides you with printers for your favorite STL containers, such as:

·   pvector v: print an std::vector

·   plist l: print an std::list

·   plist_member l: print one element from the list l

Debugging objects at execution

Consider the following situation: some buggy function segfaults at execution, and we want to survey the content of an object called constraints in the context where the function crashed. First, we use bt and f to get to this context:

(gdb) r

[run until segfault]

 

(gdb) bt

...

#42 0x00002aaac3bd67b7 in MyProject::BuggyFunction (constraints=...,

    xlist=@0x7fffffffc6f8) at BuggyFile.cpp:528

...

 

(gdb) f 42

#42 0x00002aaac3bd67b7 in MyProject::BuggyFunction (constraints=...,

    xlist=@0x7fffffffc6f8) at BuggyFile.cpp:528

528     double z = LetsCrash(constraints, xlist);

The output of f shows the current frame (#42), values of the parameters in the function call (I redacted constraints here, but e.g. the pointer value of the pointer xlist is show as a memory address) as well as the line of code where the execution is at (here, line 528 of file BuggyFile.cpp, where the function LetsCrash is called). Now constraints are in the current context and we can print it:

(gdb) p constraints

$1 = (MyProject::Constraints &) @0x1b7de60: {

  <MyProject::Constraints> = {

    _vptr.Constraints = 0x2aaac3dffb50,

    trajectory = {

      dimension = 2,

      duration = 1,

      degree = 3,

      chunks_list = { ... }

    },

    n = 42

  }, <No data fields>}

Let us take a peak at the chunks_list field of the trajectory:

(gdb) p constraints.trajectory.chunks_list

$2 = {

  <std::_List_base<MyProject::Chunk, std::allocator<MyProject::Chunk> >> = {

    _M_impl = {

      <std::allocator<std::_List_node<MyProject::Chunk> >> = {

        <__gnu_cxx::new_allocator<std::_List_node<MyProject::Chunk> >> = {<No data fields>}, <No data fields>},

      members of std::_List_base<MyProject::Chunk, std::allocator<MyProject::Chunk> >::_List_impl:

      _M_node = {

        _M_next = 0x1b930b0,

        _M_prev = 0x1b930b0

      }

    }

  }, <No data fields>}

We can call the plist pretty printer to get a more helpful output:

(gdb) plist constraints.trajectory.chunks_list

List size = 1

List type = std::list<MyProject::Chunk, std::allocator<MyProject::Chunk> >

Use plist <variable_name> <element_type> to see the elements in the list.

It says we need to specify the element_type argument (indicated above in the "List type" line) to print out elements one by one. That is:

(gdb) plist constraints.trajectory.chunks_list Chunk

elem[0]: $3 = {

  dimension = 2,

  degree = 3,

  duration = 1,

  sbegin = 0,

  send = 1,

  polynomials_vector = { ... }

}

List size = 1

We can access the first list element with front():

(gdb) p constraints.trajectory.chunks_list.front()

$4 = (MyProject::Chunk &) @0x1b930c0: {

  dimension = 2,

  degree = 3,

  duration = 1,

  sbegin = 0,

  send = 1,

  polynomials_vector = { ... }

}

However, we already had this element at hand. Had you noticed the $i printed out by GDB? They are registers that can be used to refer to printed objects. For instance:

(gdb) p $3

$5 = (MyProject::Chunk &) @0x1b930c0: {

  dimension = 2,

  degree = 3,

  duration = 1,

  sbegin = 0,

  send = 1,

  polynomials_vector = { ... }

}

In particular, whenever you print a list or a vector, each element is bound to such a register so you can access it directly afterward. We saw this above when we printed the chunks list and $3 was mapped to the first element. If the list had had more elements, the second would have been bound to $4, the third to $5, and so on. These registers can be used as variables in C++ expressions, so we can e.g. access their fields:

(gdb) pvect $5.polynomialsvector

elem[0]: $6 = {

  degree = 3,

  coefficients_vector = { ... }

}

elem[1]: $7 = {

  degree = 3,

  coefficients_vector = { ... }

}

Vector size = 2

Vector capacity = 2

Element type = MyProject::Polynomial *

As arguments to print commands are full-blown C++ expressions, one can use function calls (see front() above), membership operators (we used the dot, but -> can also be used for pointers), etc.

 

Post a Comment

1 Comments

  1. 1xbet - Best Bet in 1xBet - Download or Install for Android
    1xbet is the best betting app หารายได้เสริม in communitykhabar the https://octcasino.com/ world created for esports. It is 1xbet login a one of the safest and poormansguidetocasinogambling.com most trusted names among players. It offers a user friendly interface

    ReplyDelete