| 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 |
| |