mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-29 02:07:39 +01:00
74 lines
3.3 KiB
Text
74 lines
3.3 KiB
Text
The central data structure of the unwind API is the unwind cursor.
|
|
This structure tracks the frame registers and the preserved registers.
|
|
The distinction between frame registers and preserved registers is
|
|
important: the former represent the *current* value of a register (as
|
|
it existed at the current IP); the latter represent the *saved* value
|
|
of a register (i.e., the value that existed on entry to the current
|
|
procedure). The unwind API defines a handful of well-known frame
|
|
"registers":
|
|
|
|
- ip: the instruction pointer (pc)
|
|
- rp: the return pointer (rp, aka "return address" or "return link")
|
|
- sp: the stack pointer (memory stack pointer, in the case of ia64)
|
|
- fp: the frame pointer
|
|
- first_ip: the starting address of the current "procedure"
|
|
- handler: a pointer to an architecture & language-specific
|
|
"personality" routine
|
|
- lsda: a pointer to an architecture & language-specific
|
|
data-area
|
|
|
|
The API defines no well-known preserved registers. Each architecture
|
|
can define additional registers as needed. Of course, a portable
|
|
application may only rely on well-known registers. The names for
|
|
preserved registers are defined in the architecture-specific header
|
|
file <unwind-ARCH.h>. For example, to get the IA-64-specific register
|
|
names, an application would do:
|
|
|
|
#include <unwind-ia64.h>
|
|
|
|
The API is designed to handle two primary cases: unwinding within the
|
|
current (local) process and unwinding of another ("remote") process
|
|
(e.g., through ptrace()). In the local case, the initial machine
|
|
state is captured by an unwind context (currently the same as
|
|
ucontext_t). In the remote case, the initial machine state is
|
|
captured by an unwind accessor structure, which provides callback
|
|
routines for reading/writing memory and registers and for obtaining
|
|
unwind information.
|
|
|
|
Once a cursor has been initialized, you can step through the call
|
|
chain with the unw_step() routine. The frame registers and the
|
|
preserved state can then be accessed with unw_get_reg() or modified
|
|
with unw_set_reg(). For floating-point registers, there are separate
|
|
unw_get_fpreg() and unw_set_fpreg() routines (on some arches, e.g.,
|
|
Alpha, these could be just aliases for unw_{g,s}et_reg()). The
|
|
unw_resume() routine can be used to resume execution at an arbitrary
|
|
point in the call-chain (as identified by an unwind cursor). This is
|
|
intended for exception handling and, at least for now, the intention
|
|
is to support this routine only for the local case. Kevin, if you
|
|
feel gdb could benefit from such a routine, I'd be interested to hear
|
|
about it.
|
|
|
|
Note that it is perfectly legal to make copies of the unwind cursor.
|
|
This makes it possible, e.g., to obtain an unwind context, modify the
|
|
state in an earlier call frame, and then resume execution at the point
|
|
at which the unwind context was captured.
|
|
|
|
Here is a quick example of how to use the unwind API to do a simple
|
|
stack trace:
|
|
|
|
unw_cursor_t cursor;
|
|
unw_word_t ip, sp;
|
|
ucontext_t uc;
|
|
|
|
getcontext(&uc);
|
|
unw_init_local(&cursor, &uc);
|
|
do
|
|
{
|
|
unw_get_reg(&cursor, UNW_REG_IP, &ip);
|
|
unw_get_reg(&cursor, UNW_REG_SP, &sp);
|
|
printf ("ip=%016lx sp=%016lx\n", ip, sp);
|
|
}
|
|
while (unw_step (&cursor) > 0);
|
|
|
|
Note that this particular example should work on pretty much any
|
|
architecture, as it doesn't rely on any arch-specific registers.
|