---
name: "libunwind-ptrace"
section: "3"
platform: "linux"
package: "libunwind"
version: "1.8.3-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/libunwind-ptrace"
---

# libunwind-ptrace(3)

## NAME

libunwind-ptrace -- ptrace() support in libunwind

## SYNOPSIS

\#include \<libunwind-ptrace.h\>\

unw\_accessors\_t \_UPT\_accessors;\

void \*\_UPT\_create(pid\_t);\
 void \_UPT\_destroy(void \*);\

int \_UPT\_find\_proc\_info(unw\_addr\_space\_t, unw\_word\_t, unw\_proc\_info\_t \*, int, void \*);\
 void \_UPT\_put\_unwind\_info(unw\_addr\_space\_t, unw\_proc\_info\_t \*, void \*);\
 int \_UPT\_get\_dyn\_info\_list\_addr(unw\_addr\_space\_t, unw\_word\_t \*, void \*);\
 int \_UPT\_access\_mem(unw\_addr\_space\_t, unw\_word\_t, unw\_word\_t \*, int, void \*);\
 int \_UPT\_access\_reg(unw\_addr\_space\_t, unw\_regnum\_t, unw\_word\_t \*, int, void \*);\
 int \_UPT\_access\_fpreg(unw\_addr\_space\_t, unw\_regnum\_t, unw\_fpreg\_t \*, int, void \*);\
 int \_UPT\_get\_proc\_name(unw\_addr\_space\_t, unw\_word\_t, char \*, size\_t, unw\_word\_t \*, void \*);\
 int \_UPT\_resume(unw\_addr\_space\_t, unw\_cursor\_t \*, void \*);\

## DESCRIPTION

The [ptrace(2)](/ptrace/2.md) system call makes it possible for a process to  gain access to the machine state and virtual memory of *another* process. With the right set of callback routines, it is therefore  possible to hook up libunwind to another process via  [ptrace(2)](/ptrace/2.md). While it's not very difficult to do so directly,  libunwind further facilitates this task by providing  ready-to-use callbacks for this purpose. The routines and variables  implementing this facility use a name prefix of \_UPT, which is  stands for \`\`unwind via ptrace''.

An application that wants to use the libunwind ptrace remote needs to  take the folowing steps.

- 1\.

  Create a new libunwind address space that represents the target process. This is done by calling unw\_create\_addr\_space(). In  many cases, the application will simply want to pass the address of  \_UPT\_accessors as the first argument to this routine. Doing so  will ensure that libunwind will be able to properly unwind the  target process.

- 2\.

  Turn on ptrace mode on the target process, either by forking a new  process, invoking PTRACE\_TRACEME, and then starting the target  program (via [execve(2)](/execve/2.md)), or by directly attaching to an already  running process (via PTRACE\_ATTACH).

- 3\.

  Once the process-ID (pid) of the target process is known, a  UPT info structure can be created by calling  \_UPT\_create(), passing the pid of the target process as the  only argument.

- 4\.

  The opaque pointer returned then needs to be passed as the  \`\`argument'' pointer (third argument) to unw\_init\_remote().

In special circumstances, an application may prefer to use only  portions of the libunwind ptrace remote. For this reason, the individual  callback routines (\_UPT\_find\_proc\_info(), \_UPT\_put\_unwind\_info(), etc.) are also available for direct use. Of  course, the addresses of these routines could also be picked up from  \_UPT\_accessors, but doing so would prevent static initialization. Also,  when using \_UPT\_accessors, *all* the callback routines will be  linked into the application, even if they are never actually called.

The \_UPT\_resume() routine can be used to resume execution of the target  process. It simply invokes [ptrace(2)](/ptrace/2.md) with a command value of  PTRACE\_CONT.

When the application is done using libunwind on the target process,  \_UPT\_destroy() needs to be called, passing it the opaque pointer that  was returned by the call to \_UPT\_create(). This ensures that all  memory and other resources are freed up.

## AVAILABILITY

Since [ptrace(2)](/ptrace/2.md) works within a single machine only, the libunwind ptrace  remote by definition is not available in libunwind versions configured  for cross-unwinding.

## THREAD SAFETY

The libunwind ptrace remote assumes that a single UPT info structure is  never shared between threads. Because of this, no explicit locking is used. As  long as only one thread uses a UPT info structure at any given time, this  facility is thread-safe.

## RETURN VALUE

\_UPT\_create() may return a NULL pointer if it fails to create  the UPT info structure for any reason. For the current implementation, the only  reason this call may fail is when the system is out of memory.

## FILES

- libunwind-ptrace.h

   Header file to include when using the  interface defined by this library.

- **-l**unwind-ptrace **-l**unwind-generic

   Linker switches to add when building a program that uses the  functions defined by this library.

## EXAMPLE

```
    #include <libunwind-ptrace.h>
    #include <stdio.h>
    #include <stdlib.h>
    int
    main (int argc, char **argv)
    {
      if (argc != 2) {
        fprintf (stderr, "usage: %s PID\n", argv[0]);
        exit (EXIT_FAILURE);
      }
      char *endptr;
      pid_t target_pid = strtoul (argv[1], &endptr, 10);
      if (target_pid == 0 && argv[1] == endptr) {
        fprintf (stderr, "usage: %s PID\n", argv[0]);
        exit (EXIT_FAILURE);
      }
      unw_addr_space_t as = unw_create_addr_space (&_UPT_accessors, 0);
      if (!as) {
        fprintf (stderr, "unw_create_addr_space() failed");
        exit (EXIT_FAILURE);
      }
      void *ui = _UPT_create (target_pid);
      if (!ui) {
        fprintf (stderr, "_UPT_create() failed");
        exit (EXIT_FAILURE);
      }
      unw_cursor_t cursor;
      int ret = unw_init_remote (&cursor, as, ui);
      if (ret < 0) {
        fprintf (stderr, "unw_init_remote() failed: ret=%d\n", ret);
        exit (EXIT_FAILURE);
      }
      do {
        unw_proc_info_t pi;
        ret = unw_get_proc_info (&cursor, &pi);
        if (ret == -UNW_ENOINFO) {
          fprintf (stdout, "no info\n");
        } else if (ret >= 0) {
          printf ("\tproc=%#016lx-%#016lx\thandler=%#016lx lsda=%#016lx",
                  (long) pi.start_ip, (long) pi.end_ip,
                  (long) pi.handler, (long) pi.lsda);
        }
        ret = unw_step (&cursor);
      } while (ret > 0);
      if (ret < 0) {
        fprintf (stderr, "unwind failed with ret=%d\n", ret);
        exit (EXIT_FAILURE);
      }
      _UPT_destroy (ui);
      unw_destroy_addr_space (as);
      exit (EXIT_SUCCESS);
    }
```

## SEE ALSO

[execve(2)](/execve/2.md), libunwind(3libunwind), [ptrace(2)](/ptrace/2.md)

## AUTHOR

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