当我尝试在网上寻找「GDB 范例」时,我发现大多数文章只是贴出了命令,而没有讲解相关输出。GDB 是 GNU 调试器(GNU Debugger),亦是 Linux 系统上的标准调试器。在听 Greg Law 在 CppCon 2015 上关于 GDB 的演讲时(Give me 15 minutes and I'll change your view of GDB),我发现 Law 给出了相关输出,从而意识到了上述不足。
Law 的演讲,也让我意识到应该分享一个使用 GDB 解决问题的完整范例:包括命令输出、各个步骤,以及一些死胡同。也就是说,这篇文章将分享使用 GDB 调试查错的一般步骤,而不是其他特别的东西。这篇文章介绍了 GDB 的基本使用方法,因此可以作为教程使用。不过,还有很多东西没有介绍,请谨记在心。
# gdb `which python` /var/cores/core.python.30520 GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty"for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration"for configuration details. For bug reporting instructions, please see: . Find the GDB manual and other documentation resources online at: . For help, type"help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done.
warning: core file may not match specified executable file. [New LWP 30520] [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
warning: JITed object file architecture unknown is not compatible with target architecture i386:x86-64. Core was generated by `python ./cachetop.py'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x00007f0a37aac40d in doupdate () from /lib/x86_64-linux-gnu/libncursesw.so.5
(gdb) bt #0 0x00007f0a37aac40d in doupdate () from /lib/x86_64-linux-gnu/libncursesw.so.5 #1 0x00007f0a37aa07e6 in wrefresh () from /lib/x86_64-linux-gnu/libncursesw.so.5 #2 0x00007f0a37a99616 in ?? () from /lib/x86_64-linux-gnu/libncursesw.so.5 #3 0x00007f0a37a9a325 in wgetch () from /lib/x86_64-linux-gnu/libncursesw.so.5 #4 0x00007f0a37cc6ec3 in ?? () from /usr/lib/python2.7/lib-dynload/_curses.x86_64-linux-gnu.so #5 0x00000000004c4d5a in PyEval_EvalFrameEx () #6 0x00000000004c2e05 in PyEval_EvalCodeEx () #7 0x00000000004def08 in ?? () #8 0x00000000004b1153 in PyObject_Call () #9 0x00000000004c73ec in PyEval_EvalFrameEx () #10 0x00000000004c2e05 in PyEval_EvalCodeEx () #11 0x00000000004caf42 in PyEval_EvalFrameEx () #12 0x00000000004c2e05 in PyEval_EvalCodeEx () #13 0x00000000004c2ba9 in PyEval_EvalCode () #14 0x00000000004f20ef in ?? () #15 0x00000000004eca72 in PyRun_FileExFlags () #16 0x00000000004eb1f1 in PyRun_SimpleFileExFlags () #17 0x000000000049e18a in Py_Main () #18 0x00007f0a3be10830 in __libc_start_main (main=0x49daf0 <main>, argc=2, argv=0x7ffd33d94838, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffd33d94828) at ../csu/libc-start.c:291 #19 0x000000000049da19 in _start ()
# gdb `which python` GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty"for details. This GDB was configured as "x86\_64-linux-gnu". Type "show configuration"for configuration details. For bug reporting instructions, please see: . Find the GDB manual and other documentation resources online at: . For help, type"help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done.
而后,使用 b 命令(break 的缩写)设置断点。
1 2
(gdb) b *doupdate + 289 No symbol table is loaded. Use the "file"command.
啊,出错了……这是我有意呈现的错误。通常,我们会将断点首先设置在 main 处,因为彼时符号应该都加载完毕了。而后,在程序遇到断点并暂停时,我们可以设置其他断点。此处,我需要关注 doupdate 函数,因此,我将断点首先设置在这个函数被调用的地方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
(gdb) b doupdate Function "doupdate" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (doupdate) pending. (gdb) r cachetop.py Starting program: /usr/bin/python cachetop.py [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". warning: JITed object file architecture unknown is not compatible with target architecture i386:x86-64.
Breakpoint 1, 0x00007ffff34ad2e0 in doupdate () from /lib/x86_64-linux-gnu/libncursesw.so.5 (gdb) b *doupdate + 289 Breakpoint 2 at 0x7ffff34ad401 (gdb) c Continuing.
Breakpoint 2, 0x00007ffff34ad401 in doupdate () from /lib/x86_64-linux-gnu/libncursesw.so.5
# gdb `which python` GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty"for details. This GDB was configured as "x86\_64-linux-gnu". Type "show configuration"for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type"help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/bin/python...(no debugging symbols found)...done.
而后,我将断点设置在 doupdate 函数上;当遇到之后,我会打开记录功能,直到进程崩溃。这种记录功能,对系统影响是很大的。所以,最好不要从 main 函数就开始记录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
(gdb) b doupdate Function "doupdate" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (doupdate) pending. (gdb) r cachetop.py Starting program: /usr/bin/python cachetop.py [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". warning: JITed object file architecture unknown is not compatible with target architecture i386:x86-64.
Breakpoint 1, 0x00007ffff34ad2e0 in doupdate () from /lib/x86_64-linux-gnu/libncursesw.so.5 (gdb) record (gdb) c Continuing.
Program received signal SIGSEGV, Segmentation fault. 0x00007ffff34ad40d in doupdate () from /lib/x86_64-linux-gnu/libncursesw.so.5
# gdb `which python` /var/cores/core.python.30520 GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 [...] warning: JITed object file architecture unknown is not compatible with target architecture i386:x86-64. Core was generated by `python ./cachetop.py'. Program terminated with signal SIGSEGV, Segmentation fault. #0 ClrBlank (win=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1129 1129 if (back_color_erase) (gdb) bt #0 ClrBlank (win=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1129 #1 ClrUpdate () at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1147 #2 doupdate () at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1010 #3 0x00007f0a37aa07e6 in wrefresh (win=win@entry=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_refresh.c:65 #4 0x00007f0a37a99499 in recur_wrefresh (win=win@entry=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_getch.c:384 #5 0x00007f0a37a99616 in _nc_wgetch (win=win@entry=0x1993060, result=result@entry=0x7ffd33d93e24, use_meta=1) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_getch.c:491 #6 0x00007f0a37a9a325 in wgetch (win=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_getch.c:672 #7 0x00007f0a37cc6ec3 in ?? () from /usr/lib/python2.7/lib-dynload/_curses.x86_64-linux-gnu.so #8 0x00000000004c4d5a in PyEval_EvalFrameEx () #9 0x00000000004c2e05 in PyEval_EvalCodeEx () #10 0x00000000004def08 in ?? () #11 0x00000000004b1153 in PyObject_Call () #12 0x00000000004c73ec in PyEval_EvalFrameEx () #13 0x00000000004c2e05 in PyEval_EvalCodeEx () #14 0x00000000004caf42 in PyEval_EvalFrameEx () #15 0x00000000004c2e05 in PyEval_EvalCodeEx () #16 0x00000000004c2ba9 in PyEval_EvalCode () #17 0x00000000004f20ef in ?? () #18 0x00000000004eca72 in PyRun_FileExFlags () #19 0x00000000004eb1f1 in PyRun_SimpleFileExFlags () #20 0x000000000049e18a in Py_Main () #21 0x00007f0a3be10830 in __libc_start_main (main=0x49daf0 <main>, argc=2, argv=0x7ffd33d94838, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffd33d94828) at ../csu/libc-start.c:291 #22 0x000000000049da19 in _start ()
# gdb --tui `which python` /var/cores/core.python.30520 ┌───────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ [ No Source Available ] │ │ │ │ │ │ │ │ │ │ │ │ │ └───────────────────────────────────────────────────────────────────────────┘ None No process In: L?? PC: ?? GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty"for details. This GDB was configured as "x86_64-linux-gnu". ---Type to continue, or q to quit---
chitecture i386:x86-64. Core was generated by `python ./cachetop.py'. Program terminated with signal SIGSEGV, Segmentation fault. ---Type <return> to continue, or q <return> to quit--- #0 ClrBlank (win=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1129 (gdb) layout split
Law 在单步回退中展示了如何使用 TUI。你可以想象一下,在代码执行的过程中,同时呈现汇编码和源代码是怎样的光景。
Find this C symbol: Find this global definition: back_color_erase Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file: Find assignments to this symbol:
敲回车。
1 2 3 4 5 6 7 8
[...] #define non_dest_scroll_region CUR Booleans[26] #define can_change CUR Booleans[27] #define back_color_erase CUR Booleans[28] #define hue_lightness_saturation CUR Booleans[29] #define col_addr_glitch CUR Booleans[30] #define cr_cancels_micro_mode CUR Booleans[31] [...]
# define NCURSES_EXPORT_VAR(type) NCURSES_IMPEXP type
以及 NCURSES_IMPEXP……
1 2 3 4 5 6 7 8
typedefstructterm { /* describe an actual terminal */ TERMTYPE type; /* terminal type description */ short Filedes; /* file description being written to */ TTY Ottyb, /* original state of the terminal */ Nttyb; /* current state of the terminal */ int _baudrate; /* used to compute padding */ char * _termname; /* used for termname() */ } TERMINAL;
# gdb `which python` GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 [...] (gdb) b set_curterm Function "set_curterm" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (set_curterm) pending. (gdb) r cachetop.py Starting program: /usr/bin/python cachetop.py [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, set_curterm (termp=termp@entry=0xa43150) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 { (gdb) c Continuing.
Breakpoint 1, set_curterm (termp=termp@entry=0xab5870) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 { (gdb) c Continuing.
Breakpoint 1, set_curterm (termp=termp@entry=0xbecb90) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 { (gdb) c Continuing.
Breakpoint 1, set_curterm (termp=0x0) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 {
staticboolterminalHasColors(int fd){ [...] // Now extract the structure allocated by setupterm and free its memory // through a really silly dance. structterm *termp = set_curterm((struct term *)nullptr); (void)del_curterm(termp); // Drop any errors here.
在早先的版本里,该函数是这样定义的。
1 2 3 4 5 6 7 8 9 10 11
staticboolterminalHasColors(){ if (constchar *term = std::getenv("TERM")) { // Most modern terminals support ANSI escape sequences for colors. // We could check terminfo, or have a list of known terms that support // colors, but that would be overkill. // The user can always ask for no colors by setting TERM to dumb, or // using a commandline flag. returnstrcmp(term, "dumb") != 0; } returnfalse; }
# gdb `which python` GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 [...] (gdb) b set_curterm Function "set_curterm" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (set_curterm) pending. (gdb) r cachetop.py Starting program: /usr/bin/python cachetop.py [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, set_curterm (termp=termp@entry=0xa43150) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 { (gdb) c Continuing.
Breakpoint 1, set_curterm (termp=termp@entry=0xab5870) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 { (gdb) c Continuing.
Breakpoint 1, set_curterm (termp=termp@entry=0xbecb90) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 { (gdb) c Continuing.
Breakpoint 1, set_curterm (termp=0x0) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 {
此时,我要使用 set 命令,复写相关的内存:使用之前传入 set_curterm 并正确执行的参数 0xbecb90 替代 0x0——当然,希望这一地址仍旧是合法的。
(gdb) set$rdi=0xbecb90 (gdb) c Continuing. warning: JITed object file architecture unknown is not compatible with target architecture i386:x86-64.
Program received signal SIGSEGV, Segmentation fault. 0x00007ffff34ad411 in ClrBlank (win=0xaea060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1129 1129 if (back_color_erase)
# gdb `which python` GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 [...] (gdb) b set_curterm Function "set_curterm" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (set_curterm) pending. (gdb) r cachetop.py Starting program: /usr/bin/python cachetop.py [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, set_curterm (termp=termp@entry=0xa43150) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 {
现在,我要将断点 1 转换为条件断点,使其只在 %rdi 的值为 0x0 时生效。
1 2 3 4 5 6 7 8 9 10 11
(gdb) cond 1 $rdi==0x0 (gdb) i b Num Type Disp Enb Address What 1 breakpoint keep y 0x00007ffff3c76a80 in set_curterm at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 stop only if$rdi==0x0 breakpoint already hit 1 time (gdb) c Continuing.
Breakpoint 1, set_curterm (termp=0x0) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 (gdb)
吼啊!通过使用 cond (conditional),我将断点 1 设置为条件断点。因此,当断点 1 下一次生效时,就是 set_curterm 接受的第一个参数值为 0x0 的时候。此外,我用了 i b (info breakpoints) 列出了所有断点的信息。
Breakpoint 1, set_curterm (termp=0x0) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80
(gdb) ret Make set_curterm return now? (y or n) y #0 0x00007ffff5a44e75 in llvm::sys::Process::FileDescriptorHasColors(int) () from /usr/lib/x86_64-linux-gnu/libbcc.so.0 (gdb) c Continuing.
Program received signal SIGSEGV, Segmentation fault. _nc_free_termtype (ptr=ptr@entry=0x100) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/free_ttype.c:52 52 FreeIfNeeded(ptr->str_table);
Breakpoint 1, set_curterm (termp=0x0) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tinfo/lib_cur_term.c:80 80 { (gdb) ret Make set_curterm return now? (y or n) y #0 0x00007ffff5a44e75 in llvm::sys::Process::FileDescriptorHasColors(int) () from /usr/lib/x86_64-linux-gnu/libbcc.so.0 (gdb) ret Make selected stack frame return now? (y or n) y #0 0x00007ffff45cabb8 in clang::driver::tools::Clang::ConstructJob(clang::driver::Compilation&, clang::driver::JobAction const&, clang::driver::InputInfo const&, llvm::SmallVector const&, llvm::opt::ArgList const&, char const*) const () from /usr/lib/x86_64-linux-gnu/libbcc.so.0 (gdb) c
# apt-get install -y python-dbg Reading package lists... Done [...] The following additional packages will be installed: libpython-dbg libpython2.7-dbg python2.7-dbg Suggested packages: python2.7-gdbm-dbg python2.7-tk-dbg python-gdbm-dbg python-tk-dbg The following NEW packages will be installed: libpython-dbg libpython2.7-dbg python-dbg python2.7-dbg 0 upgraded, 4 newly installed, 0 to remove and 20 not upgraded. Need to get 11.9 MB of archives. After this operation, 36.4 MB of additional disk space will be used. [...]
# gdb `which python` /var/cores/core.python.30520 GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 [...] Reading symbols from /usr/bin/python...Reading symbols from /usr/lib/debug/.build-id/4e/a0539215b2a9e32602f81c90240874132c1a54.debug...done. [...] (gdb) bt #0 ClrBlank (win=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1129 #1 ClrUpdate () at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1147 #2 doupdate () at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/tty/tty_update.c:1010 #3 0x00007f0a37aa07e6 in wrefresh (win=win@entry=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_refresh.c:65 #4 0x00007f0a37a99499 in recur_wrefresh (win=win@entry=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_getch.c:384 #5 0x00007f0a37a99616 in _nc_wgetch (win=win@entry=0x1993060, result=result@entry=0x7ffd33d93e24, use_meta=1) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_getch.c:491 #6 0x00007f0a37a9a325 in wgetch (win=0x1993060) at /build/ncurses-pKZ1BN/ncurses-6.0+20160213/ncurses/base/lib_getch.c:672 #7 0x00007f0a37cc6ec3 in PyCursesWindow_GetCh.lto_priv.109 (self=0x7f0a3c57b198, args=()) at /build/python2.7-HpIZBG/python2.7-2.7.11/Modules/_cursesmodule.c:853 #8 0x00000000004c4d5a in call_function (oparg=<optimized out>, pp_stack=0x7ffd33d93f30) at ../Python/ceval.c:4350 #9 PyEval_EvalFrameEx () at ../Python/ceval.c:2987 #10 0x00000000004c2e05 in PyEval_EvalCodeEx () at ../Python/ceval.c:3582 #11 0x00000000004def08 in function_call.lto_priv () at ../Objects/funcobject.c:523 #12 0x00000000004b1153 in PyObject_Call () at ../Objects/abstract.c:2546 #13 0x00000000004c73ec in ext_do_call (nk=0, na=<optimized out>, flags=<optimized out>, pp_stack=0x7ffd33d941e8, func=<function at remote 0x7f0a37edcc80>) at ../Python/ceval.c:4662 #14 PyEval_EvalFrameEx () at ../Python/ceval.c:3026 #15 0x00000000004c2e05 in PyEval_EvalCodeEx () at ../Python/ceval.c:3582 #16 0x00000000004caf42 in fast_function (nk=0, na=<optimized out>, n=<optimized out>, pp_stack=0x7ffd33d943f0, func=<function at remote 0x7f0a38039140>) at ../Python/ceval.c:4445 #17 call_function (oparg=<optimized out>, pp_stack=0x7ffd33d943f0) at ../Python/ceval.c:4370 #18 PyEval_EvalFrameEx () at ../Python/ceval.c:2987 #19 0x00000000004c2e05 in PyEval_EvalCodeEx () at ../Python/ceval.c:3582 #20 0x00000000004c2ba9 in PyEval_EvalCode (co=<optimized out>, globals=<optimized out>, locals=<optimized out>) at ../Python/ceval.c:669 #21 0x00000000004f20ef in run_mod.lto_priv () at ../Python/pythonrun.c:1376 #22 0x00000000004eca72 in PyRun_FileExFlags () at ../Python/pythonrun.c:1362 #23 0x00000000004eb1f1 in PyRun_SimpleFileExFlags () at ../Python/pythonrun.c:948 #24 0x000000000049e18a in Py_Main () at ../Modules/main.c:640 #25 0x00007f0a3be10830 in __libc_start_main (main=0x49daf0 <main>, argc=2, argv=0x7ffd33d94838, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffd33d94828) at ../csu/libc-start.c:291 #26 0x000000000049da19 in _start ()
此时,所有的 ?? 都不见了,然而对解决我们的问题并没有什么 X 用……
此外,Python 调试软件包还加强了 GDB 的功能。我们现在可以看看 Python 的调用栈。
1 2 3 4 5 6 7 8
(gdb) py-bt Traceback (most recent call first): File "./cachetop.py", line 188, in handle_loop s = stdscr.getch() File "/usr/lib/python2.7/curses/wrapper.py", line 43, in wrapper return func(stdscr, *args, **kwds) File "./cachetop.py", line 260, in curses.wrapper(handle_loop, args)
以及,我们可以看看 Python 代码是怎样的。
1 2 3 4 5 6 7 8 9 10 11 12
(gdb) py-list 183 b.attach_kprobe(event="mark_buffer_dirty", fn_name="do_count") 184 185 exiting = 0 186 187 while 1: >188 s = stdscr.getch() 189 if s == ord('q'): 190 exiting = 1 191 elif s == ord('r'): 192 sort_reverse = not sort_reverse 193 elif s == ord('<'):
这能指出,在我们的 Python 代码中,究竟是那一行触发了段错误。这看起来非常棒!
之前我们在回溯调用栈时遇到的问题,其原因在于我们看到了 Python 内部在执行的方法(methods),但却看不到对应方法的符号。如果你在调试别的语言,类似的问题取决于它的编译选项和运行环境,以及执行代码是如何结束的。如果你在网上检索「语言名 GDB」,你可能会找到类似 python-dbg 这样的扩展。如果没有的话,坏消息是你必须自己写这样的软件包,但好消息是这样做是可行的。如果你是在调试 Python,那么请在网上检索「add new GDB commands in Pyhon」。
廿四 · 更多……
看起来,我似乎是要写一个完整的 GDB 指南,但显然我不是:GDB 还有很多我没讲到的东西。你可以在 GDB 中使用 help 命令,分门别类查看 GDB 的其他功能。
aliases -- Aliases of other commands breakpoints -- Making program stop at certain points data -- Examining data files -- Specifying and examining files internals -- Maintenance commands obscure -- Obscure features running -- Running the program stack -- Examining the stack status -- Status inquiries support -- Support facilities tracepoints -- Tracing of program execution without stopping the program user-defined -- User-defined commands
Type "help" followed by a class name for a list of commands in that class. Type "help all"for the list of all commands. Type "help" followed by command name for full documentation. Type "apropos word" to search for commands related to "word". Command name abbreviations are allowed if unambiguous.
对于具体某个命令来说,你也可以用 help 命令查看具体用法。例如说,你可以查看所有和 breakpoints 相关的命令。
(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 break-range -- Set a breakpoint for an address range catch -- Set catchpoints to catch events catch assert -- Catch failed Ada assertions catch catch -- Catch an exception catch exception -- Catch Ada exceptions catch exec -- Catch calls to exec catch fork -- Catch calls to fork catch load -- Catch loads of shared libraries catch rethrow -- Catch an exception catch signal -- Catch signals by their names and/or numbers catch syscall -- Catch system calls by their names and/or numbers catch throw -- Catch an exception catch unload -- Catch unloads of shared libraries catch vfork -- Catch calls to vfork clear -- Clear breakpoint at specified location commands -- Set commands to be executed when a breakpoint is hit condition -- Specify breakpoint number N to break only if COND is true delete -- Delete some breakpoints or auto-display expressions delete bookmark -- Delete a bookmark from the bookmark list delete breakpoints -- Delete some breakpoints or auto-display expressions delete checkpoint -- Delete a checkpoint (experimental) delete display -- Cancel some expressions to be displayed when program stops delete mem -- Delete memory region delete tracepoints -- Delete specified tracepoints delete tvariable -- Delete one or more trace state variables disable -- Disable some breakpoints disable breakpoints -- Disable some breakpoints disable display -- Disable some expressions to be displayed when program stops disable frame-filter -- GDB command to disable the specified frame-filter disable mem -- Disable memory region disable pretty-printer -- GDB command to disable the specified pretty-printer disable probes -- Disable probes disable tracepoints -- Disable specified tracepoints disable type-printer -- GDB command to disable the specified type-printer disable unwinder -- GDB command to disable the specified unwinder disable xmethod -- GDB command to disable a specified (group of) xmethod(s) dprintf -- Set a dynamic printf at specified location enable -- Enable some breakpoints enable breakpoints -- Enable some breakpoints enable breakpoints count -- Enable breakpoints for COUNT hits enable breakpoints delete -- Enable breakpoints and delete when hit enable breakpoints once -- Enable breakpoints for one hit enable count -- Enable breakpoints for COUNT hits enable delete -- Enable breakpoints and delete when hit enable display -- Enable some expressions to be displayed when program stops enable frame-filter -- GDB command to disable the specified frame-filter enable mem -- Enable memory region enable once -- Enable breakpoints for one hit enable pretty-printer -- GDB command to enable the specified pretty-printer enable probes -- Enable probes enable tracepoints -- Enable specified tracepoints enable type-printer -- GDB command to enable the specified type printer enable unwinder -- GDB command to enable unwinders enable xmethod -- GDB command to enable a specified (group of) xmethod(s) ftrace -- Set a fast tracepoint at specified location hbreak -- Set a hardware assisted breakpoint ignore -- Set ignore-count of breakpoint number N to COUNT rbreak -- Set a breakpoint for all functions matching REGEXP rwatch -- Set a read watchpoint for an expression save -- Save breakpoint definitions as a script save breakpoints -- Save current breakpoint definitions as a script save gdb-index -- Save a gdb-index file save tracepoints -- Save current tracepoint definitions as a script skip -- Ignore a functionwhile stepping skip delete -- Delete skip entries skip disable -- Disable skip entries skip enable -- Enable skip entries skip file -- Ignore a file while stepping skip function -- Ignore a functionwhile stepping strace -- Set a static tracepoint at location or marker tbreak -- Set a temporary breakpoint tcatch -- Set temporary catchpoints to catch events tcatch assert -- Catch failed Ada assertions tcatch catch -- Catch an exception tcatch exception -- Catch Ada exceptions tcatch exec -- Catch calls to exec tcatch fork -- Catch calls to fork tcatch load -- Catch loads of shared libraries tcatch rethrow -- Catch an exception tcatch signal -- Catch signals by their names and/or numbers tcatch syscall -- Catch system calls by their names and/or numbers tcatch throw -- Catch an exception tcatch unload -- Catch unloads of shared libraries tcatch vfork -- Catch calls to vfork thbreak -- Set a temporary hardware assisted breakpoint trace -- Set a tracepoint at specified location watch -- Set a watchpoint for an expression
Type "help" followed by command name for full documentation. Type "apropos word" to search for commands related to "word". Command name abbreviations are allowed if unambiguous.