For production runs, we compile the code as
%%bash
g++ main_debug.cc -o debug_example
For debugging we need to add -g
to our code to get debug information added
%%bash
g++ -g main_debug.cc -o debug_example
gdb name_of_executable
Note that all comand line options are not provided at this stage.
gdb debug_example
GNU gdb (GDB) Fedora 9.1-7.fc32
Copyright (C) 2020 Free Software Foundation, Inc.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from debug_example...
(gdb)
run
to execute the code within the debuuger (gdb) run 3
Starting program: /home/diehlpk/debug_example 3
warning: Error disabling address space randomization: Operation not permitted
9
[Inferior 1 (process 4516) exited normally]
We use the break
command to define a break point and the debugger will stop at this point and we can display the values of pointers and varibales.
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
int findSquare(int a)
{
return a * a;
}
int main(int n, char** args)
{
for (int i = 1; i < n; i++)
{
int a = atoi(args[i]);
cout << findSquare(a) << endl;
}
return 0;
}
(gdb) break findSquare
Breakpoint 1 at 0x40118d: file main_debug.cc, line 8.
(gdb) break main_debug.cc:15
Breakpoint 2 at 0x4011b3: file main_debug.cc, line 15.
(gdb) run 3
Starting program: /home/diehlpk/debug_example 3
warning: Error disabling address space randomization: Operation not permitted
Breakpoint 2, main (n=2, args=0x7ffd286b5b28) at main_debug.cc:15
15 int a = atoi(args[i]);
continue
command(gdb) continue
Continuing.
Breakpoint 1, findSquare (a=3) at main_debug.cc:8
8 return a * a;
(gdb) continue
Continuing.
9
[Inferior 1 (process 4547) exited normally]
Here, we see that a = 3
whch is good since we provided run 3
and the command line argument was corretly passed.
delete
command:delete
- Will delete all break pointsdelete [break point number 1]
- Will delete onlt this on break point (gdb) delete 2
(gdb) run 3
Starting program: /home/diehlpk/debug_example 3
warning: Error disabling address space randomization: Operation not permitted
Breakpoint 1, findSquare (a=3) at main_debug.cc:8
8 return a * a;
(gdb) continue
Continuing.
9
[Inferior 1 (process 4560) exited normally]
(gdb) watch a
- Will interupt the code and print the new and old value of a
. (gdb) print a
- WIll print the value of a
.(gdb) print a
$2 = 3
(gdb
Let us look into some code with some segmentaiton fault:
%%bash
g++ main_debug_segfault.cc -o segfault
./segfault
bash: line 3: 8198 Segmentation fault (core dumped) ./segfault
Let us use gdb to find the segfault in the code
gdb segfault
GNU gdb (GDB) Fedora 9.1-7.fc32
Copyright (C) 2020 Free Software Foundation, Inc.
(gdb) run
Starting program: /home/diehlpk/segfault
warning: Error disabling address space randomization: Operation not permitted
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.31-6.fc32.x86_64
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401191 in main ()
Missing separate debuginfos, use: dnf debuginfo-install libgcc-10.3.1-1.fc32.x86_64 libstdc++-10.3.1-1.fc32.x86_64
(gdb)
That is not really a helpful message, since we already know that the program fails.
We need to compile the code using -g
to get more details
%%bash
g++ -g main_debug_segfault.cc -o segfault
gdb segfault
GNU gdb (GDB) Fedora 9.1-7.fc32
Copyright (C) 2020 Free Software Foundation, Inc.
(gdb) run
Starting program: /home/diehlpk/segfault
warning: Error disabling address space randomization: Operation not permitted
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.31-6.fc32.x86_64
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401191 in main (n=1, args=0x7ffc72343818) at main_debug_segfault.cc:8
8 std::cout << *pointer << std::endl;
Missing separate debuginfos, use: dnf debuginfo-install libgcc-10.3.1-1.fc32.x86_64 libstdc++-10.3.1-1.fc32.x86_64
Now we get the line number and the piece of code which is causing the segfault.
(gdb) run
Starting program: /home/diehlpk/segfault
warning: Error disabling address space randomization: Operation not permitted
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.31-6.fc32.x86_64
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401191 in main (n=1, args=0x7ffc72343818) at main_debug_segfault.cc:8
8 std::cout << *pointer << std::endl;
Missing separate debuginfos, use: dnf debuginfo-install libgcc-10.3.1-1.fc32.x86_64 libstdc++-10.3.1-1.fc32.x86_64
(gdb) print pointer
$1 = (double *) 0x0
Now we can check the pointer and see that the pointer has the value 0x0
which is a nullptr
and we have not allocated memory.
Let us have a look at the code:
#include <iostream>
using namespace std;
int main(int n, char** args)
{
double * pointer = nullptr;
std::cout << *pointer << std::endl;
return 0;
}
Can you see why we have the segfault in the code?
This is the correct version of the code after debugging:
#include <iostream>
using namespace std;
int main(int n, char** args)
{
double * pointer = 2;
std::cout << *pointer << std::endl;
return 0;
}
Can you see why we have the segfault in the code?
Valgrind can help with the following:
delete
and delete[]
.To detect the previous segfault, we could use the memcheck
tool which is part of valgrind
valgrind ./segfault
will enable the memory check valgrind --tool=memcheck ./segfault
==24842== Memcheck, a memory error detector
==24842== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==24842== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==24842== Command: ./segfault
==24842==
==24842== Invalid read of size 8
==24842== at 0x401191: main (code.cc:8)
==24842== Address 0x0 is not stack'd, malloc'd or (recently) free'd
valgrind --tool=memcheck ./segfault2
==25418== Memcheck, a memory error detector
==25418== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25418== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==25418== Command: ./segfault2
==25418==
2
==25418== Mismatched free() / delete / delete []
==25418== at 0x484565B: operator delete[](void*) (vg_replace_malloc.c:1103)
==25418== by 0x4011F4: main (code2.cc:9)
==25418== Address 0x4db2c80 is 0 bytes inside a block of size 8 alloc'd
==25418== at 0x4841FF5: operator new(unsigned long) (vg_replace_malloc.c:422)
==25418== by 0x4011AE: main (code2.cc:7)
Looking at the code:
#include <iostream>
int main(int n, char** args)
{
double * pointer = new double(2);
std::cout << *pointer << std::endl;
delete [] pointer;
return 0;
}
valgrind ./index
==28728== Memcheck, a memory error detector
==28728== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==28728== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==28728== Command: ./index
==28728==
==28728== Invalid read of size 8
==28728== at 0x4011AB: main (code3.cc:7)
==28728== Address 0x4db2cb0 is 8 bytes after a block of size 40 alloc'd
==28728== at 0x484322F: operator new[](unsigned long) (vg_replace_malloc.c:640)
==28728== by 0x40119E: main (code3.cc:6)
Let us look at the code:
#include <iostream>
int main(int n, char** args)
{
double * pointer = new double[5];
std::cout << pointer[6] << std::endl;
return 0;
}
valgrind --tool=memcheck ./free
==9345== Memcheck, a memory error detector
==9345== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9345== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==9345== Command: ./free
==9345==
==9345==
==9345== HEAP SUMMARY:
==9345== in use at exit: 0 bytes in 0 blocks
==9345== total heap usage: 2 allocs, 2 frees, 72,712 bytes allocated
==9345==
Let us look at the code:
#include <iostream>
double * func(int i){
return new double(i);
}
int main(int n, char** args)
{
double* value = func(0);
delete value;
}