How to use gdb on C++ code File: gdb.help Author: course (send problems to walton@das) Version: 3 Using the NDFA assignment as an example, we will go through procedures using gdb to find bugs. After your program compiles, use: gdb ndfa_test run (e.g. "list main") to list the code of a function, and then br to set a break point on a line number. After the "list " you may type carriage return to list more lines. Also, you may type list , to list the lines you want. For example, you may set a breakpoint in main right after an ndfa has been constructed, and then look at the ndfa in memory to see if it is right. Sometimes your program malfunctions by calling your error routine. Setting br error will stop the program when error is called. There is more than one error routine, and this just sets the breakpoint on the first error routine, but it seems to work a lot of the time. If you want to set breakpoints on all the error routines, do `list error' and then list the rest of the file setting breakpoints on the first line of each error routine. Let us consider the case where your program gets a segmentation fault or has an infinite loop which you stopped with a control-C or stopped on a breakpoint on error, and you need to find what is going on in the program. First type bt which prints a "backtrace" of the function call frames. Frame 0 is the last function call, frame 1 the next to last function call, etc. The function called in each frame is displayed, and also its arguments. Often just looking at the arguments will indicate a problem. If you want to look at frame 2 in more detail type frame 2 list p p ... where the expressions are (almost) any C++ expression that could be evaluated by the code listed in the context of the call frame. By using p commands (p is for `print') you can look at all the data and figure out what is wrong. There is one unfortunate gdb bug that requires you do extra work to compensate (this is called doing a "workaround" of the bug). Sometimes gdb does not correctly identify the file containing a function. For example, it may claim that the function single_character is in .......io_manip.h...... instead of ndfa.cc. Then when you go to a frame that is executing single_character, list does not work, and neither do the prints. You can work around this bug by replacing your normal "list" command by list ndfa.cc:1 . . . where the list command lists the first line of ndfa.cc and then you do enough carriage returns to get to the single_character function. Then you can do prints as if the gdb bug does not exist. Unfortunately you still will not know exactly which line of single_character was executing, which "bt" and "frame 2" would normally have told you, and you will just have to guess. In looking at data a few points are helpful. First, addresses that are near 0 are illegal, and cause segmentation faults. This is because computer system designers learned long ago that errors in computing addresses often resulted in small integer addresses, so making these illegal addresses catches a lot of programming bugs better. Second, if you do something like print my_ndfa and get back that initial = 0x130458, which is a pointer to a state, then you can print the state via print * my_ndfa.initial or print {state}0x130458 Also, if the answer to print my_ndfa is named $5 you can use print * $5.initial and if the answer to this is $6 and has a non NULL character_transition, you can print that state by either print * $6.character_transition or print * my_ndfa.initial->character_transition For more subtle problems of computing the wrong thing it may be desirable to single step the program, starting from some breakpoint. The "next" command n steps to the next line in the current file. After this command, a simple carriage return repeats the "next" command. The line printed by the "next" command is the next line to be executed: it has not been executed yet. The step command s executes the next line, but if that line calls a function the step command stops at the first line of that called function, rather than letting the entire function execute as the "next" command does. So you use the step command occasionally when you want to go into a called function. If you want to do this you need to look carefully at the next line to be executed to see whether to use step or next. After a bit of single stepping, you may find it advisable to just set a break point and look at data at that breakpoint. The continue command c continues execution after a breakpoint, until the next breakpoint.