stop 命令、stopi 命令、when 命令、wheni 命令、trace 命令以及 tracei 命令使用事件规范来指示事件类型和参数。格式由表示事件类型的关键字和可选参数构成。通常,对于这三个命令而言,事件规范的含义相同;例外情况在命令说明中进行了介绍(请参见stop 命令、trace 命令和when 命令)。
断点是操作的发生位置,程序在该位置停止执行。下面是断点事件的事件规范。
已进入函数,并且即将执行第一行。序进程后的第一个可执行代码用作实际断点位置。它可能是要初始化的局部变量所在的那一行。如果是 C++ 构造函数,在执行了所有基类构造函数后,将停止执行。如果使用 -instr 修饰符(请参见-instr),则它是即将执行的函数的第一个指令。function 规范可以接受形式参数签名,以支持重载的函数名或模板实例规范。例如:
stop in mumble(int, float, struct Node *) |
不要将 in function 与 -in function 修饰符混淆。
指定行即将被执行。如果指定 filename,则即将执行指定文件中的指定行。文件名可以是源文件名或目标文件名。尽管不要求使用引号,但文件名中包含特殊字符时需要使用。如果指定行在模板代码中,则会在该模板的所有实例上放置断点。
给定地址处的指令即将被执行。此事件只能与 stopi 命令(请参见stopi 命令)或 -instr 事件修饰符(请参见-instr)结合使用。
对于所有名为 function 的重载函数或其所有模板实例化,等效于 in function 。
对于每个类,等效于 in function 或名为 function 的成员函数。
对于所有是 classname 的成员但不是 classname 的任何基类的成员函数,等效于 in function。-norecurse 是缺省值。如果指定 -recurse,则包括基类。
调用了对由 object-expression 表示的地址处的特定对象调用的成员函数。stop inobject ox 大致等效于以下命令,但与 inclass 不同,此处,动态类型的 ox 的基类包括在内。缺省值是 -recurse。如果指定 -norecurse,则不包括基类。
stop inclass dynamic_type(ox) -if this==ox |
以下是涉及访问或更改内存地址内容的事件的事件规范。
访问了由 address-expression 指定的内存。
mode 指定内存访问模式。可由以下一个或所有字母组成:
已读取指定地址处的内存。
已写入内存。
已执行内存。
mode 还可以包含以下任一项:
访问后停止进程(缺省值)。
访问前停止进程。
在这两种情况下,程序计数器都将指向违例指令。“之前”和“之后”都具有副作用。
address-expression 是求值结果为地址的任何表达式。如果提供符号表达式,则会自动推导出要监视的区域大小;可以通过指定 byte-size-expression 将其覆盖。也可以使用非符号、无类型地址表达式,在这种情况下,必须提供大小。例如:
stop access w 0x5678, sizeof(Complex) |
access 命令有一个限制,即任何两个匹配区都不能重叠。
access 事件规范取代了 modify 事件规范
variable 的值已更改。change 事件大致等效于:
when step { if [ $last_value !=$[variable]] then stop else last_value=$[variable] } |
此事件使用单步执行来执行。要提高速度,可使用 access 事件(请参见access mode address-expression [, byte-size-expression ])。
即使未检测到更改,第一次检查 variable 时也会触发一个事件。这第一个事件是访问 variable 的初始值。以后检测到 variable 值的更改时会触发其他事件。
由 condition-expression 表示的条件的求值结果为 true。可以为 condition-expression 指定任何表达式,但其求值结果必须为整型。cond 事件大致等效于:
stop step -if conditional_expression
成功执行 dlopen()() 或 dlclose()() 调用后会发生这些事件。执行 dlopen()() 或 dlclose()() 调用可能会导致装入多个库。预定义变量 $dllist 中总是有这些库的列表。$dllist 中的第一个 shell 字为 "+" 或 "-",表示是要添加还是要删除库列表。
lib-path 是共享库的名称。如果指定该名称,则只在装入或卸载了给定库时才会发生事件。在这种情况下,$dlobj 包含库的名称。$dllist 仍然可用。
如果 lib-path 以 / 开头,则将执行完整字符串匹配。否则,将只比较路径的尾部。
如果未指定 lib-path,则只要出现 dl 活动,都会发生事件。在这种情况下,$dlobj 为空,但 $dllist 有效。
当出现指定的错误时,就会发生 fault 事件。这些错误为体系结构相关式错误。以下这组 dbx 已知的错误在 proc(4) 手册页中进行了定义。
错误 |
说明 |
---|---|
FLTILL |
非法指令 |
FLTPRIV |
特权指令 |
FLTBPT* |
断点陷阱 |
FLTTRACE* |
跟踪陷阱(单步) |
FLTACCESS |
内存访问(如对齐) |
FLTBOUNDS |
内存边界(无效地址) |
FLTIOVF |
整数溢出 |
FLTIZDIV |
整数除以零 |
FLTPE |
浮点异常 |
FLTSTACK |
无法恢复的栈错误 |
FLTPAGE |
可恢复的页错误 |
FLTWATCH* |
监视点陷阱 |
FLTCPCOVF |
CPU 性能计数器溢出 |
dbx 使用 BPT、TRACE 和 BOUNDS 来实现断点和单步执行。处理它们时可能会干扰 dbx 的运行情况。
FLTBPT 和 FLTTRACE 会被忽略,因为它们会干扰诸如断点和单步执行等 dbx 基本功能(请参见事件安全)。
上述错误摘自 /sys/fault.h。fault 可以是上面所列错误中的任何一种(大小写、有无 FLT 前缀均可),也可以是实际的数字代码。
在 Linux 平台上不能使用 fault 事件。
退出了 lwp 时,会发生 lwp_exit 事件。$lwp 包含事件处理程序执行期间退出的 LWP(lightweight process,轻量级进程)的 ID。
在 Linux 平台上不能使用 lwpexit 事件。
信号首次传送给所调试的程序时,会发生 sig signal 事件。signal 可以是十进制数或信号名(大小写均可),前缀是可选的。它与 catch 命令和 ignore 命令毫无关系,尽管 catch 命令可按如下方式实现:
function simple_catch { when sig $1 { stop; echo Stopped due to $sigstr $sig whereami } } |
收到 sig 事件时,进程尚未检测到它。只有在使用指定的信号继续执行进程时,信号才会传送给它。
首次将具有指定 sub-code 的指定信号传送到子进程时,会发生 sig signal sub-code 事件。与信号相同,可以按十进制数形式或大小写字母形式键入 sub-code,前缀是可选的。
刚启动了指定的系统调用,且进程已进入内核模式。
dbx 支持的系统调用概念是由陷阱按 /usr/include/sys/syscall.h 中的枚举提供内核系统调用。
这与系统调用的 ABI 概念不同。一些 ABI 系统调用在用户模式下得到部分实现,并且使用非 ABI 内核陷阱。但是,对于大多数普通系统调用(主要异常是信号处理),syscall.h 和 ABI 之间没有区别。
在 Linux 平台上不能使用 sysin 事件。
/usr/include/sys/syscall.h 中的一组内核系统调用陷阱属于 Solaris OS 中随发行版本而异的一个专用接口。dbx 接受的陷阱名(代码)和陷阱编号列表包括 dbx 支持的任何 Solaris OS 版本支持的所有陷阱名(代码)和陷阱编号。dbx 支持的名称不太可能与任何 Solaris OS 特定发行版本支持的名称完全一致,而且 syscall.h 中的某些名称可能不可用。任何陷阱编号(代码)均可为 dbx 接受,并可正常使用,但是,如果它与已知的系统调用陷阱不对应,系统会发出警告。
已完成指定的系统调用,进程即将返回到用户模式。
在 Linux 平台上不能使用 sysout 事件。
如果不使用参数,所有系统调用都会被跟踪。某些 dbx 功能(例如 modify 事件和运行时检查)会导致子进程为其自身目的执行系统调用,并且在被跟踪时显示出来。
以下是与执行进度有关的事件的事件规范。
next 事件与 step 事件类似,不同之处在于并不步入函数。
returns 事件是当前访问的函数的返回点处的断点。使用访问的函数是为了可以在提供大量 step up 命令后使用 returns 事件规范。returns 事件始终为 -temp,并且只有当存在活动进程时才能创建该事件。
每当给定的函数返回到其调用点时,都会执行 returnsfunction 事件。这不是临时事件。执行此操作时,并不提供返回值,但可以访问以下寄存器查找整型返回值:
$o0
$eax
$rax、$rdx
该事件大致等效于:
when in func { stop returns; } |
执行源代码的第一个指令时,会发生 step 事件。例如,可以使用以下语句获得简单跟踪:
when step { echo $lineno: $line; }; cont |
启用了 step 事件后,即指示 dbx 在下次使用 cont 命令时自动单步执行。
step 命令终止时,不会发生 step(和 next)事件。step 命令是按照 step 事件实现的,实现方式大致如下:alias step="when step -temp { whereami; stop; }; cont"
dbx 已成功连接到进程。
dbx 已成功与所调试的程序分离。
所调试的进程即将过期,原因如下:
已调用 _exit(2) 系统调用。(在执行显式调用或 main() 返回时,会发生此情况。)
即将传送终止信号。
进程正由 kill 命令中止。
触发此事件时,通常(但并非总是)会有进程的最终状态,从而提供了检查进程状态的最后机会。在此事件后恢复执行会终止进程。
在 Linux 平台上不能使用 lastrites 事件。
dbx 不再与调试的进程关联时,会发生 proc_gone 事件。预定义变量 $reason 可以是 signal、exit、kill 或 detach。
由于执行 follow exec 而装入了新程序时,会发生 prog_new 事件。
此事件的处理程序始终永久性存在。
进程已停止。每当进程停止以便用户收到提示(尤其是为了响应 stop 处理程序)时,都会发生 stop 事件。例如,以下命令是等效的:
display x when stop {print x;} |
刚使用 exec() 执行了所调试的进程。在 a.out 中指定的所有内存均有效且存在,但预装入的共享库尚未装入。例如,尽管 printf 可供 dbx 使用,但尚未映射到内存中。
对此事件执行 stop 不起作用,但可以将 sync 事件与 when 命令一起使用。
在 Linux 平台上不能使用 sync 事件。
在执行 sync(或 attach,如果所调试的进程尚未处理共享库)后,会发生 syncrtld 事件。它在动态链接程序启动代码已经执行且所有预装入共享库的符号表都已装入之后、.init 段中的任何代码运行之前执行。
针对此事件执行 stop 不起作用,但可以将 syncrtld 事件与 when 命令一起使用。
创建了线程或具有指定 thread_id 的线程后,会发生 thr_create 事件。例如,在以下 stop 命令中,线程 ID t@1 是指执行创建线程,而线程 ID t@5 是指被创建线程。
stop thr_create t@5 -thread t@1 |
线程退出后,会发生 thr_exit 事件。要捕获特定线程的退出,请使用 stop 命令的 -thread 选项,如下所示:
stop thr_exit -thread t@5 |
每当应用程序抛出任何不是未处理的异常或意外的异常时,都会发生 throw 事件。
在 Linux 平台上不能使用 throw 事件。
如果为 throw 事件指定了异常 type,则只有该类型的异常会导致发生 throw 事件。
-unhandled 是一种特殊的异常类型,表示会抛出但没有相应处理程序的异常。
-unexpected 是一种特殊的异常类型,表示该异常不符合抛出它的函数的异常规范。
所调试的程序运行了 seconds 时,会发生 timer 事件。 用于此事件的计时器与 collector 命令共享。精度为毫秒,因此,seconds 可以为浮点值(例如 0.001)。