[SOLVED] CS chain compiler c++ data structure ECS 150 GDB tutorial

$25

File Name: CS_chain_compiler_c++_data_structure_ECS_150__GDB_tutorial.zip
File Size: 546.36 KB

5/5 - (1 vote)

ECS 150 GDB tutorial
Prof. Joel Porquet-Lupine
UC Davis 2020/2021
Copyright 2017-2021 Joel Porquet-Lupine CC BY-NC-SA 4.0 International License /
1 / 24

GDB
GNU project
Started by Richard Stallman in 1983
Free software, mass collaboration project in response to proprietary UNIX
Copyleft license: GNU GPL
User programs: text editor (Emacs), compiler (GCC toolchain), debugger (GDB), and various utilities (ls, grep, awk, make, etc.)
Kernel: GNU Hurd
GDB
GNU DeBugger
Supports many languages
Including C and C++
Inspection of program during execution
Execution flow
Data
Helps finding errors like segmentation fault
Read the fully-detailed manual: https://sourceware.org/gdb/current/onlinedocs/gdb/
2 / 24
/

GDB usage
Compilation flags
Canonical compilation command line:
$ gcc [cflags] -o Optimize for speed (-O2)
$ gcc -Wall -Werror -O2 -o myprogram main.c Enable debugging support (-g)
$ gcc -Wall -Werror -g myprogram main.c
Not recommended to use debugging along with optimizations No optimization option is equivalent to -O0
3 / 24
/

GDB usage
Makefile digression
During development, very useful to be able to debug your program
For production, probably better to disable the debug support and activate all possible optimization support
Reduce size of the executable (can easily be by 50%!) Increase performance (can also be by 50%!)
Makefile automation
ifeq ($(D),1)
CFLAGS += -g # Enable debugging else
CFLAGS += -O2 # Enable optimization endif
Building mode
$ make D=1 # compile with debug support and no optimization
$ make # compile with optimizations (production)
Probably want to use make clean when changing building mode
4 / 24
/

GDB usage
Starting GDB
Start GDB, specify the program to debug
$ gdb

(gdb) file myprogram
Reading symbols from myprogramdone. (gdb)
Or, start GDB with the program to debug as argument
$ gdb myprogram

Reading symbols from myprogramdone. (gdb)
Running the program
Without any argument:
(gdb) run
With arguments:
(gdb) run argv1 argv2
5 / 24
/

GDB usage
Interactive help
GDB offers an interactive shell
History management Auto-complete (with TAB)
In order to discover what you can do, just ask:
(gdb) help
List of classes of commands:
aliases Aliases of other commands
breakpoints Making program stop at certain points
(gdb) help breakpoints
Making program stop at certain points.
List of commands:
awatch Set a watchpoint for an expression break Set breakpoint at specified location
(gdb) help break
Set breakpoint at specified location.
break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
6 / 24
/

GDB usage
Possible scenarios
1. Program doesnt have bugs:
It will run fine until completion 2. Best-case scenario, regarding bugs:
Segmentation fault 3. Worst-case scenario:
Doesnt crash but wrong result
Bugs that dont trigger any segmentation fault
In this case, youll probably have to spend more time
$ ./myprogram
I worked, hurray!
$ ./myprogram
segmentation fault (core dumped) ./myprogram
$ ./myprogram
I work, rray!
7 / 24
/

Segmentation faults
Example #1
#include #include #include
size_t foo_len (const char *s) {
return strlen(s); }
int main (int argc, char *argv[]) {
char *a = NULL;
printf (size of a = %d
, foo_len(a));
return 0; }
Execution
$ ./strlen-test
zsh: segmentation fault (core dumped) ./strlen-test
8 / 24
/

Segmentation faults
Run with GDB
(After compiling the code with -g)
$ gdb ./strlen-test
(gdb) run
Starting program: /home/joel/tmp/test/strlen-test
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7abc446 in strlen () from /usr/lib/libc.so.6
(gdb)
Backtrace
First thing to do when getting a segfault:
Understand what is the sequence of calls that brought us there
Investigate
foo_len() is supposed to receive a pointer
Here it receives 0 (aka NULL)
Looks like this NULL pointer probably gets dereferenced in strlen()
(gdb) backtrace # use just bt
#0 0x00007ffff7abc446 in strlen () from /usr/lib/libc.so.6
#1 0x000000000040055e in foo_len (s=0x0) at strlen-test.c:7
#2 0x0000000000400583 in main (argc=1, argv=0x7fffffffd788) at strlen-test.c:14
9 / 24
/

Segmentation faults
Fix
Here, the problem is fairly obvious
size_t foo_len (const char *s) {
return strlen(s); }
int main (int argc, char *argv[]) {
char *a = This is a valid string;
printf (size of a = %d
, foo_len(a));
return 0; }
And, celebrate!
$ ./strlen-test size of a = 22
10 / 24
/

Segmentation faults
Better fix
Prevent the same bug from happening again
size_t foo_len (const char *s) {
assert(s && String cannot be NULL here!);
return strlen(s); }
int main (int argc, char *argv[]) {
char *a = NULL;
printf (size of a = %d
, foo_len(a));
return 0; }
$ ./strlen-test
strlen-test: strlen-test.c:8: foo_len:
Assertion `s && String cannot be NULL here! failed.
11 / 24
/

Segmentation faults
Example #2
#include #include
const static int len = 10;
int main(void) {
int *tab; unsigned int i;
tab = malloc(len * sizeof(int)); for (i = len 1; i >= 0; i)
tab[i] = i;
free(tab);
return 0; }
Execution
$ ./tablen-test
segmentation fault (core dumped) ./tablen-test
12 / 24
/

Segmentation faults
Run GDB
$ gdb ./tablen-test
(gdb) run
Starting program: /home/joel/tmp/test/tablen-test
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400535 in main () at tablen-test.c:14
14tab[i] = i;
Backtrace
Except that here, its not much of help
Inspect variables
Display index i so that we know which index in the array was being accessed:
(gdb) bt
#0 0x0000000000400535 in main () at tablen-test.c:14
(gdb) print i $1 = 4294967295
13 / 24
/

Segmentation faults
Fix
Problem is a case of overflow
An unsigned int type automatically wraps from 0 to 4294967295
#include #include
const static int len = 10;
int main(void) {
int *tab; int i;
tab = malloc(len * sizeof(int)); for (i = len 1; i >= 0; i)
tab[i] = i;
free(tab);
return 0; }
14 / 24
/

Tracking bugs
Behavior bugs
Behavioral bugs more complicated to find because program doesnt crash Its just that the output is wrong
#include #include #include
int main(void)
{
int i;
char str[] = Tracking bugs is my passion;
printf(Before: %s
, str);
for (i = 0; i < strlen(str) – 1; i++) str[i] = toupper(str[i]);printf(“After: %s
“, str); return 0;}Execution Before: Tracking bugs is my passionAfter: TRACKING BUGS IS MY PASSIOn15 / 24/ Tracking bugsSetting breakpointsStop the program during the execution at a designated point Set as many breakpoints as necessaryGDB will always stop the execution when reaching themBreaking at exact location in code (gdb) break string-test.c:13Breakpoint 1 at 0x4005ef: file string-test.c, line 13.(gdb) rStarting program: /home/joel/tmp/test/string-test Before: Tracking bugs is my passionBreakpoint 1, main () at string-test.c:1313str[i] = toupper(str[i]);16 / 24/ Tracking bugsBreaking at a particular function(gdb) b mainBreakpoint 1 at 0x40059f: file string-test.c, line 8.(gdb) rStarting program: /home/joel/tmp/test/string-testBreakpoint 1, main () at string-test.c:88 char str[] = “Tracking bugs is my passion”;Breaking only if condition is satisfied (gdb) b string-test.c:13 if i == 5Breakpoint 1 at 0x4005ef: file string-test.c, line 13.(gdb) rStarting program: /home/joel/tmp/test/string-test Before: Tracking bugs is my passionBreakpoint 1, main () at string-test.c:1313str[i] = toupper(str[i]);(gdb) print i $1 = 517 / 24/ Tracking bugsDealing with breakpointsSet at least one breakpoint before running the programOtherwise the program will run until completionOnce the program stops and the gdb shell is available, a few options:1. Continue the execution until hitting the same or another breakpoint(gdb) continue # or just ‘c’2. Execute only the next line of code and break again(gdb) step # or just ‘s’ Careful, step enters function calls3. Jump over function calls(gdb) next # or just ‘n’Tip: typing in the interactive GDB shell repeats the last command
18 / 24
/

Tracking bugs
Printing variables
int a = 2;
char b = x;
int *c = &a
char *s = A string;

// <= breaking hereprint Inspect the value of all your variables with command DefaultBy default, prints variables according to their typeTweakCan tweak both the way print prints and what it prints(gdb) print a $1 = 2(gdb) p b$2 = 120 ‘x’ (gdb) p c$3 = (int *) 0x7fffffffd65c (gdb) p s$4 = 0x40070b “A string” (gdb) print /x a $1 = 0x2(gdb) p /c b+2 $2 = 122 ‘z’ (gdb) p *c$3 = 2 (gdb) p s[0] $4 = 65 ‘A’19 / 24/ Tracking bugsPrinting data structuresstruct entry { int key;char *name; } obj = {.key = 2,.name = “toto”,};struct entry *e = &objprintWith , you can access the pointer and the object it’s pointing to:(gdb) print e$1 = (struct entry *) 0x7fffffffd640 (gdb) print &obj$2 = (struct entry *) 0x7fffffffd640 (gdb) p *e$3 = {key = 2, name = 0x400734 “toto”} (gdb) p e->key
$4 = 2
(gdb) p obj.name
$5 = 0x400734 toto
20 / 24
/

Misc
Setting watchpoint
Breakpoints are for interrupting the execution flow at a specific location Watchpoints are for interrupting the program when a variable is modified
(gdb) watch i
Hardware watchpoint 2: i
(gdb) c
Continuing.
Before: Tracking bugs is my passion
Hardware watchpoint 2: i
Old value = 0
New value = 1
0x0000000000400612 in main () at string-test.c:12
12for (i = 0; i < strlen(str) – 1; i++)21 / 24/ MiscOther useful commandsfinishRuns until the current function is finisheduntilWhen executed in a loop, continues the execution until the loop ends info breakpointsShows informations about all declared breakpoints (gdb) info bNum Type Disp Enb Address What1 breakpoint keep y 0x000000000040059f in main at string-test.c:8 breakpoint already hit 1 time2 hw watchpoint keep y ibreakpoint already hit 2 timesdeleteDeletes a breakpoint 22 / 24/ ValgrindExample#include void f(void)
{
int *x = malloc(10 * sizeof(int));
x[10] = 0; }
int main(void) {
f();
return 0; }
23 / 24
/

Valgrind
Run
$ valgrind leak-check=full ./valgrind_example

==31134== Invalid write of size 4
==31134== at 0x108668: f (in /home/joel/work/ecs150/slides/tuto_gdb/code/valgrind_example) ==31134== by 0x108679: main (in /home/joel/work/ecs150/slides/tuto_gdb/code/valgrind_example) ==31134== Address 0x51f0068 is 0 bytes after a block of size 40 allocd
==31134==
==31134==
==31134==
==31134==
==31134==
==31134== HEAP SUMMARY:
==31134== in use at exit: 40 bytes in 1 blocks
==31134== total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==31134==
at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
by 0x10865B: f (in /home/joel/work/ecs150/slides/tuto_gdb/code/valgrind_example)
by 0x108679: main (in /home/joel/work/ecs150/slides/tuto_gdb/code/valgrind_example)
==31134== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31134==
==31134==
==31134==
==31134==
==31134== LEAK SUMMARY:
at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
by 0x10865B: f (in /home/joel/work/ecs150/slides/tuto_gdb/code/valgrind_example)
by 0x108679: main (in /home/joel/work/ecs150/slides/tuto_gdb/code/valgrind_example)
==31134==
==31134==
==31134==
==31134==
==31134==
==31134==
==31134== For counts of detected and suppressed errors, rerun with: -v
==31134== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
definitely lost: 40 bytes in 1 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 0 bytes in 0 blocks
suppressed: 0 bytes in 0 blocks
24 / 24
/

Reviews

There are no reviews yet.

Only logged in customers who have purchased this product may leave a review.

Shopping Cart
[SOLVED] CS chain compiler c++ data structure ECS 150 GDB tutorial
$25