You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
5.4 KiB
127 lines
5.4 KiB
The central data structure of the unwind API is the unwind cursor. |
|
This structure tracks the register contents. 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; |
|
unw_context_t uc; |
|
|
|
unw_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. |
|
|
|
* IA-64 Specific Information |
|
|
|
Apart from the normal frame-registers, the IA-64 implementation of |
|
libunwind provides the means to access the current value of the |
|
register backing store pointer (bsp). One quirk with this |
|
frame-register is that it corresponds to the address that would be in |
|
register ar.bsp after flushing the current register stack to the |
|
backing store (i.e., as if a "flushrs" instruction had been executed). |
|
Of course, given this value and the contents of the current frame |
|
marker (CFM), it's easy to calculate the original value of ar.bsp: |
|
|
|
unw_word_t cfm, bsp, bsp_after_flushrs, sof; |
|
|
|
unw_get_reg (&cursor, UNW_IA64_BSP, &bsp_after_flushrs); |
|
unw_get_reg (&cursor, UNW_IA64_CFM, &cfm); |
|
bsp = ia64_rse_skip_regs (bsp_after_flushrs, -(cfm & 0x7f)); |
|
|
|
** Dynamic Unwind Info |
|
|
|
|