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