mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-12-23 20:03:43 +01:00
4b00b1f7b5
(Logical change 1.12)
112 lines
4.9 KiB
Text
112 lines
4.9 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.
|
|
|
|
* Multiarchitecture support
|
|
|
|
If libunwind is configured for a target other than the local (native)
|
|
host, the library is installed as libunwind-$ARCH, where $ARCH is
|
|
the target architecture name (e.g., ia32, ia64, or alpha). Similarly,
|
|
the header file is installed as libunwind-$ARCH.
|
|
|
|
With this setup, an application should:
|
|
|
|
- include <libunwind.h>, and
|
|
- link against -lunwind
|
|
|
|
if the application needs to use the unwinder of the host. An
|
|
application wanting to use the unwinder for a different target (e.g.,
|
|
a cross-debugger) should:
|
|
|
|
- include <libunwind-$ARCH.h>, and
|
|
- link against -lunwind-$ARCH
|
|
|
|
The global symbols exported by -lunwind-$ARCH are unique such that the
|
|
same application can be linked against the separate unwind libraries
|
|
of multiple targets. However, a single compilation unit can include
|
|
the header file for only one target. For example, foo.c might include
|
|
<libunwind-ia64.h> and bar.c might include <libunwind.h> and the
|
|
entire application would have to be linked against both -lunwind and
|
|
-lunwind-ia64.
|
|
|
|
Note: the unwind header files of all targets have a common dependency
|
|
on libunwind-common.h. To avoid version conflicts, it is necessary to
|
|
ensure that the unwind libraries for all targets were derived from the
|
|
same release of libunwind. That is, if the unwind library for one
|
|
target is upgraded to a newer version, the libraries for all other
|
|
targets also need to be upgraded.
|
|
|
|
Note 2: The assumption is that a cross-unwinder can handle all
|
|
interesting flavors of a target. For example, the unwinder for the
|
|
ia64 target is expected to be able to handle both Linux and HP-UX.
|