[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GDB uses a number of debugging-specific algorithms. They are often not very complicated, but get lost in the thicket of special cases and real-world issues. This chapter describes the basic algorithms and mentions some of the specific target definitions that they use.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A frame is a construct that GDB uses to keep track of calling and called functions.
GDB's frame model, a fresh design, was implemented with the need to support DWARF's Call Frame Information in mind. In fact, the term "unwind" is taken directly from that specification. Developers wishing to learn more about unwinders, are encouraged to read the DWARF specification.
GDB's model is that you find a frame's registers by
"unwinding" them from the next younger frame. That is,
`get_frame_register' which returns the value of a register in
frame #1 (the next-to-youngest frame), is implemented by calling frame
#0's frame_register_unwind
(the youngest frame). But then the
obvious question is: how do you access the registers of the youngest
frame itself?
To answer this question, GDB has the sentinel frame, the
"-1st" frame. Unwinding registers from the sentinel frame gives you
the current values of the youngest real frame's registers. If f
is a sentinel frame, then get_frame_type (f) ==
SENTINEL_FRAME
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To produce a backtrace and allow the user to manipulate older frames' variables and arguments, GDB needs to find the base addresses of older frames, and discover where those frames' registers have been saved. Since a frame's "callee-saves" registers get saved by younger frames if and when they're reused, a frame's registers may be scattered unpredictably across younger frames. This means that changing the value of a register-allocated variable in an older frame may actually entail writing to a save slot in some younger frame.
Modern versions of GCC emit Dwarf call frame information ("CFI"), which describes how to find frame base addresses and saved registers. But CFI is not always available, so as a fallback GDB uses a technique called prologue analysis to find frame sizes and saved registers. A prologue analyzer disassembles the function's machine code starting from its entry point, and looks for instructions that allocate frame space, save the stack pointer in a frame pointer register, save registers, and so on. Obviously, this can't be done accurately in general, but it's tractable to do well enough to be very helpful. Prologue analysis predates the GNU toolchain's support for CFI; at one time, prologue analysis was the only mechanism GDB used for stack unwinding at all, when the function calling conventions didn't specify a fixed frame layout.
In the olden days, function prologues were generated by hand-written, target-specific code in GCC, and treated as opaque and untouchable by optimizers. Looking at this code, it was usually straightforward to write a prologue analyzer for GDB that would accurately understand all the prologues GCC would generate. However, over time GCC became more aggressive about instruction scheduling, and began to understand more about the semantics of the prologue instructions themselves; in response, GDB's analyzers became more complex and fragile. Keeping the prologue analyzers working as GCC (and the instruction sets themselves) evolved became a substantial task.
To try to address this problem, the code in `prologue-value.h' and `prologue-value.c' provides a general framework for writing prologue analyzers that are simpler and more robust than ad-hoc analyzers. When we analyze a prologue using the prologue-value framework, we're really doing "abstract interpretation" or "pseudo-evaluation": running the function's code in simulation, but using conservative approximations of the values registers and memory would hold when the code actually runs. For example, if our function starts with the instruction:
addi r1, 42 # add 42 to r1 |
r1
after executing
this instruction, but we do know it'll be 42 greater than its original
value.
If we then see an instruction like:
addi r1, 22 # add 22 to r1 |
r1's
value is, but again, we can say
it is now 64 greater than its original value.
If the next instruction were:
mov r2, r1 # set r2 to r1's value |
r2's
value is now the original value of
r1
plus 64.
It's common for prologues to save registers on the stack, so we'll need to track the values of stack frame slots, as well as the registers. So after an instruction like this:
mov (fp+4), r2 |
r1
plus 64.
And so on.
Of course, this can only go so far before it gets unreasonable. If we
wanted to be able to say anything about the value of r1
after
the instruction:
xor r1, r3 # exclusive-or r1 and r3, place result in r1 |
r1
's value is now
"unknown". We can ignore things that are too complex, if that loss of
information is acceptable for our application.
So when we say "conservative approximation" here, what we mean is an approximation that is either accurate, or marked "unknown", but never inaccurate.
Using this framework, a prologue analyzer is simply an interpreter for machine code, but one that uses conservative approximations for the contents of registers and memory instead of actual values. Starting from the function's entry point, you simulate instructions up to the current PC, or an instruction that you don't know how to simulate. Now you can examine the state of the registers and stack slots you've kept track of.
This does take some work. But prologue analyzers aren't quick-and-simple pattern patching to recognize a few fixed prologue forms any more; they're big, hairy functions. Along with inferior function calls, prologue analysis accounts for a substantial portion of the time needed to stabilize a GDB port. So it's worthwhile to look for an approach that will be easier to understand and maintain. In the approach described above:
The file `prologue-value.h' contains detailed comments explaining the framework and how to use it.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In general, a breakpoint is a user-designated location in the program where the user wants to regain control if program execution ever reaches that location.
There are two main ways to implement breakpoints; either as "hardware" breakpoints or as "software" breakpoints.
Hardware breakpoints are sometimes available as a builtin debugging features with some chips. Typically these work by having dedicated register into which the breakpoint address may be stored. If the PC (shorthand for program counter) ever matches a value in a breakpoint registers, the CPU raises an exception and reports it to GDB.
Another possibility is when an emulator is in use; many emulators include circuitry that watches the address lines coming out from the processor, and force it to stop if the address matches a breakpoint's address.
A third possibility is that the target already has the ability to do breakpoints somehow; for instance, a ROM monitor may do its own software breakpoints. So although these are not literally "hardware breakpoints", from GDB's point of view they work the same; GDB need not do anything more than set the breakpoint and wait for something to happen.
Since they depend on hardware resources, hardware breakpoints may be limited in number; when the user asks for more, GDB will start trying to set software breakpoints. (On some architectures, notably the 32-bit x86 platforms, GDB cannot always know whether there's enough hardware resources to insert all the hardware breakpoints and watchpoints. On those platforms, GDB prints an error message only when the program being debugged is continued.)
Software breakpoints require GDB to do somewhat more work. The basic theory is that GDB will replace a program instruction with a trap, illegal divide, or some other instruction that will cause an exception, and then when it's encountered, GDB will take the exception and stop the program. When the user says to continue, GDB will restore the original instruction, single-step, re-insert the trap, and continue on.
Since it literally overwrites the program being tested, the program area must be writable, so this technique won't work on programs in ROM. It can also distort the behavior of programs that examine themselves, although such a situation would be highly unusual.
Also, the software breakpoint instruction should be the smallest size of instruction, so it doesn't overwrite an instruction that might be a jump target, and cause disaster when the program jumps into the middle of the breakpoint instruction. (Strictly speaking, the breakpoint must be no larger than the smallest interval between instructions that may be jump targets; perhaps there is an architecture where only even-numbered instructions may jumped to.) Note that it's possible for an instruction set not to have any instructions usable for a software breakpoint, although in practice only the ARC has failed to define such an instruction.
The basic definition of the software breakpoint is the macro
BREAKPOINT
.
Basic breakpoint object handling is in `breakpoint.c'. However, much of the interesting breakpoint action is in `infrun.c'.
target_remove_breakpoint (bp_tgt)
target_insert_breakpoint (bp_tgt)
bp_tgt->placed_address
. Returns zero for success,
non-zero for failure. On input, bp_tgt contains the address of the
breakpoint, and is otherwise initialized to zero. The fields of the
struct bp_target_info
pointed to by bp_tgt are updated
to contain other information about the breakpoint on output. The field
placed_address
may be updated if the breakpoint was placed at a
related address; the field shadow_contents
contains the real
contents of the bytes where the breakpoint has been inserted,
if reading memory would return the breakpoint instead of the
underlying memory; the field shadow_len
is the length of
memory cached in shadow_contents
, if any; and the field
placed_size
is optionally set and used by the target, if
it could differ from shadow_len
.
For example, the remote target `Z0' packet does not require
shadowing memory, so shadow_len
is left at zero. However,
the length reported by BREAKPOINT_FROM_PC
is cached in
placed_size
, so that a matching `z0' packet can be
used to remove the breakpoint.
target_remove_hw_breakpoint (bp_tgt)
target_insert_hw_breakpoint (bp_tgt)
bp_tgt->placed_address
. Returns zero for success,
non-zero for failure. See target_insert_breakpoint
for
a description of the struct bp_target_info
pointed to by
bp_tgt; the shadow_contents
and
shadow_len
members are not used for hardware breakpoints,
but placed_size
may be.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GDB has support for figuring out that the target is doing a
longjmp
and for stopping at the target of the jump, if we are
stepping. This is done with a few specialized internal breakpoints,
which are visible in the output of the `maint info breakpoint'
command.
To make this work, you need to define a macro called
GET_LONGJMP_TARGET
, which will examine the jmp_buf
structure and extract the longjmp target address. Since jmp_buf
is target specific, you will need to define it in the appropriate
`tm-target.h' file. Look in `tm-sun4os4.h' and
`sparc-tdep.c' for examples of how to do this.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Watchpoints are a special kind of breakpoints (see section breakpoints) which break when data is accessed rather than when some instruction is executed. When you have data which changes without your knowing what code does that, watchpoints are the silver bullet to hunt down and kill such bugs.
Watchpoints can be either hardware-assisted or not; the latter type is known as "software watchpoints." GDB always uses hardware-assisted watchpoints if they are available, and falls back on software watchpoints otherwise. Typical situations where GDB will use software watchpoints are:
Software watchpoints are very slow, since GDB needs to single-step the program being debugged and test the value of the watched expression(s) after each instruction. The rest of this section is mostly irrelevant for software watchpoints.
When the inferior stops, GDB tries to establish, among other
possible reasons, whether it stopped due to a watchpoint being hit.
For a data-write watchpoint, it does so by evaluating, for each
watchpoint, the expression whose value is being watched, and testing
whether the watched value has changed. For data-read and data-access
watchpoints, GDB needs the target to supply a primitive that
returns the address of the data that was accessed or read (see the
description of target_stopped_data_address
below): if this
primitive returns a valid address, GDB infers that a
watchpoint triggered if it watches an expression whose evaluation uses
that address.
GDB uses several macros and primitives to support hardware watchpoints:
TARGET_HAS_HARDWARE_WATCHPOINTS
TARGET_CAN_USE_HARDWARE_WATCHPOINT (type, count, other)
TARGET_REGION_OK_FOR_HW_WATCHPOINT (addr, len)
target_insert_watchpoint (addr, len, type)
target_remove_watchpoint (addr, len, type)
target_hw_bp_type
,
defined by `breakpoint.h' as follows:
enum target_hw_bp_type { hw_write = 0, /* Common (write) HW watchpoint */ hw_read = 1, /* Read HW watchpoint */ hw_access = 2, /* Access (read or write) HW watchpoint */ hw_execute = 3 /* Execute HW breakpoint */ }; |
These two macros should return 0 for success, non-zero for failure.
target_stopped_data_address (addr_p)
HAVE_STEPPABLE_WATCHPOINT
HAVE_NONSTEPPABLE_WATCHPOINT
HAVE_CONTINUABLE_WATCHPOINT
CANNOT_STEP_HW_WATCHPOINTS
STOPPED_BY_WATCHPOINT (wait_status)
struct target_waitstatus
, defined by `target.h'.
Normally, this macro is defined to invoke the function pointed to by
the to_stopped_by_watchpoint
member of the structure (of the
type target_ops
, defined on `target.h') that describes the
target-specific operations; to_stopped_by_watchpoint
ignores
the wait_status argument.
GDB does not require the non-zero value returned by
STOPPED_BY_WATCHPOINT
to be 100% correct, so if a target cannot
determine for sure whether the inferior stopped due to a watchpoint,
it could return non-zero "just in case".
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The 32-bit Intel x86 (a.k.a. ia32) processors feature special debug registers designed to facilitate debugging. GDB provides a generic library of functions that x86-based ports can use to implement support for watchpoints and hardware-assisted breakpoints. This subsection documents the x86 watchpoint facilities in GDB.
To use the generic x86 watchpoint support, a port should do the following:
I386_USE_GENERIC_WATCHPOINTS
somewhere in the
target-dependent headers.
I386_USE_GENERIC_WATCHPOINTS
.
NATDEPFILES
(see section NATDEPFILES) or
TDEPFILES
(see section TDEPFILES).
I386_DR_LOW_*
macros described
below. Typically, each macro should call a target-specific function
which does the real work.
The x86 watchpoint support works by maintaining mirror images of the debug registers. Values are copied between the mirror images and the real debug registers via a set of macros which each target needs to provide:
I386_DR_LOW_SET_CONTROL (val)
I386_DR_LOW_SET_ADDR (idx, addr)
I386_DR_LOW_RESET_ADDR (idx)
I386_DR_LOW_GET_STATUS
I386_DR_LOW_GET_STATUS
, so as to support per-thread status
register values.
For each one of the 4 debug registers (whose indices are from 0 to 3) that store addresses, a reference count is maintained by GDB, to allow sharing of debug registers by several watchpoints. This allows users to define several watchpoints that watch the same expression, but with different conditions and/or commands, without wasting debug registers which are in short supply. GDB maintains the reference counts internally, targets don't have to do anything to use this feature.
The x86 debug registers can each watch a region that is 1, 2, or 4 bytes long. The ia32 architecture requires that each watched region be appropriately aligned: 2-byte region on 2-byte boundary, 4-byte region on 4-byte boundary. However, the x86 watchpoint support in GDB can watch unaligned regions and regions larger than 4 bytes (up to 16 bytes) by allocating several debug registers to watch a single region. This allocation of several registers per a watched region is also done automatically without target code intervention.
The generic x86 watchpoint support provides the following API for the GDB's application code:
i386_region_ok_for_watchpoint (addr, len)
TARGET_REGION_OK_FOR_HW_WATCHPOINT
is set to call
this function. It counts the number of debug registers required to
watch a given region, and returns a non-zero value if that number is
less than 4, the number of debug registers available to x86
processors.
i386_stopped_data_address (addr_p)
target_stopped_data_address
is set to call this function.
This
function examines the breakpoint condition bits in the DR6 Debug
Status register, as returned by the I386_DR_LOW_GET_STATUS
macro, and returns the address associated with the first bit that is
set in DR6.
i386_stopped_by_watchpoint (void)
STOPPED_BY_WATCHPOINT
is set to call this function. The
argument passed to STOPPED_BY_WATCHPOINT
is ignored. This
function examines the breakpoint condition bits in the DR6 Debug
Status register, as returned by the I386_DR_LOW_GET_STATUS
macro, and returns true if any bit is set. Otherwise, false is
returned.
i386_insert_watchpoint (addr, len, type)
i386_remove_watchpoint (addr, len, type)
target_insert_watchpoint
and target_remove_watchpoint
are set to call these functions. i386_insert_watchpoint
first
looks for a debug register which is already set to watch the same
region for the same access types; if found, it just increments the
reference count of that debug register, thus implementing debug
register sharing between watchpoints. If no such register is found,
the function looks for a vacant debug register, sets its mirrored
value to addr, sets the mirrored value of DR7 Debug Control
register as appropriate for the len and type parameters,
and then passes the new values of the debug register and DR7 to the
inferior by calling I386_DR_LOW_SET_ADDR
and
I386_DR_LOW_SET_CONTROL
. If more than one debug register is
required to cover the given region, the above process is repeated for
each debug register.
i386_remove_watchpoint
does the opposite: it resets the address
in the mirrored value of the debug register and its read/write and
length bits in the mirrored value of DR7, then passes these new
values to the inferior via I386_DR_LOW_RESET_ADDR
and
I386_DR_LOW_SET_CONTROL
. If a register is shared by several
watchpoints, each time a i386_remove_watchpoint
is called, it
decrements the reference count, and only calls
I386_DR_LOW_RESET_ADDR
and I386_DR_LOW_SET_CONTROL
when
the count goes to zero.
i386_insert_hw_breakpoint (bp_tgt)
i386_remove_hw_breakpoint (bp_tgt)
target_insert_hw_breakpoint
and
target_remove_hw_breakpoint
are set to call these functions.
The argument is a struct bp_target_info *
, as described in
the documentation for target_insert_breakpoint
.
These functions work like i386_insert_watchpoint
and
i386_remove_watchpoint
, respectively, except that they set up
the debug registers to watch instruction execution, and each
hardware-assisted breakpoint always requires exactly one debug
register.
i386_stopped_by_hwbp (void)
i386_stopped_data_address
, except that it doesn't record the
address whose watchpoint triggered.
i386_cleanup_dregs (void)
Notes:
enum target_hw_bp_type
doesn't even have an enumeration for I/O
watchpoints, this feature is not yet available to GDB running
on x86.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Internally, a checkpoint is a saved copy of the program state, including whatever information is required in order to restore the program to that state at a later time. This can be expected to include the state of registers and memory, and may include external state such as the state of open files and devices.
There are a number of ways in which checkpoints may be implemented in gdb, e.g. as corefiles, as forked processes, and as some opaque method implemented on the target side.
A corefile can be used to save an image of target memory and register state, which can in principle be restored later -- but corefiles do not typically include information about external entities such as open files. Currently this method is not implemented in gdb.
A forked process can save the state of user memory and registers, as well as some subset of external (kernel) state. This method is used to implement checkpoints on Linux, and in principle might be used on other systems.
Some targets, e.g. simulators, might have their own built-in method for saving checkpoints, and gdb might be able to take advantage of that capability without necessarily knowing any details of how it is done.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In order to function properly, several modules need to be notified when some changes occur in the GDB internals. Traditionally, these modules have relied on several paradigms, the most common ones being hooks and gdb-events. Unfortunately, none of these paradigms was versatile enough to become the standard notification mechanism in GDB. The fact that they only supported one "client" was also a strong limitation.
A new paradigm, based on the Observer pattern of the Design Patterns book, has therefore been implemented. The goal was to provide a new interface overcoming the issues with the notification mechanisms previously available. This new interface needed to be strongly typed, easy to extend, and versatile enough to be used as the standard interface when adding new notifications.
See A. GDB Currently available observers for a brief description of the observers currently implemented in GDB. The rationale for the current implementation is also briefly discussed.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Please send FSF & GNU inquiries & questions to gnu@gnu.org. There are also other ways to contact the FSF.
These pages are maintained by the GDB developers.
Copyright Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.
This document was generated by GDB Administrator on March, 31 2007 using texi2html