How to debug codes? Debug using GDB
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.
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.
1 Comments
1xbet - Best Bet in 1xBet - Download or Install for Android
ReplyDelete1xbet 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