gdb: Agent Expressions
Appendix F The GDB Agent Expression Mechanism
*********************************************
In some applications, it is not feasible for the debugger to interrupt
the program's execution long enough for the developer to learn anything
helpful about its behavior. If the program's correctness depends on its
real-time behavior, delays introduced by a debugger might cause the
program to fail, even when the code itself is correct. It is useful to
be able to observe the program's behavior without interrupting it.
Using GDB's 'trace' and 'collect' commands, the user can specify
locations in the program, and arbitrary expressions to evaluate when
those locations are reached. Later, using the 'tfind' command, she can
examine the values those expressions had when the program hit the trace
points. The expressions may also denote objects in memory -- structures
or arrays, for example -- whose values GDB should record; while visiting
a particular tracepoint, the user may inspect those objects as if they
were in memory at that moment. However, because GDB records these
values without interacting with the user, it can do so quickly and
unobtrusively, hopefully not disturbing the program's behavior.
When GDB is debugging a remote target, the GDB "agent" code running
on the target computes the values of the expressions itself. To avoid
having a full symbolic expression evaluator on the agent, GDB translates
expressions in the source language into a simpler bytecode language, and
then sends the bytecode to the agent; the agent then executes the
bytecode, and records the values for GDB to retrieve later.
The bytecode language is simple; there are forty-odd opcodes, the
bulk of which are the usual vocabulary of C operands (addition,
subtraction, shifts, and so on) and various sizes of literals and memory
reference operations. The bytecode interpreter operates strictly on
machine-level values -- various sizes of integers and floating point
numbers -- and requires no information about types or symbols; thus, the
interpreter's internal data structures are simple, and each bytecode
requires only a few native machine instructions to implement it. The
interpreter is small, and strict limits on the memory and time required
to evaluate an expression are easy to determine, making it suitable for
use by the debugging agent in real-time applications.
Menu