GDB: Difference between revisions
No edit summary |
No edit summary |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
<languages /> | <languages /> | ||
<translate> | <translate> | ||
<!--T:1--> | |||
[https://www.gnu.org/software/gdb/ GDB] is a debugger used to investigate software problem. | [https://www.gnu.org/software/gdb/ GDB] is a debugger used to investigate software problem. | ||
GDB is an acronym saying <i>GDB: The <u>G</u>NU Project <u>D</u>e<u>b</u>ugger</i> | GDB is an acronym saying <i>GDB: The <u>G</u>NU Project <u>D</u>e<u>b</u>ugger</i> | ||
== Description == | == Description == <!--T:2--> | ||
With a debugger, it is possible to quickly find the cause of a problem in a piece of software. | With a debugger, it is possible to quickly find the cause of a problem in a piece of software. | ||
Often it is used to resolve [https://en.wikipedia.org/wiki/Segmentation_fault segmentation faults]. | Often it is used to resolve [https://en.wikipedia.org/wiki/Segmentation_fault segmentation faults]. | ||
Line 10: | Line 11: | ||
[https://en.wikipedia.org/wiki/Memory_leak memory leak]), we recommend using [[Debugging_and_profiling#Valgrind | Valgrind]]. | [https://en.wikipedia.org/wiki/Memory_leak memory leak]), we recommend using [[Debugging_and_profiling#Valgrind | Valgrind]]. | ||
== Use cases == | == Use cases == <!--T:3--> | ||
=== Finding a bug with the debugger === | === Finding a bug with the debugger === | ||
In this section, the following program is used: | In this section, the following program is used: | ||
{{ | {{File | ||
File | |||
|name= program.cpp | |name= program.cpp | ||
|lines=yes | |lines=yes | ||
Line 22: | Line 22: | ||
using namespace std; | using namespace std; | ||
<!--T:4--> | |||
int main(int argc, char**argv) { | int main(int argc, char**argv) { | ||
vector<int> numbers; | vector<int> numbers; | ||
int iterator = 1000; | <!--T:5--> | ||
int iterator = 1000; | |||
while(iterator --) { | <!--T:6--> | ||
while(iterator --) { | |||
numbers.push_back(iterator); | numbers.push_back(iterator); | ||
} | } | ||
cout << numbers[1000000] << endl; | <!--T:7--> | ||
cout << numbers[1000000] << endl; | |||
return 0; | <!--T:8--> | ||
return 0; | |||
} | } | ||
}} | }} | ||
Line 44: | Line 49: | ||
}} | }} | ||
<!--T:9--> | |||
We may then run the program inside the debugger. Note that we compiled using the option <tt>-g</tt> to include debugging symbols within the binary and allow the debugger to provide more information on the bug. We run the program inside the debugger using | We may then run the program inside the debugger. Note that we compiled using the option <tt>-g</tt> to include debugging symbols within the binary and allow the debugger to provide more information on the bug. We run the program inside the debugger using | ||
{{Command | {{Command | ||
Line 50: | Line 56: | ||
Starting program: /home/seb/program ./program | Starting program: /home/seb/program ./program | ||
<!--T:10--> | |||
Program received signal SIGSEGV, Segmentation fault. | Program received signal SIGSEGV, Segmentation fault. | ||
0x0000000000400c17 in main (argc{{=}}2, argv{{=}}0x7fffffffda88) at program.cpp:15 | 0x0000000000400c17 in main (argc{{=}}2, argv{{=}}0x7fffffffda88) at program.cpp:15 | ||
Line 55: | Line 62: | ||
Missing separate debuginfos, use: debuginfo-install glibc-2.16-31.fc18.x86_64 libgcc-4.7.2-8.fc18.x86_64 libstdc++-4.7.2-8.fc18.x86_64 | Missing separate debuginfos, use: debuginfo-install glibc-2.16-31.fc18.x86_64 libgcc-4.7.2-8.fc18.x86_64 libstdc++-4.7.2-8.fc18.x86_64 | ||
<!--T:11--> | |||
(gdb) bt | (gdb) bt | ||
#0 0x0000000000400c17 in main (argc{{=}}2, argv{{=}}0x7fffffffda88) at program.cpp:15 | #0 0x0000000000400c17 in main (argc{{=}}2, argv{{=}}0x7fffffffda88) at program.cpp:15 | ||
Line 61: | Line 69: | ||
So, the above error is caused by line 15. The code tries to use index 1000000, but the array only contains 1000 elements. | So, the above error is caused by line 15. The code tries to use index 1000000, but the array only contains 1000 elements. | ||
=== Finding the cause of a segmentation fault using a <tt>core</tt> file === | === Finding the cause of a segmentation fault using a <tt>core</tt> file === <!--T:12--> | ||
In this example, we use the same program as in the previous section. We however do so without using the debugger directly. This is useful for a bug that happens a long time after the program has started. | In this example, we use the same program as in the previous section. We however do so without using the debugger directly. This is useful for a bug that happens a long time after the program has started. | ||
<!--T:13--> | |||
To find the cause for this error, a <tt>core</tt> file must be generated. To do this, you must activate the creation of such files. | To find the cause for this error, a <tt>core</tt> file must be generated. To do this, you must activate the creation of such files. | ||
{{Command|ulimit -c unlimited}} | {{Command|ulimit -c unlimited}} | ||
<!--T:14--> | |||
Executing the same program again, a <tt>core</tt> file is written. | Executing the same program again, a <tt>core</tt> file is written. | ||
{{Commands|./program | {{Commands|./program | ||
Line 75: | Line 85: | ||
}} | }} | ||
<!--T:15--> | |||
Using the <tt>program</tt> binary executable and the <tt>core</tt> file, it is possible to trace its execution | Using the <tt>program</tt> binary executable and the <tt>core</tt> file, it is possible to trace its execution | ||
up to the error. | up to the error. | ||
Line 80: | Line 91: | ||
Reading symbols from /home/seb/program...done. | Reading symbols from /home/seb/program...done. | ||
<!--T:16--> | |||
(gdb) core-file core.18246 | (gdb) core-file core.18246 | ||
[New LWP 18246] | [New LWP 18246] | ||
Core was generated by | Core was generated by './program'. | ||
Program terminated with signal 11, Segmentation fault. | Program terminated with signal 11, Segmentation fault. | ||
#0 0x0000000000400c17 in main (argc{{=}}1, argv{{=}}0x7fff2315c848) at | #0 0x0000000000400c17 in main (argc{{=}}1, argv{{=}}0x7fff2315c848) at | ||
Line 91: | Line 103: | ||
libstdc++-4.7.2-8.fc18.x86_64 | libstdc++-4.7.2-8.fc18.x86_64 | ||
<!--T:17--> | |||
(gdb) bt | (gdb) bt | ||
#0 0x0000000000400c17 in main (argc{{=}}1, argv{{=}}0x7fff2315c848) at | #0 0x0000000000400c17 in main (argc{{=}}1, argv{{=}}0x7fff2315c848) at | ||
Line 98: | Line 111: | ||
We here get the same result as if we had run it inside the debugger. | We here get the same result as if we had run it inside the debugger. | ||
=== Attaching the debugger to a running process === | === Attaching the debugger to a running process === <!--T:18--> | ||
It is possible to debug a process that is already running, for example a job running on one of the compute nodes. To do so, we first need the process ID. | It is possible to debug a process that is already running, for example a job running on one of the compute nodes. To do so, we first need the process ID. | ||
<!--T:19--> | |||
{{Command|ps aux {{!}} grep firefox {{!}} grep -v grep | {{Command|ps aux {{!}} grep firefox {{!}} grep -v grep | ||
seb 12691 6.4 7.5 1539672 282656 ? Sl 08:53 6:48 /usr/lib64/firefox/firefox http://www.google.ca/ | seb 12691 6.4 7.5 1539672 282656 ? Sl 08:53 6:48 /usr/lib64/firefox/firefox http://www.google.ca/ | ||
}} | }} | ||
<!--T:20--> | |||
After that, it is possible to attach the debugger directly. | After that, it is possible to attach the debugger directly. | ||
{{Command|gdb attach 12691 | {{Command|gdb attach 12691 | ||
}} | }} | ||
<!--T:21--> | |||
After having done this, a lot of information is displayed. | After having done this, a lot of information is displayed. | ||
<!--T:22--> | |||
There are many commands available within GDB. One of the most useful is <tt>backtrace</tt>, or <tt>bt</tt>. | There are many commands available within GDB. One of the most useful is <tt>backtrace</tt>, or <tt>bt</tt>. | ||
This commands shows the current call stack. | This commands shows the current call stack. | ||
Line 133: | Line 150: | ||
#17 0x0000000000402403 in main () | #17 0x0000000000402403 in main () | ||
<!--T:23--> | |||
|quit | |quit | ||
A debugging session is active. | A debugging session is active. | ||
<!--T:24--> | |||
Inferior 1 [process 12691] will be detached. | |||
<!--T:25--> | |||
Quit anyway? (y or n) y | Quit anyway? (y or n) y | ||
Detaching from program: /usr/lib64/firefox/firefox, process 12691 | Detaching from program: /usr/lib64/firefox/firefox, process 12691 | ||
}} | }} | ||
== Advanced usage == <!--T:26--> | |||
== Advanced usage == | |||
In the previous sections, we used the <tt>run</tt> and <tt>backtrace</tt> commands. Many more commands are available to debug in an interactive way, by stopping the program. For example, you can set breakpoints on functions or lines of code, or whenever a given variable is modified. When execution is interrupted, you can analyse the state of the program by printing the value of variables. The following table contains a list of the main commands. | In the previous sections, we used the <tt>run</tt> and <tt>backtrace</tt> commands. Many more commands are available to debug in an interactive way, by stopping the program. For example, you can set breakpoints on functions or lines of code, or whenever a given variable is modified. When execution is interrupted, you can analyse the state of the program by printing the value of variables. The following table contains a list of the main commands. | ||
<!--T:27--> | |||
{| class="wikitable" style="font-size: 95%; text-align: center;" | {| class="wikitable" style="font-size: 95%; text-align: center;" | ||
|+align="bottom" style="color:#e76700;"|''Main GDB commands'' | |+align="bottom" style="color:#e76700;"|''Main GDB commands'' | ||
Line 194: | Line 214: | ||
|} | |} | ||
=== Displaying STL structures === | === Displaying STL structures === <!--T:28--> | ||
By default, GDB does not display C++ STL structures very well. Many solutions are given [https://sourceware.org/gdb/wiki/STLSupport here]. The simplest solution is probably [http://www.yolinux.com/TUTORIALS/GDB-Commands.html#STLDEREF this one], which is to copy [http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt this file] in your home folder, with the name <tt>~/.gdbinit</tt>. | By default, GDB does not display C++ STL structures very well. Many solutions are given [https://sourceware.org/gdb/wiki/STLSupport here]. The simplest solution is probably [http://www.yolinux.com/TUTORIALS/GDB-Commands.html#STLDEREF this one], which is to copy [http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt this file] in your home folder, with the name <tt>~/.gdbinit</tt>. | ||
== Other resources == | == Other resources == <!--T:29--> | ||
* [http://www.sourceware.org/gdb/ GDB website] | * [http://www.sourceware.org/gdb/ GDB website] | ||
* [http://oucsace.cs.ohiou.edu/~bhumphre/gdb.html GDB tutorial] | * [http://oucsace.cs.ohiou.edu/~bhumphre/gdb.html GDB tutorial] | ||
* [http://goo.gl/rLPvR0 Talk from the TACC on debugging and profiling] | * [http://goo.gl/rLPvR0 Talk from the TACC on debugging and profiling] | ||
</translate> | </translate> |
Latest revision as of 17:54, 11 July 2024
GDB is a debugger used to investigate software problem. GDB is an acronym saying GDB: The GNU Project Debugger
Description
With a debugger, it is possible to quickly find the cause of a problem in a piece of software. Often it is used to resolve segmentation faults. If you desire to resolve a problem relating to memory (for example, a memory leak), we recommend using Valgrind.
Use cases
Finding a bug with the debugger
In this section, the following program is used:
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char**argv) {
vector<int> numbers;
int iterator = 1000;
while(iterator --) {
numbers.push_back(iterator);
}
cout << numbers[1000000] << endl;
return 0;
}
This program generates a segmentation fault when it is ran.
[name@server ~]$ g++ -g program.cpp -o program
[name@server ~]$ ./program
Segmentation fault (core dumped)
[name@server ~]$
We may then run the program inside the debugger. Note that we compiled using the option -g to include debugging symbols within the binary and allow the debugger to provide more information on the bug. We run the program inside the debugger using
[name@server ~]$ gdb ./program
(gdb) run
Starting program: /home/seb/program ./program
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400c17 in main (argc=2, argv=0x7fffffffda88) at program.cpp:15
15 cout << numbers[1000000] << endl;
Missing separate debuginfos, use: debuginfo-install glibc-2.16-31.fc18.x86_64 libgcc-4.7.2-8.fc18.x86_64 libstdc++-4.7.2-8.fc18.x86_64
(gdb) bt
#0 0x0000000000400c17 in main (argc=2, argv=0x7fffffffda88) at program.cpp:15
So, the above error is caused by line 15. The code tries to use index 1000000, but the array only contains 1000 elements.
Finding the cause of a segmentation fault using a core file
In this example, we use the same program as in the previous section. We however do so without using the debugger directly. This is useful for a bug that happens a long time after the program has started.
To find the cause for this error, a core file must be generated. To do this, you must activate the creation of such files.
[name@server ~]$ ulimit -c unlimited
Executing the same program again, a core file is written.
[name@server ~]$ ./program
Segmentation fault (core dumped)
[name@server ~]$ file core.18158
core.18158: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './program'
[name@server ~]$
Using the program binary executable and the core file, it is possible to trace its execution
up to the error.
[name@server ~]$ gdb -q ./program
Reading symbols from /home/seb/program...done.
(gdb) core-file core.18246
[New LWP 18246]
Core was generated by './program'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000000000400c17 in main (argc=1, argv=0x7fff2315c848) at
program.cpp:15
15 cout << numbers[1000000] << endl;
Missing separate debuginfos, use: debuginfo-install
glibc-2.16-31.fc18.x86_64 libgcc-4.7.2-8.fc18.x86_64
libstdc++-4.7.2-8.fc18.x86_64
(gdb) bt
#0 0x0000000000400c17 in main (argc=1, argv=0x7fff2315c848) at
program.cpp:15
We here get the same result as if we had run it inside the debugger.
Attaching the debugger to a running process
It is possible to debug a process that is already running, for example a job running on one of the compute nodes. To do so, we first need the process ID.
[name@server ~]$ ps aux | grep firefox | grep -v grep
seb 12691 6.4 7.5 1539672 282656 ? Sl 08:53 6:48 /usr/lib64/firefox/firefox http://www.google.ca/
After that, it is possible to attach the debugger directly.
[name@server ~]$ gdb attach 12691
After having done this, a lot of information is displayed.
There are many commands available within GDB. One of the most useful is backtrace, or bt. This commands shows the current call stack.
(gdb) bt
#0 0x00000033646e99ad in poll () from /lib64/libc.so.6
#1 0x0000003db86849f3 in PollWrapper(_GPollFD*, unsigned int, int) () from /usr/lib64/firefox/xulrunner/libxul.so
#2 0x0000003366e47d24 in g_main_context_iterate.isra.24 () from /lib64/libglib-2.0.so.0
#3 0x0000003366e47e44 in g_main_context_iteration () from /lib64/libglib-2.0.so.0
#4 0x0000003db86849a2 in nsAppShell::ProcessNextNativeEvent(bool) () from /usr/lib64/firefox/xulrunner/libxul.so
#5 0x0000003db869a7d1 in nsBaseAppShell::DoProcessNextNativeEvent(bool, unsigned int) () from /usr/lib64/firefox/xulrunner/libxul.so
#6 0x0000003db869a8ea in nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal*, bool, unsigned int) () from /usr/lib64/firefox/xulrunner/libxul.so
#7 0x0000003db89810c2 in nsThread::ProcessNextEvent(bool, bool*) () from /usr/lib64/firefox/xulrunner/libxul.so
#8 0x0000003db89563eb in NS_ProcessNextEvent(nsIThread*, bool) () from /usr/lib64/firefox/xulrunner/libxul.so
#9 0x0000003db873056f in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) () from /usr/lib64/firefox/xulrunner/libxul.so
#10 0x0000003db89a4ab7 in MessageLoop::Run() () from /usr/lib64/firefox/xulrunner/libxul.so
#11 0x0000003db869a1b3 in nsBaseAppShell::Run() () from /usr/lib64/firefox/xulrunner/libxul.so
#12 0x0000003db857d92d in nsAppStartup::Run() () from /usr/lib64/firefox/xulrunner/libxul.so
#13 0x0000003db7d18f4a in XREMain::XRE_mainRun() () from /usr/lib64/firefox/xulrunner/libxul.so
#14 0x0000003db7d1b007 in XREMain::XRE_main(int, char**, nsXREAppData const*) () from /usr/lib64/firefox/xulrunner/libxul.so
#15 0x0000003db7d1b259 in XRE_main () from /usr/lib64/firefox/xulrunner/libxul.so
#16 0x0000000000402c23 in do_main(int, char**, nsIFile*) ()
#17 0x0000000000402403 in main ()
(gdb) quit
A debugging session is active.
Inferior 1 [process 12691] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/lib64/firefox/firefox, process 12691
Advanced usage
In the previous sections, we used the run and backtrace commands. Many more commands are available to debug in an interactive way, by stopping the program. For example, you can set breakpoints on functions or lines of code, or whenever a given variable is modified. When execution is interrupted, you can analyse the state of the program by printing the value of variables. The following table contains a list of the main commands.
Command | Shortcut | Argument | Description |
---|---|---|---|
run/kill | r/k | - | begin/stop execution |
where / backtrace | bt | - | displays the backtrace |
break | b | src.c:line_number or function | sets a break point at the given line of code or function |
watch | - | variable name | interrupts the program when a variable is modified |
continue | c | - | resume the program |
step | s | - | execute the next operation |
p | variable name | displays the content of a variable | |
list | l | src.c:number | displays the given line of code |
Displaying STL structures
By default, GDB does not display C++ STL structures very well. Many solutions are given here. The simplest solution is probably this one, which is to copy this file in your home folder, with the name ~/.gdbinit.