LIBUNWIND-NTO(3libunwind)

πŸ’– LIBUNWIND-NTO β€” QNX Neutrino support in libunwind πŸ’–

okay bestie, welcome to libunwind-nto from the 3libunwind manual β€” this is the QNX Neutrino ✨remote✨ situation and honestly it's giving "spy on another process, but make it library-grade" πŸ•΅οΈβ™€οΈπŸ¦‹


🌸 NAME 🌸

libunwind-nto β€” QNX Neutrino support in libunwind πŸ’… no cap, that's literally the whole name section.


✨ SYNOPSIS ✨

here's the vibe, verbatim, don't @ me:

#include <libunwind-nto.h>

unw_accessors_t unw_nto_accessors;

void *unw_nto_create(pid_t, pthread_t);
void unw_nto_destroy(void *);

int unw_nto_find_proc_info(unw_addr_space_t, unw_word_t, unw_proc_info_t
*, int, void *);
void unw_nto_put_unwind_info(unw_addr_space_t, unw_proc_info_t *, void
*);
int unw_nto_get_dyn_info_list_addr(unw_addr_space_t, unw_word_t *, void
*);
int unw_nto_access_mem(unw_addr_space_t, unw_word_t, unw_word_t *, int,
void *);
int unw_nto_access_reg(unw_addr_space_t, unw_regnum_t, unw_word_t *,
int, void *);
int unw_nto_access_fpreg(unw_addr_space_t, unw_regnum_t, unw_fpreg_t *,
int, void *);
int unw_nto_get_proc_name(unw_addr_space_t, unw_word_t, char *, size_t,
unw_word_t *, void *);
int unw_nto_resume(unw_addr_space_t, unw_cursor_t *, void *);

πŸ¦‹ DESCRIPTION πŸ¦‹

okay so here's the tea β˜• QNX lets a process get access to the machine state and virtual memory of another process, or of a different thread inside the same process. gain access to the machine state and virtual memory of another β€” yeah, that part again, it's in the source text, we keep it, we don't edit the icon 🫢 β€” and because of all that, it's possible to hook up libunwind to another process. πŸ‘‘

ngl, doing that directly isn't super hard, but libunwind is out here doing the most for you by shipping ready-to-use callbacks for exactly this purpose. slay. πŸ’…

the routines and variables that implement this facility all rock a name prefix of unw_nto β€” which is stands for ``unwind-via-nto''. iykyk. πŸŽ€

an application that wants to use the libunwind NTO remote has to take these steps, in order, no skipping:

  1. create a new libunwind address-space that represents the target process and thread. you do this by calling unw_create_addr_space(). in many cases your app is just gonna pass the address of unw_nto_accessors as the first argument to that routine. doing so = libunwind can properly unwind the target process. periodt. ✨
  2. create an NTO info structure by calling unw_nto_create(), passing the pid and tid of the target process thread as the arguments. heads up bestie: this will stop the target thread πŸ›‘. the process ID (pid) of the target process must be known, and only a single thread can be unwound at a time so the thread ID (tid) must also be specified.
  3. the opaque pointer that comes back needs to be passed as the ``argument'' pointer β€” that's the third argument β€” to unw_init_remote(). πŸ’–

when your app is done using libunwind on the target process, you need to call unw_nto_destroy(), handing it the opaque pointer that unw_nto_create() returned. that's what ensures all the memory and other resources are freed up. 🧹✨

also: unw_nto_resume() is not supported on the NTO remote. just so you know. πŸ’€

in special circumstances, an application may prefer to use only portions of the libunwind NTO remote. for this reason, the individual callback routines β€” unw_nto_find_proc_info(), unw_nto_put_unwind_info(), etc. β€” are also available for direct use. of course, the addresses of these routines could also be picked up from unw_nto_accessors, but doing so would prevent static initialization. also, when you use unw_nto_accessors, all the callback routines get linked into the application, even if they're never actually called. no thoughts, just linkage. πŸ™ˆ


🌈 THREAD SAFETY 🌈

the libunwind NTO remote assumes that a single unw_nto-info structure is never shared between threads of the unwinding program. because of this, no explicit locking is used, like, at all. as long as only one thread uses an NTO info structure at any given time, this facility is thread-safe. one at a time bestie, we are not doing chaos πŸ‘‘πŸ’…


⭐ RETURN VALUE ⭐

unw_nto_create() may return a NULL if it fails to create the NTO info structure for any reason. that's it, that's the return value section. short and iconic.


πŸŽ€ FILES πŸŽ€

  • libunwind-nto.h β€” headerfile to include when using the interface defined by this library. yes, "headerfile", one word, we respect it 🫢
  • -lunwind-nto -lunwind-generic β€” linker-switches to add when building a program that uses the functions defined by this library. don't forget them or you'll be crying in undefined reference 😭

πŸ’œ EXAMPLE πŸ’œ

here's a whole entire main character program, copied exactly, zero edits:

#include <libunwind-nto.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 (&unw_nto_accessors, 0);
  if (!as) {
    fprintf (stderr, "unw_create_addr_space() failed");
    exit (EXIT_FAILURE);
  }

  void *ui = unw_nto_create (target_pid, (thread_t)1);
  if (!ui) {
    fprintf (stderr, "unw_nto_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);
  }

  unw_nto_destroy (ui);
  unw_destroy_addr_space (as);
  exit (EXIT_SUCCESS);
}

πŸ‘‘ SEE ALSO πŸ‘‘


and that's the page!! this was the Programming Library page for LIBUNWIND-NTO(3libunwind), dated 29 August 2023 πŸ’– slay, go unwind something (responsibly, single-threaded, one at a time) πŸ¦‹βœ¨πŸ’