The debugging tool, gdb. The simplest debugging technique is the insertion of printf statements at appropriate places to trace the execution of the program. We will later see the conditional compilation directive which makes it easy to take out debugging statements without physically deleting them from the code. For the moment we will look at an interactive technique for debugging code, which makes insertion of intermediate printfs, for tracing, unnecessary. gdb is a GNU Free Software Foundation debugging tool. (GNU means "Gnu is Not Unix"). To use gdb on a program, compile the program with the switch -g. (This includes a global symbol table in a.out.) That is: ug% gcc -g file.c (creates a.out). Then invoke gdb by: ug% gdb file a.out For example, consider the file try_swap.c containing: #include void swap ( int *, int *); void bad_swap(int *, int *); int main () { int array[5] = {3, 7, 13, 5, 19}; printf("%d %d\n",array[0],array[4]); bad_swap(&array[0], &array[4]); printf("%d %d\n",array[0],array[4]); swap(&array[0], &array[4]); printf("%d %d\n",array[0],array[4]); return 0; } void swap ( int *a, int *b ) { int temp; temp = *a; *a = *b; *b = temp; } void bad_swap ( int *a, int *b ) { int *temp; temp = a; a = b; b = temp; } The output from this is, on 3 lines, 3 19 3 19 19 3. Clearly swap works but bad_swap does not. We can explain this in general terms, but it is illustrative to look at the code in gdb and see what actually happens. First: ug$ gcc -Wall -g try_swap.c ug$ gdb a.out <==== invoke gdb GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.14 (sparc-sun-solaris2), Copyright 1995 Free Software Foundation, Inc... (gdb) l <===== lists 10 lines 1 #include 2 void swap ( int *, int *); 3 void bad_swap(int *, int *); 4 int 5 main () 6 { 7 int array[5] = {3, 7, 13, 5, 19}; 8 printf("%d %d\n",array[0],array[4]); 9 bad_swap(&array[0], &array[4]); 10 printf("%d %d\n",array[0],array[4]); (gdb) <=== hit return 11 swap(&array[0], &array[4]); 12 printf("%d %d\n",array[0],array[4]); 13 return 0; 14 } 15 void 16 swap ( int *a, int *b ) { 17 int temp; 18 temp = *a; *a = *b; *b = temp; 19 } 20 void (gdb) <=== hit return 21 bad_swap ( int *a, int *b ) { 22 int *temp; 23 temp = a; a = b; b = temp; 24 } (gdb) run Starting program: /users/students/prof1400/marker/cs1401/a.out 3 19 3 19 19 3 Program exited normally. (gdb) We can insert break points and stop the process on any line. Eg (gdb) break 9 <==== typed by me. Breakpoint 3 at 0x10840: file try_swap.c, line 9. (gdb) break 22 <==== typed by me. Breakpoint 1 at 0x108fc: file try_swap.c, line 23. (gdb) break 24 <==== typed by me. Breakpoint 2 at 0x10914: file try_swap.c, line 24. (gdb) break 10 Breakpoint 4 at 0x10858: file try_swap.c, line 10. (gdb) run Starting program: /users/students/prof1400/marker/cs1401/a.out 3 19 Breakpoint 3, main () at try_swap.c:9 9 bad_swap(&array[0], &array[4]); (gdb) p &array[0] <=== p means "print" $9 = (int *) 0xeffffae8 (gdb) p &array[4] $10 = (int *) 0xeffffaf8 (gdb) p array[0] $11 = 3 (gdb) p array[4] $12 = 19 (gdb) c <=== c typed by me "continue" Continuing. Breakpoint 1, bad_swap (a=0xeffffae8, b=0xeffffaf8) at try_swap.c:23 23 temp = a; a = b; b = temp; (gdb) p a $13 = (int *) 0xeffffae8 (gdb) p b $14 = (int *) 0xeffffaf8 (gdb) p *a $15 = 3 (gdb) p *b $16 = 19 <==== Thus, inside bad_swap, a b have the values of the addresses of array[0], array[4]. Breakpoint 2, bad_swap (a=0xeffffaf8, b=0xeffffae8) at try_swap.c:24 24 } (gdb) p a $21 = (int *) 0xeffffaf8 (gdb) p b $22 = (int *) 0xeffffae8 (gdb) p *a $23 = 19 (gdb) p *b $24 = 3 <=== ie the swap appears to have been made. (gdb) c Breakpoint 4, main () at try_swap.c:10 10 printf("%d %d\n",array[0],array[4]); (gdb) p &array[0] $26 = (int *) 0xeffffae8 (gdb) p &array[4] $27 = (int *) 0xeffffaf8 <==== the swap was not made. The thing to note here is that the actual contents of the memory locations were not touched. Now look at the result of running swap. Insert breaks before, after and in swap. (gdb) break 11 Breakpoint 5 at 0x10870: file try_swap.c, line 11. (gdb) break 18 Breakpoint 6 at 0x108c0: file try_swap.c, line 18. (gdb) break 19 Breakpoint 7 at 0x108e8: file try_swap.c, line 19. (gdb) break 12 Breakpoint 8 at 0x10888: file try_swap.c, line 12. (gdb) run Breakpoint 5, main () at try_swap.c:11 11 swap(&array[0], &array[4]); (gdb) p &array[0] $28 = (int *) 0xeffffae8 (gdb) p &array[4] $29 = (int *) 0xeffffaf8 (gdb) c Continuing. Breakpoint 6, swap (a=0xeffffae8, b=0xeffffaf8) at try_swap.c:18 18 temp = *a; *a = *b; *b = temp; (gdb) p a $30 = (int *) 0xeffffae8 (gdb) p b $31 = (int *) 0xeffffaf8 (gdb) p *a $32 = 3 (gdb) p *b $33 = 19 (gdb) c Continuing. Breakpoint 7, swap (a=0xeffffae8, b=0xeffffaf8) at try_swap.c:19 19 } (gdb) p a $34 = (int *) 0xeffffae8 (gdb) p b $35 = (int *) 0xeffffaf8 (gdb) p *a $36 = 19 (gdb) p *b $37 = 3 (gdb) c Continuing. Breakpoint 8, main () at try_swap.c:12 12 printf("%d %d\n",array[0],array[4]); (gdb) p &array[0] $39 = (int *) 0xeffffae8 (gdb) p array[0] $40 = 19 (gdb) p &array[4] $41 = (int *) 0xeffffaf8 (gdb) p array[4] <=== the addresse have not changed. But $42 = 3 the contents have. Other possible commands: (gdb) p array $43 = {19, 7, 13, 5, 3} (gdb) p &array $44 = (int (*)[5]) 0xeffffae8 (gdb) p *(array+2) $48 = 13 (gdb) p sizeof(array) $49 = 20