\documentclass{article}
\usepackage[fancyhdr,pdf]{latex2man}

\input{common.tex}

\begin{document}

\begin{Name}{3libunwind}{libunwind-nto}{Blackberry}{Programming Library}{QNX Neutrino remote for libunwind}libunwind-nto -- QNX Neutrino support in libunwind
\end{Name}
\section{Synopsis}

\File{\#include $<$libunwind-nto.h$>$}\\

\noindent
\Type{unw\_accessors\_t} \Var{unw\_nto\_accessors};\\

\Type{void~*}\Func{unw\_nto\_create}(\Type{pid\_t}, \Type{pthread\_t});\\
\noindent
\Type{void}~\Func{unw\_nto\_destroy}(\Type{void~*});\\

\noindent
\Type{int} \Func{unw\_nto\_find\_proc\_info}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{unw\_proc\_info\_t~*}, \Type{int}, \Type{void~*});\\
\noindent
\Type{void} \Func{unw\_nto\_put\_unwind\_info}(\Type{unw\_addr\_space\_t}, \Type{unw\_proc\_info\_t~*}, \Type{void~*});\\
\noindent
\Type{int} \Func{unw\_nto\_get\_dyn\_info\_list\_addr}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t~*}, \Type{void~*});\\
\noindent
\Type{int} \Func{unw\_nto\_access\_mem}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{unw\_word\_t~*}, \Type{int}, \Type{void~*});\\
\noindent
\Type{int} \Func{unw\_nto\_access\_reg}(\Type{unw\_addr\_space\_t}, \Type{unw\_regnum\_t}, \Type{unw\_word\_t~*}, \Type{int}, \Type{void~*});\\
\noindent
\Type{int} \Func{unw\_nto\_access\_fpreg}(\Type{unw\_addr\_space\_t}, \Type{unw\_regnum\_t}, \Type{unw\_fpreg\_t~*}, \Type{int}, \Type{void~*});\\
\noindent
\Type{int} \Func{unw\_nto\_get\_proc\_name}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{char~*}, \Type{size\_t}, \Type{unw\_word\_t~*}, \Type{void~*});\\
\noindent
\Type{int} \Func{unw\_nto\_resume}(\Type{unw\_addr\_space\_t}, \Type{unw\_cursor\_t~*}, \Type{void~*});\\

\section{Description}

The QNX operating system makes it possible for a process to
gain access to the machine state and virtual memory of \emph{another}
process, or a different thread within the same process.
gain access to the machine state and virtual memory of \emph{another}
it is possible to hook up \Prog{libunwind} to another process.
While it's not very difficult to do so directly,
\Prog{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 \Func{unw\_nto},
which is stands for ``unwind-via-nto''.

An application that wants to use the \Prog{libunwind} NTO remote needs
to take the following steps.
\begin{enumerate}

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

    \item Create an NTO info structure by calling \Func{unw\_nto\_create}(),
        passing the pid and tid of the target process thread as the arguments.
        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.

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

\end{enumerate}

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

The \Func{unw\_nto\_resume}() is not supported on the NTO remote.

In special circumstances, an application may prefer to use
only portions of the \Prog{libunwind} NTO remote.  For this reason, the
individual callback routines (\Func{unw\_nto\_find\_proc\_info}(),
\Func{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 \Var{unw\_nto\_accessors}, but doing so would prevent static
initialization.  Also, when using \Var{unw\_nto\_accessors}, \emph{all}
the callback routines will be linked into the application, even if
they are never actually called.

\section{Thread Safety}

The \Prog{libunwind} NTO remote assumes that a single \Prog{unw\_nto}-info
structure is never shared between threads of the unwinding program.
Because of this,
no explicit locking is used.
As long as only one thread uses an NTO info structure at any given time,
this facility is thread-safe.

\section{Return Value}

\Func{unw\_nto\_create}() may return a NULL if it fails
to create the NTO info structure for any reason.

\section{Files}

\begin{Description}
\item[\File{libunwind-nto.h}] Headerfile to include when using the
  interface defined by this library.
\item[\Opt{-l}\File{unwind-nto} \Opt{-l}\File{unwind-generic}]
    Linker-switches to add when building a program that uses the
    functions defined by this library.
\end{Description}

\section{Example}
\begin{verbatim}
    #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);
    }
\end{verbatim}

\section{See Also}
\SeeAlso{libunwind}(3libunwind)

\LatexManEnd

\end{document}
