tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Interface to retrieve LWPs via ptrace(2)



There are two basic BSD interfaces to retrieve kernel processes
associated to a process:

FreeBSD:

PT_GETNUMLWPS
        This request returns the number of kernel threads
        associated with the traced process.
PT_GETLWPLIST
        This request can be used to get the current thread list.  A
        pointer to an array of type lwpid_t should be passed in
        addr, with the array size specified by data.  The return
        value from ptrace() is the count of array entries filled
        in.

OpenBSD:

PT_GET_THREAD_FIRST
       This request reads the thread ID of the traced process' first
       thread into the “struct ptrace_thread_state” pointed to by addr.
       The data argument should be set to
       sizeof(struct ptrace_thread_state).
PT_GET_THREAD_NEXT
       This request is just like PT_GET_THREAD_FIRST, except it returns
       the thread ID of the subsequent thread. The
       “struct ptrace_thread_state” pointed to by addr must be
       initialized by a previous PT_GET_THREAD_FIRST or
       PT_GET_THREAD_NEXT request.

I need an equivalent interface for LLDB.

Which one is preferred for NetBSD?

In the OpenBSD one, as there is no timing window (likely harmless)
between GETNUMLWPS and GETLWPLIST. The OpenBSD one can also omit
allocations of intermediate arrays.

On the other hand FreeBSD might need just two ptrace(2) calls for higher
number of LWPs and it might scale better.

Both functions construct equivalent algorithms.

The following examples come from GDB:
- FreeBSD

static void
fbsd_add_threads (pid_t pid)
{
  struct cleanup *cleanup;
  lwpid_t *lwps;
  int i, nlwps;

  gdb_assert (!in_thread_list (pid_to_ptid (pid)));
  nlwps = ptrace (PT_GETNUMLWPS, pid, NULL, 0);
  if (nlwps == -1)
    perror_with_name (("ptrace"));

  lwps = XCNEWVEC (lwpid_t, nlwps);
  cleanup = make_cleanup (xfree, lwps);

  nlwps = ptrace (PT_GETLWPLIST, pid, (caddr_t) lwps, nlwps);
  if (nlwps == -1)
    perror_with_name (("ptrace"));

  for (i = 0; i < nlwps; i++)
    {
      ptid_t ptid = ptid_build (pid, lwps[i], 0);

      if (!in_thread_list (ptid))
	{
#ifdef PT_LWP_EVENTS
	  struct ptrace_lwpinfo pl;

	  /* Don't add exited threads.  Note that this is only called
	     when attaching to a multi-threaded process.  */
	  if (ptrace (PT_LWPINFO, lwps[i], (caddr_t) &pl, sizeof pl) == -1)
	    perror_with_name (("ptrace"));
	  if (pl.pl_flags & PL_FLAG_EXITED)
	    continue;
#endif
	  if (debug_fbsd_lwp)
	    fprintf_unfiltered (gdb_stdlog,
				"FLWP: adding thread for LWP %u\n",
				lwps[i]);
	  add_thread (ptid);
	}
    }
  do_cleanups (cleanup);
}

https://github.com/jsonn/src/blob/trunk/external/gpl3/gdb/dist/gdb/fbsd-nat.c

 - OpenBSD

static void
obsd_update_thread_list (struct target_ops *ops)
{
  pid_t pid = ptid_get_pid (inferior_ptid);
  struct ptrace_thread_state pts;

  prune_threads ();

  if (ptrace (PT_GET_THREAD_FIRST, pid, (caddr_t)&pts, sizeof pts) == -1)
    perror_with_name (("ptrace"));

  while (pts.pts_tid != -1)
    {
      ptid_t ptid = ptid_build (pid, pts.pts_tid, 0);

      if (!in_thread_list (ptid))
	{
	  if (ptid_get_lwp (inferior_ptid) == 0)
	    thread_change_ptid (inferior_ptid, ptid);
	  else
	    add_thread (ptid);
	}

      if (ptrace (PT_GET_THREAD_NEXT, pid, (caddr_t)&pts, sizeof pts) == -1)
	perror_with_name (("ptrace"));
    }
}

https://github.com/jsonn/src/blob/trunk/external/gpl3/gdb/dist/gdb/obsd-nat.c

Attachment: signature.asc
Description: OpenPGP digital signature



Home | Main Index | Thread Index | Old Index