可能出于下列原因之一调试程序:
为了确定程序在何处以及为何导致崩溃。确定崩溃原因的方法包括:
为了确定程序为何给出错误结果。其方法包括:
为了查找内存泄漏或内存管理问题。执行运行时检查可以检测运行时错误(如,内存访问错误和内存泄漏错误),以及监视内存使用(请参见查找内存访问问题和内存泄漏)。
要确定程序发生崩溃的位置,可能需要检查核心转储文件,即程序崩溃时的程序内存映像。可使用 where 命令(请参见where 命令)确定程序在转储核心时的执行位置。
注 - dbx 无法像对待本机代码那样通过核心转储文件来指明 Java 应用程序的状态。
$ dbx program_name core
或
$ dbx - core
在下面的示例中,程序因段故障和转储核心而崩溃。用户启动 dbx 并装入核心转储文件。然后使用 where 命令显示栈跟踪,其中显示在 foo.c 文件的第 9 行发生崩溃。
% dbx a.out core Reading a.out core file header read successfully Reading ld.so.1 Reading libc.so.1 Reading libdl.so.1 Reading libc_psr.so.1 program terminated by signal SEGV (no mapping at the fault address) Current function is main 9 printf("string ’%s’ is %d characters long\n", msg, strlen(msg)); (dbx) where [1] strlen(0x0, 0x0, 0xff337d24, 0x7efefeff, 0x81010100, 0xff0000), at 0xff2b6dec =>[2] main(argc = 1, argv = 0xffbef39c), line 9 in "foo.c" (dbx)
有关调试核心转储文件的更多信息,请参见调试核心转储文件。有关使用调用栈的更多信息,请参见查看调用栈。
断点是程序中要暂时停止程序的执行并让 dbx 进行控制的位置。在程序内怀疑存在错误之处设置断点。如果程序崩溃,请确定崩溃的发生位置,然后在这部分代码前设置断点。
程序在断点处停止时,便可以检查程序的状态和变量值。使用 dbx 可以设置多种类型的断点(请参见使用 Ctrl+C 停止进程)。
最简单的断点类型就是停止断点。可以设置用于在函数或过程中停止的停止断点。例如,要在调用 main 函数时停止:
(dbx) stop in main (2) stop in main
有关 stop in 命令的更多信息,请参见在函数中设置 stop 断点和stop 命令。
也可以设置用于在源代码的特定行处停止的停止断点。例如,要在源文件 t.c 中的第 13 行处停止:
(dbx) stop at t.c:13 (3) stop at “t.c”:13
有关 stop at 命令的更多信息,请参见在源代码行设置 stop 断点和stop 命令。
可以使用 file 命令设置当前文件并使用 list 命令列出要在其中停止的函数来确定要停止在那里的行。然后使用 stop at 命令在源代码行设置断点:
(dbx) file t.c (dbx) list main 10 main(int argc, char *argv[]) 11 { 12 char *msg = "hello world\n"; 13 printit(msg); 14 } (dbx) stop at 13 (4) stop at “t.c”:13
要使程序在断点处停止后继续执行,请使用 cont 命令(请参见继续执行程序和cont 命令)。
要获取所有当前断点的列表,请使用 status 命令:
(dbx) status (2) stop in main (3) stop at "t.c":13
现在如果运行程序,程序将在第一个断点处停止:
(dbx) run ... stopped in main at line 12 in file "t.c" 12 char *msg = "hello world\n";
程序在断点处停止后,可能希望按一次执行一个源代码行的方式执行程序,在此时比较程序的实际状态与预期状态。可以使用 step 和 next 命令来执行此操作。这两个命令都是执行程序的一个源代码行,当执行完相应行时即停止。但在处理包含函数调用的源代码行时有所差别:step 命令步入函数,而 next 命令步过函数。
step up 命令会一直执行,直至当前函数将控制权返回给调用它的函数为止。
step to 命令会尝试步入当前源代码行中的指定函数;如果未指定任何函数,则尝试步入由当前源代码行的汇编代码确定调用的最后一个函数。
某些函数(特别是 printf 之类的库函数)可能未使用 -g 选项编译,因此 dbx 无法步入这些函数。在这种情况下,step 和 next 执行功能相似。
以下示例说明如何使用 step 和 next 命令以及在设置断点中设置的断点。
(dbx) stop at 13 (3) stop at "t.c":13 (dbx) run Running: a.out stopped in main at line 13 in file "t.c" 13 printit(msg); (dbx) next Hello world stopped in main at line 14 in file "t.c" 14 } (dbx) run Running: a.out stopped in main at line 13 in file "t.c" 13 printit(msg); (dbx) step stopped in printit at line 6 in file "t.c" 6 printf("%s\n", msg); (dbx) step up Hello world printit returns stopped in main at line 13 in file "t.c" 13 printit(msg); (dbx)
有关单步执行程序的更多信息,请参见单步执行程序。有关 step 和 next 命令的更多信息,请参见step 命令和next 命令。
调用栈表示所有当前处于活动状态的例程,即那些已被调用但尚未返回至各自调用方的例程。在该栈中,函数及其参数按其调用顺序存放。栈跟踪显示程序流中执行停止位置及执行到达此点的过程。它提供了有关程序状态的最简明的描述。
要显示栈跟踪,请使用 where 命令:
(dbx) stop in printf (dbx) run (dbx) where [1] printf(0x10938, 0x20a84, 0x0, 0x0, 0x0, 0x0), at 0xef763418 =>[2] printit(msg = 0x20a84 "hello world\n"), line 6 in "t.c" [3] main(argc = 1, argv = 0xefffe93c), line 13 in "t.c" (dbx)
对于使用 -g 选项编译的函数,参数名及其类型是已知的,因此会显示精确的值。对于无调试信息的函数,显示的参数值是十六进制数。这些数字未必都有意义。例如,在上述栈跟踪中,帧 1 所示为 SPARC 输入寄存器 $i0 至 $i5 的内容,但仅寄存器 $i0 至 $i1 的内容有意义,因为只有两个参数传递到单步执行程序所示的示例中的 printf。
可以在未使用 -g 选项编译的函数中停止。在此类函数中停止时,dbx 在栈内向下搜索其函数是使用 -g 选项编译的第一帧(本例中为 printit()),并为其设置当前作用域(请参见程序作用域)。这用箭头符号 (=>) 表示。
有关调用栈的更多信息,请参见效率方面的考虑。
虽然栈跟踪可能包含足够的信息,可以完全表明程序的状态,但仍可能需要查看更多变量的值。print 命令可以求表达式的值,并根据表达式的类型输出值。以下示例中例举了几个简单的 C 表达式:
(dbx) print msg msg = 0x20a84 "Hello world" (dbx) print msg[0] msg[0] = ’h’ (dbx) print *msg *msg = ’h’ (dbx) print &msg &msg = 0xefffe8b4
可以使用数据更改断点跟踪变量和表达式的值何时发生变化(请参见设置数据更改断点)。例如,要在变量计数值更改时停止执行,请键入:
(dbx) stop change count
运行时检查由两部分组成: 内存访问检查及内存使用和泄露检查。访问检查将检查被调试应用程序是否不当使用了内存。内存使用和泄露检查包括跟踪所有仍存在的堆空间,然后在需要时或程序终止时,扫描可用数据空间以及识别无引用的空间。
可以使用 check 命令启用内存访问检查及内存使用和泄露检查。要仅启用内存访问检查,请键入:
(dbx) check -access
(dbx) check -memuse
启用所需的运行时检查类型后,运行程序。程序正常运行,但速度很慢,因为每次进行内存访问前都要检查其有效性。如果 dbx 检测到无效访问,便会显示错误的类型和位置。此时,可以使用 dbx 命令(如 where 命令)获取当前栈跟踪,也可以使用 print 命令检查变量。
注 - 不能对使用 Java 代码和 C JNI 代码或 C++ JNI 代码混编的应用程序使用运行时检查。
有关使用运行时检查的详细信息,请参见第 9 章。