libunwind - Man Page

a (mostly) platform-independent unwind API

Synopsis

#include <libunwind.h>

int unw_getcontext(unw_context_t *);
int unw_init_local(unw_cursor_t *, unw_context_t *);
int unw_init_remote(unw_cursor_t *, unw_addr_space_t, void *);
int unw_step(unw_cursor_t *);
int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *);
int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *);
int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t);
int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t);
int unw_resume(unw_cursor_t *);

unw_addr_space_t unw_local_addr_space;
unw_addr_space_t unw_create_addr_space(unw_accessors_t, int);
void unw_destroy_addr_space(unw_addr_space_t);
unw_accessors_t unw_get_accessors(unw_addr_space_t);
void unw_flush_cache(unw_addr_space_t, unw_word_t, unw_word_t);
int unw_set_caching_policy(unw_addr_space_t, unw_caching_policy_t);
int unw_set_cache_size(unw_addr_space_t, size_t, int);

const char *unw_regname(unw_regnum_t);
int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *);
int unw_get_save_loc(unw_cursor_t *, int, unw_save_loc_t *);
int unw_is_fpreg(unw_regnum_t);
int unw_is_signal_frame(unw_cursor_t *);
int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *);

void _U_dyn_register(unw_dyn_info_t *);
void _U_dyn_cancel(unw_dyn_info_t *);

Local Unwinding

Libunwind is very easy to use when unwinding a stack from  within a running program. This is called local unwinding. Say  you want to unwind the stack while executing in some function  F(). In this function, you would call unw_getcontext() to get a snapshot of the CPU registers (machine state). Then you  initialize an unwind cursor based on this snapshot. This is  done with a call to unw_init_local(). The cursor now points  to the current frame, that is, the stack frame that corresponds to the  current activation of function F(). The unwind cursor can then  be moved “up” (towards earlier stack frames) by calling  unw_step(). By repeatedly calling this routine, you can  uncover the entire call chain that led to the activation of function  F(). A positive return value from unw_step() indicates  that there are more frames in the chain, zero indicates that the end  of the chain has been reached, and any negative value indicates that  some sort of error has occurred.

While it is not possible to directly move the unwind cursor in the  “down” direction (towards newer stack frames), this effect can be  achieved by making copies of an unwind cursor. For example, a program  that sometimes has to move “down” by one stack frame could maintain  two cursor variables: “curr” and “prev”. The former  would be used as the current cursor and prev would be maintained  as the “previous frame” cursor by copying the contents of curr to prev right before calling unw_step(). With this  approach, the program could move one step “down” simply by copying  back prev to curr whenever that is necessary. In the most  extreme case, a program could maintain a separate cursor for each call  frame and that way it could move up and down the callframe chain at  will.

Given an unwind cursor, it is possible to read and write the CPU  registers that were preserved for the current stack frame (as  identified by the cursor). Libunwind provides several routines  for this purpose: unw_get_reg() reads an integer (general)  register, unw_get_fpreg() reads a floating-point register,  unw_set_reg() writes an integer register, and  unw_set_fpreg() writes a floating-point register. Note that,  by definition, only the preserved machine state can be accessed  during an unwind operation. Normally, this state consists of the  callee-saved (“preserved”) registers. However, in some  special circumstances (e.g., in a signal handler trampoline), even the  caller-saved (“scratch”) registers are preserved in the stack  frame and, in those cases, libunwind will grant access to them  as well. The exact set of registers that can be accessed via the  cursor depends, of course, on the platform. However, there are two  registers that can be read on all platforms: the instruction pointer  (IP), sometimes also known as the “program counter”, and the stack  pointer (SP). In libunwind, these registers are identified by  the macros UNW_REG_IP and UNW_REG_SP, respectively.

Besides just moving the unwind cursor and reading/writing saved  registers, libunwind also provides the ability to resume  execution at an arbitrary stack frame. As you might guess, this is  useful for implementing non-local gotos and the exception handling  needed by some high-level languages such as Java. Resuming execution  with a particular stack frame simply requires calling  unw_resume() and passing the cursor identifying the target  frame as the only argument.

Normally, libunwind supports both local and remote unwinding  (the latter will be explained in the next section). However, if you  tell libunwind that your program only needs local unwinding, then  a special implementation can be selected which may run much faster than  the generic implementation which supports both kinds of unwinding. To  select this optimized version, simply define the macro  UNW_LOCAL_ONLY before including the headerfile  <libunwind.h>. It is perfectly OK for a single program to  employ both local-only and generic unwinding. That is, whether or not  UNW_LOCAL_ONLY is defined is a choice that each source file  (compilation unit) can make on its own. Independent of the setting(s)  of UNW_LOCAL_ONLY, you'll always link the same library into  the program (normally -lunwind). Furthermore, the  portion of libunwind that manages unwind info for dynamically  generated code is not affected by the setting of  UNW_LOCAL_ONLY.

If we put all of the above together, here is how we could use  libunwind to write a function “show_backtrace()” which prints a classic stack trace:

#define UNW_LOCAL_ONLY
#include <libunwind.h>

void show_backtrace (void) {
  unw_cursor_t cursor; unw_context_t uc;
  unw_word_t ip, sp;

  unw_getcontext(&uc);
  unw_init_local(&cursor, &uc);
  while (unw_step(&cursor) > 0) {
    unw_get_reg(&cursor, UNW_REG_IP, &ip);
    unw_get_reg(&cursor, UNW_REG_SP, &sp);
    printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp);
  }
}

Remote Unwinding

Libunwind can also be used to unwind a stack in a “remote”  process. Here, “remote” may mean another process on the same  machine or even a process on a completely different machine from the  one that is running libunwind. Remote unwinding is typically  used by debuggers and instruction-set simulators, for example.

Before you can unwind a remote process, you need to create a new  address space object for that process. This is achieved with the  unw_create_addr_space() routine. The routine takes two  arguments: a pointer to a set of accessor routines and an  integer that specifies the byte order of the target process. The  accessor routines provide libunwind with the means to  communicate with the remote process. In particular, there are  callbacks to read and write the process's memory, its registers, and  to access unwind information which may be needed by libunwind.

With the address space created, unwinding can be initiated by a call  to unw_init_remote(). This routine is very similar to  unw_init_local(), except that it takes an address space  object and an opaque pointer as arguments. The routine uses these  arguments to fetch the initial machine state. Libunwind never  uses the opaque pointer on its own, but instead just passes it on to  the accessor (callback) routines. Typically, this pointer is used to  select, e.g., the thread within a process that is to be unwound.

Once a cursor has been initialized with unw_init_remote(), unwinding works exactly like in the local case. That is, you can use  unw_step() to move “up” in the call chain, read and write  registers, or resume execution at a particular stack frame by calling  unw_resume.

Cross-Platform and Multi-Platform Unwinding

Libunwind has been designed to enable unwinding across  platforms (architectures). Indeed, a single program can use  libunwind to unwind an arbitrary number of target platforms,  all at the same time!

We call the machine that is running libunwind the host and the machine that is running the process being unwound the  target. If the host and the target platform are the same, we  call it native unwinding. If they differ, we call it  cross-platform unwinding.

The principle behind supporting native, cross-platform, and  multi-platform unwinding is very simple: for native unwinding, a  program includes <libunwind.h> and uses the linker switch  -lunwind. For cross-platform unwinding, a program  includes <libunwind-PLAT.h> and uses the linker  switch -lunwind-PLAT, where PLAT is the name  of the target platform (e.g., ia64 for IA-64, hppa-elf for ELF-based HP PA-RISC, or x86 for 80386). Multi-platform  unwinding works exactly like cross-platform unwinding, the only  limitation is that a single source file (compilation unit) can include  at most one libunwind header file. In other words, the  platform-specific support for each supported target needs to be  isolated in separate source files---a limitation that shouldn't be an  issue in practice.

Note that, by definition, local unwinding is possible only for the  native case. Attempting to call, e.g., unw_local_init() when  targeting a cross-platform will result in a link-time error  (unresolved references).

Thread- and Signal-Safety

All libunwind routines are thread-safe. What this means is  that multiple threads may use libunwind simultaneously.  However, any given cursor may be accessed by only one thread at  any given time.

To ensure thread safety, some libunwind routines may have to  use locking. Such routines must not be called from signal  handlers (directly or indirectly) and are therefore not signal-safe. The manual page for each libunwind routine  identifies whether or not it is signal-safe, but as a general rule,  any routine that may be needed for local unwinding is  signal-safe (e.g., unw_step() for local unwinding is  signal-safe). For remote unwinding, none of the  libunwind routines are guaranteed to be signal-safe.

Unwinding Through Dynamically Generated Code

Libunwind provides the routines _U_dyn_register() and  _U_dyn_cancel() to register/cancel the information required to  unwind through code that has been generated at runtime (e.g., by a  just-in-time (JIT) compiler). It is important to register the  information for all dynamically generated code because  otherwise, a debugger may not be able to function properly or  high-level language exception handling may not work as expected.

The interface for registering and canceling dynamic unwind info has  been designed for maximum efficiency, so as to minimize the  performance impact on JIT compilers. In particular, both routines are  guaranteed to execute in “constant time” (O(1)) and the  data structure encapsulating the dynamic unwind info has been designed  to facilitate sharing, such that similar procedures can share much of  the underlying information.

For more information on the libunwind support for dynamically  generated code, see libunwind-dynamic(3libunwind).

Caching of Unwind Info

To speed up execution, libunwind may aggressively cache the  information it needs to perform unwinding. If a process changes  during its lifetime, this creates a risk of libunwind using  stale data. For example, this would happen if libunwind were  to cache information about a shared library which later on gets  unloaded (e.g., via dlclose(3libunwind)).

To prevent the risk of using stale data, libunwind provides two  facilities: first, it is possible to flush the cached information  associated with a specific address range in the target process (or the  entire address space, if desired). This functionality is provided by  unw_flush_cache(). The second facility is provided by  unw_set_caching_policy(), which lets a program  select the exact caching policy in use for a given address space  object. In particular, by selecting the policy  UNW_CACHE_NONE, it is possible to turn off caching  completely, therefore eliminating the risk of stale data altogether  (at the cost of slower execution). By default, caching is enabled for  local unwinding only. The cache size can be dynamically changed with  unw_set_cache_size(), which also flushes the current cache.

Files

libunwind.h

Headerfile to include for native (same  platform) unwinding.

libunwind-PLAT.h

Headerfile to include when  the unwind target runs on platform PLAT. For example, to unwind  an IA-64 program, the header file libunwind-ia64.h should be  included.

-lunwind

Linker switch to add when building a  program that does native (same platform) unwinding.

-lunwind-PLAT

Linker switch to add when  building a program that unwinds a program on platform PLAT. For example, to (cross-)unwind an IA-64 program, the linker switch  -lunwind-ia64 should be added. Note: multiple such switches  may need to be specified for programs that can unwind programs on  multiple platforms.

See Also

libunwind-dynamic(3libunwind), libunwind-ia64(3libunwind), libunwind-ptrace(3libunwind), libunwind-setjmp(3libunwind), unw_create_addr_space(3libunwind), unw_destroy_addr_space(3libunwind), unw_flush_cache(3libunwind), unw_get_accessors(3libunwind), unw_get_fpreg(3libunwind), unw_get_proc_info(3libunwind), unw_get_proc_name(3libunwind), unw_get_reg(3libunwind), unw_getcontext(3libunwind), unw_init_local(3libunwind), unw_init_remote(3libunwind), unw_is_fpreg(3libunwind), unw_is_signal_frame(3libunwind), unw_regname(3libunwind), unw_resume(3libunwind), unw_set_caching_policy(3libunwind), unw_set_cache_size(3libunwind), unw_set_fpreg(3libunwind), unw_set_reg(3libunwind), unw_step(3libunwind), unw_strerror(3libunwind), _U_dyn_register(3libunwind), _U_dyn_cancel(3libunwind)

Author

David Mosberger-Tang
Email: dmosberger@gmail.com
WWW: http://www.nongnu.org/libunwind/.

Info

29 August 2023 Programming Library