This is the mail archive of the
gdb@sourceware.cygnus.com
mailing list for the GDB project.
Re: uw-threads issues
>There are currently two failure cases that are interesting.
There've been several bug fixes in uw-thread.c since the version Jason
emailed you. Those changes should show up in the gdb snapshot
shortly, but in the meantime, could you try the appended patch?
Nick Duffek
nsd@cygnus.com
--- uw-thread.c 2000/01/07 20:28:50
+++ uw-thread.c 2000/01/14 04:18:30
@@ -1,5 +1,5 @@
-/* Low level interface for debugging UnixWare threads for GDB, the GNU
- debugger.
+/* Low level interface for debugging UnixWare user-mode threads for
+ GDB, the GNU debugger.
Copyright 1999, 2000 Free Software Foundation, Inc.
@@ -20,6 +20,82 @@
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+
+/* Like many systems, UnixWare implements two classes of threads:
+ kernel-mode threads, which are scheduled by the kernel; and
+ user-mode threads, which are scheduled by a library. UnixWare
+ calls these two classes lightweight processes (LWPs) and threads,
+ respectively.
+
+ This module deals with user-mode threads. It calls procfs_ops
+ functions to deal with LWPs and processes and core_ops functions to
+ deal with core files.
+
+ As of this writing, the user-mode thread debugging interface is not
+ documented beyond the comments in <thread.h>. The following
+ description has been gleaned from experience and from information
+ provided by SCO.
+
+ libthread.so, against which all UnixWare user-mode thread programs
+ link, provides a global thread_debug structure named _thr_debug.
+ It has three fields:
+
+ (1) thr_map is a pointer to a pointer to an element of a
+ thread_map ring. A thread_map contains a single thread's id
+ number, state, LWP pointer, recent register state, and other
+ useful information.
+
+ (2) thr_brk is a pointer to a stub function that libthread.so
+ calls when it changes a thread's state, e.g. by creating it,
+ switching it to an LWP, or causing it to exit.
+
+ (3) thr_debug_on controls whether libthread.so calls thr_brk().
+
+ Debuggers are able to track thread activity by setting a private
+ breakpoint on thr_brk() and setting thr_debug_on to 1.
+
+ thr_brk() receives two arguments:
+
+ (1) a pointer to a thread_map describing the thread being
+ changed; and
+
+ (2) an enum thread_change specifying one of the following
+ changes:
+
+ invalid unknown
+ thread_create thread has just been created
+ thread_exit thread has just exited
+ switch_begin thread will be switched to an LWP
+ switch_complete thread has been switched to an LWP
+ cancel_complete thread wasn't switched to an LWP
+ thread_suspend thread has been thr_suspend()ed
+ thread_suspend_pending thread will be thr_suspend()ed
+ thread_continue thread has been thr_continue()d
+
+ The thread_map argument to thr_brk() is NULL under the following
+ circumstances:
+
+ - The main thread is being acted upon. The main thread always
+ has id 1, so its thread_map is easy to find by scanning through
+ _thr_debug.thr_map.
+
+ - A "switch_complete" change is occurring, which means that the
+ thread specified in the most recent "switch_begin" change has
+ moved to an LWP.
+
+ - A "cancel_complete" change is occurring, which means that the
+ thread specified in the most recent "switch_begin" change has
+ not moved to an LWP after all.
+
+ - A spurious "switch_begin" change is occurring after a
+ "thread_exit" change.
+
+ Between switch_begin and switch_complete or cancel_complete, the
+ affected thread's LWP pointer is not reliable. It is possible that
+ other parts of the thread's thread_map are also unreliable during
+ that time. */
+
+
#include "defs.h"
#include "gdbthread.h"
#include "target.h"
@@ -38,22 +114,9 @@
/*
- * Private thread data for the thread_info struct.
- */
-struct private_thread_info {
- int stable; /* 0 if libthread.so is modifying thread map */
- int thrid; /* thread id assigned by libthread.so */
- int lwpid; /* thread's lwp if .stable, 0 means no lwp */
- CORE_ADDR mapp; /* address of thread's map structure */
-};
-
-/* Tell procfs.c that we are taking over! */
-extern int procfs_suppress_run;
-
-/*
* Whether to emit debugging output.
*/
-#define DEBUG 1
+#define DEBUG 0
/*
* Default debugging output file, overridden by envvar UWTHR_DEBUG.
@@ -63,7 +126,7 @@
/*
* #if DEBUG, write string S to the debugging output channel.
*/
-#ifndef DEBUG
+#if !DEBUG
# define DBG(fmt_and_args)
# define DBG2(fmt_and_args)
#else
@@ -89,11 +152,11 @@
*
* Otherwise, issue an error message and return nonlocally.
*/
-#define CALL_BASE(call) \
-do { \
- if (!lwp_infpid()) \
- error ("uw-thread: no lwp"); \
- CALL_BASE_1 (call); \
+#define CALL_BASE(call) \
+do { \
+ if (!lwp_infpid ()) \
+ error ("uw-thread: "__FUNCTION__": no lwp"); \
+ CALL_BASE_1 (call); \
} while (0)
/*
@@ -102,7 +165,7 @@
*/
#define TRY_BASE(call, called) \
do { \
- if ((*(called) = lwp_infpid())) \
+ if ((*(called) = lwp_infpid ())) \
CALL_BASE_1 (call); \
} while (0)
@@ -115,10 +178,23 @@
CORE_ADDR mapp;
} iter_t;
+/*
+ * Private thread data for the thread_info struct.
+ */
+struct private_thread_info {
+ int stable; /* 0 if libthread.so is modifying thread map */
+ int thrid; /* thread id assigned by libthread.so */
+ int lwpid; /* thread's lwp if .stable, 0 means no lwp */
+ CORE_ADDR mapp; /* address of thread's map structure */
+};
+
/* procfs.c's target-specific operations. */
extern struct target_ops procfs_ops;
+/* Flag to prevent procfs.c from starting inferior processes. */
+extern int procfs_suppress_run;
+
/* This module's target-specific operations. */
static struct target_ops uw_thread_ops;
@@ -334,8 +410,8 @@
static void
deactivate_uw_thread (void)
{
- unpush_target (&uw_thread_ops);
uw_thread_active = 0;
+ unpush_target (&uw_thread_ops);
}
/*
@@ -362,15 +438,13 @@
}
/*
- * If a thread is associated with lwp id LWPID, return the corresponding
- * member of the global thread list; otherwise, return null.
+ * find_thread_lwp() callback: return whether TP describes a thread
+ * associated with lwp id DATA.
*/
-
-/* Iterator callback function, returns true if match. */
static int
find_thread_lwp_callback (struct thread_info *tp, void *data)
{
- int lwpid = (int) data;
+ int lwpid = (int)data;
if (!ISTID (tp->pid))
return 0;
@@ -383,13 +457,14 @@
return 1;
}
+/*
+ * If a thread is associated with lwp id LWPID, return the corresponding
+ * member of the global thread list; otherwise, return null.
+ */
static struct thread_info *
find_thread_lwp (int lwpid)
{
- /* The thread iterator will return the first thread_info
- for which the callback returns true. */
- return iterate_over_threads (find_thread_lwp_callback,
- (void *) lwpid);
+ return iterate_over_threads (find_thread_lwp_callback, (void *)lwpid);
}
/*
@@ -460,17 +535,10 @@
error ("failed to create new thread structure");
newthread->private = xmalloc (sizeof (struct private_thread_info));
- /*
- * newthread has been added to the global thread list by add_thread().
- * Set fields private to this module.
- */
- if (ISTID (pid))
- {
- newthread->private->stable = 1;
- newthread->private->thrid = thrid;
- newthread->private->lwpid = lwpid;
- newthread->private->mapp = mapp;
- }
+ newthread->private->stable = 1;
+ newthread->private->thrid = thrid;
+ newthread->private->lwpid = lwpid;
+ newthread->private->mapp = mapp;
if (target_has_execution)
printf_unfiltered ("[New %s]\n", target_pid_to_str (pid));
@@ -539,7 +607,7 @@
static void
uw_thread_detach (char *args, int from_tty)
{
- deactivate_uw_thread();
+ deactivate_uw_thread ();
base_ops.to_detach (args, from_tty);
}
@@ -557,9 +625,9 @@
}
/*
- * Return whether the trap we just received from lwp PID was due to a
- * breakpoint on the libthread.so debugging stub, updating data
- * structures accordingly if so.
+ * If the trap we just received from lwp PID was due to a breakpoint
+ * on the libthread.so debugging stub, update this module's state
+ * accordingly.
*/
static void
libthread_stub (int pid)
@@ -578,20 +646,20 @@
/* Retrieve stub args. */
sp = read_register_pid (SP_REGNUM, pid);
if (!base_ops.to_xfer_memory (sp + SP_ARG0, (char *)&mapp,
- sizeof (mapp), 0, &base_ops))
+ sizeof (mapp), 0, &base_ops))
goto err;
if (!base_ops.to_xfer_memory (sp + SP_ARG0 + sizeof (mapp), (char *)&change,
- sizeof (change), 0, &base_ops))
+ sizeof (change), 0, &base_ops))
goto err;
/* create_inferior() may not have finished yet, so notice the main
thread to ensure that it's displayed first by add_thread(). */
- mapp_main = find_main();
+ mapp_main = find_main ();
/* Notice thread creation, deletion, or stability change. */
switch (change) {
case tc_switch_begin:
- if (!mapp) /* null means main thread */
+ if (!mapp) /* usually means main thread */
mapp = mapp_main;
/* fall through */
@@ -617,6 +685,8 @@
case tc_thread_exit: /* thread has exited */
printf_unfiltered ("[Exited %s]\n", target_pid_to_str (tid));
delete_thread (tid);
+ if (tid == inferior_pid)
+ inferior_pid = pid;
break;
case tc_switch_begin: /* lwp is switching threads */
@@ -733,7 +803,7 @@
static void
uw_thread_prepare_to_store (void)
{
- CALL_BASE (base_ops.to_prepare_to_store());
+ CALL_BASE (base_ops.to_prepare_to_store ());
}
/*
@@ -744,10 +814,13 @@
static void
uw_thread_create_inferior (char *exec_file, char *allargs, char **env)
{
+ if (uw_thread_active)
+ deactivate_uw_thread ();
+
procfs_ops.to_create_inferior (exec_file, allargs, env);
if (uw_thread_active)
{
- find_main();
+ find_main ();
thr_infpid (NULL);
}
}
@@ -758,7 +831,7 @@
static void
uw_thread_kill (void)
{
- base_ops.to_kill();
+ base_ops.to_kill ();
}
/*
@@ -767,9 +840,9 @@
static void
uw_thread_mourn_inferior (void)
{
- remove_thread_event_breakpoints();
- deactivate_uw_thread();
- base_ops.to_mourn_inferior();
+ remove_thread_event_breakpoints ();
+ deactivate_uw_thread ();
+ base_ops.to_mourn_inferior ();
}
/*
@@ -799,17 +872,13 @@
/*
* Add to the thread list any threads and lwps it doesn't already contain.
- *
- * This is useful for a program's first thread, which doesn't generate a
- * tc_thread_create stub call, and for core file debugging.
*/
static void
uw_thread_find_new_threads (void)
{
CALL_BASE (if (base_ops.to_find_new_threads)
- base_ops.to_find_new_threads());
- if (procfs_suppress_run)
- notice_threads();
+ base_ops.to_find_new_threads ());
+ notice_threads ();
}
/*
@@ -820,18 +889,15 @@
uw_thread_pid_to_str (int pid)
{
#define FMT "Thread %d"
- static char buf[sizeof(FMT) + 3 * sizeof(pid)];
-
- if (!procfs_suppress_run)
- return procfs_ops.to_pid_to_str (pid);
+ static char buf[sizeof (FMT) + 3 * sizeof (pid)];
if (!ISTID (pid))
/* core_ops says "process foo", so call procfs_ops explicitly. */
return procfs_ops.to_pid_to_str (pid);
sprintf (buf, FMT, TIDGET (pid));
- return buf;
#undef FMT
+ return buf;
}
/*
@@ -881,13 +947,13 @@
}
/*
- * Check whether libthread.so has been loaded, and if so, try to initialize
- * user-space thread debugging support. Return success.
+ * Check whether libthread.so has just been loaded, and if so, try to
+ * initialize user-space thread debugging support.
*
* libthread.so loading happens while (a) an inferior process is being
* started by procfs and (b) a core image is being loaded.
*
- * This function may be called with uw_thread_active == 0.
+ * This function often gets called with uw_thread_active == 0.
*/
static void
libthread_init (void)
@@ -930,7 +996,7 @@
if (!target_has_execution)
/* Locate threads in core file. */
- notice_threads();
+ notice_threads ();
else
{
@@ -942,7 +1008,7 @@
/* Activate the stub function. */
onp = (CORE_ADDR)&((struct thread_debug *)thr_debug_addr)->thr_debug_on;
if (!base_ops.to_xfer_memory ((CORE_ADDR)onp, (char *)&one,
- sizeof (one), 1, &base_ops))
+ sizeof (one), 1, &base_ops))
{
delete_breakpoint (b);
goto err;
@@ -955,8 +1021,8 @@
return;
err:
- error ("uw-thread: error initializing thread debugging\n");
- deactivate_uw_thread();
+ warning ("uw-thread: unable to initialize user-mode thread debugging\n");
+ deactivate_uw_thread ();
}
/*
@@ -968,19 +1034,17 @@
* If OBJFILE is null, libthread.so has gone away, so stop debugging
* user-mode threads.
*
- * This function may be called with uw_thread_active == 0.
+ * This function often gets called with uw_thread_active == 0.
*/
static void
uw_thread_new_objfile (struct objfile *objfile)
{
- if (procfs_suppress_run)
- {
- if (objfile)
- libthread_init();
+ if (objfile)
+ libthread_init ();
- else if (uw_thread_active)
- deactivate_uw_thread();
- }
+ else if (uw_thread_active)
+ deactivate_uw_thread ();
+
if (target_new_objfile_chain)
target_new_objfile_chain (objfile);
}
@@ -1020,12 +1084,12 @@
void
_initialize_uw_thread (void)
{
- init_uw_thread_ops();
+ init_uw_thread_ops ();
add_target (&uw_thread_ops);
procfs_suppress_run = 1;
/* Notice when libthread.so gets loaded. */
target_new_objfile_chain = target_new_objfile_hook;
- target_new_objfile_hook = uw_thread_new_objfile;
+ target_new_objfile_hook = uw_thread_new_objfile;
}