预备知识
调试原则
-
确认的基本原则:逐个确认自己认为正确的事情所对应的代码确实是正确的。
-
从简单的工作开始调试
-
使用自顶向下的方法
编写模块化,较好的抽象的代码。函数调用的前后就提供了暂停的机会。
-
使用调试工具确定段错误的位置
当发生段错误(内存访问错误)后,在调试器中重新运行程序并重新产生段错误,然后利用反向跟踪(backtrack)功能获得其他有用的信息。
-
通过发出中断确定无限循环的位置
怀疑程序存在无限循环,在调试器中运行程序,运行足够长时间以进入循环后,运行调试器发出中断,然后执行反向跟踪,了解已到达循环主体的哪个位置以及程序是如何达到该位置的。(程序还没被取消执行,可以根据需要恢复执行)
-
使用二分搜索
- 当由于语法错误无法正常编译时,可以注释掉一般的代码。
- 若程序运行后在第n次循环出现问题,可以检查该变量在n / 2 的时候的指。
调试工具
- GDB:gdb prog
- DDD,GDB的GUI版本:ddd prog
- Eclipse,IDE
- CGDB 起GDB前端的作用
GDB
|
|
| command parameters are in italics optional parameters are in square brackets | elective |
|---|---|
| Help Commands help command apropos keyword | Get help on a certain command Search help for a particular keyword |
| Starting and Quitting gdb [-tui] [-c core] [exename] quit run [arg1] [arg2] […] kill file exename | Start gdb on an executable or standalone; specify “-tui” to start the TUI GUI; specify “-c” with a corefile name to see where a crash occurred load an execuable file by name |
| Breakpoints and Watchpoints break function break lino break file.c:lino beak *0x844823 info beakpointers clear location clear delete number delete enable number disable number watch expression rwatch expression awatch expression info watch | If you’re running in dumb terminal mode, gdb will print the line it will execute next. If you’re running in cool GUI mode, the line it will execute next will be highlighted in the source window. To clear a breakpoint, use the clear command with the breakpoint location. You can also clear a breakpoint by number with the delete command. enable or disable breakpoints, though these two commands take a breakpoint number as an argument, not a location! The enabled/disabled status of a breakpoint is visible under the “Enb” column in the breakpoint listing. Hardware watchpoints are special breakpoints that will trigger whenever an expression changes. Break when a variable is read from Break when a variable is writen or read from |
| Stepping and Running next nexti step stepi stepi 4 advance location continue jump location finish CTRL-C Enter | Use the next command to execute a line of source code. Use the nexti command to execute a machine instruction. next will execute the function until it’s done, and then return you to the next line . What if you have a function you want to step into from your current function, and trace through that function line-by-line? Use the step (or s) command to do this. It works just like next, except it steps into functions. To step for a single assembly instruction, use the stepi command. stepi 4 will step four instruction advance is just shorthand for “continue to this temporary breakpoint.” Use the continue (or c) command to continue execution. The jump command works exactly like continue, except it takes a location to jump to as an argument. If you need to stop at the jump destination, set a breakpoint there first. To exit the current function and return to the calling function, use the finish command. Stop running, wherever you are just hitting RETURN will repeat the last command entered. |
| 检查代码 disas disas sum disas *0x2324897 disas 0x210884 0x23904242 print /x $eip | |
| Examining Variables display expression info display undisplay number print expression print $eax print /x $eax print /t $eax print 0x100 print /x 555 print /x ($ebp+8) print *(int *) 0xfff076b0 print *(int *) ($ebp+8) x/2w 0xfff076b0 x/20b sum | inspect variables over the course of the run, just display them. Each time you step the code, the value of the variable will be displayed (if it’s in scope). Use this number to undisplay the variable. If you forget the display numbers, you can type info display to get them: If you just want to one-off know the value of a variable, you can print it. There’s also a handy printf command that you can use to better format your output if you want to: |
| set variable expression set variable i = 50 or set (i = 20) | the set variable command changing Variables and Values at Runtime. This, along with the jump command, can help you repeat sections of code without restarting the program. |
| stack backtrace | The command backtrace (or bt) will show you the current function call stack, with the current function at the top, and the callers in order beneath it: |
| Attach to a Running Process | If your program is already going and you want to stop it and debug, first you’ll need the process ID (PID), which will be a number. (Get it from Unix’s ps command.) Then start gdb with no arguments, you’ll use the attach command with the PID to attach to (and break) the running program. Once we’ve quit the debugger and detached from the program, the program returns to running normally. Mix this with set variable, above, and you’ve got some power! |
| Using Coredumps for Postmortem Analysis 事后分析 | $ cc -g -o foo foo.c $ ./foo Segmentation fault (core dumped) This means that a core file (with a memory snapshot from the time of the crash) has been created with the name “core”. If you’re not getting a core file (that is, it only says “Segmentation fault” and no core file is created), you might have your ulimit set too low; try typing ulimit -c unlimited at your shell prompt. You can fire up gdb with the -c option to specify a core file: $ gdb -tui -c core foo And, if in TUI mode, you’ll be greeted with a screen of information, telling you why the program exited (“signal 11, Segmentation fault”), and the highlight will be on the offending line. (In dumb terminal mode, the offending line is printed out.) |
| Window Functions info win focus name focus pre focus next winheight | In TUI mode, you can get a list of existing windows with the info win command. You can then change which window has focus with the focus (or fs) command. focus takes either a window name, or “prev” or “next” as an argument. Valid window names are “SRC” (source window), “CMD” (command window), “REGS” (registers window), and “ASM” (assembly window). (Window names are case in-sensitive.) Note that when the SRC window has focus, the arrow keys will move the source code, but when the CMD window has focus, the arrow keys will select the previous and next commands in the command history. (For the record, the commands to move the SRC window single lines and single pages are +, -, <, and >.) The winheight (or wh) command sets the height of a particular window. |
| Display Registers and Assembly layout src layout asm layout split layout reg tui reg general tui reg float tui reg system tui reg next set disassembly-flavor info registers info all-registers | Standard layout—source on top, command window on the bottom Just like the “src” layout, except it’s an assembly window on top Three windows: source on top, assembly in the middle, and command at the bottom Opens the register window on top of either source or assembly, whichever was opened last Show the general registers Show the floating point registers show the “system” registers Show the next page of registers—this is important because there might be pages of registers that aren’t in the “general”, “float”, or “system” sets Assembly code comes in two flavors on Intel machines: Intel and AT&T. You can set which one appears in the disassembly window with set disassembly-flavor. Valid values are “intel” and “att”. If you already have the assembly window open, you’ll have to close it and reopen it (layout src followed by layout split, for example.) To display registers in dumb terminal mode, type info registers for the integer registers, or info all-registers for everything. |
- Beej’s Quick Guide to GDB (based on the very handy gdb -tui mode)
Compiling
You have to tell your compiler to compile your code with symbolic debugging information included. Here’s how to do it with gcc, with the -g switch:
$ gcc -g hello.c -o hello
$ g++ -g hello.cpp -o hello
Once you’ve done that, you should be able to view program listings in the debugger.
More Information
Check out the Official GDB Documentation for more information than you can shake a stick at!
Also, a good GNU GDB front-end is DDD, the DataDisplayDebugger.
All the normal gdb commands will work in GUI mode (TUI), and additionally the arrow keys and pgup/pgdown keys will scroll the source window (when it has focus, which it does by default). Also, you can change which file or function is displayed in the source window by giving the command list with a location as an argument, for example, “list hello.c:5 to bring up the file hello.c on line 5.