Date: Fri, 24 Sep 1999 08:21:04 +0100 (BST) From: Doug Rabson <dfr@nlsystems.com> To: Kip Macy <kip@lyris.com> Cc: freebsd-current@freebsd.org Subject: Re: freebsd-uthread.c Message-ID: <Pine.BSF.4.10.9909240810100.325-100000@salmon.nlsystems.com> In-Reply-To: <Pine.SOL.4.05.9909232100160.13300-100000@luna>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 23 Sep 1999, Kip Macy wrote: > > In three places in your code you do the following or something similar: > ptr = (CORE_ADDR) cached_pthread.nxt; > > struct pthread has no member nxt in either -current or -stable > and your patch did not add it to pthread_private.h > What did you mean for this to be? This field changed after I generated the patch. Here is the latest diff against -current (not sure if it will work in -stable): Index: Makefile =================================================================== RCS file: /home/ncvs/src/gnu/usr.bin/binutils/gdb/Makefile,v retrieving revision 1.43 diff -u -r1.43 Makefile --- Makefile 1999/08/27 23:34:48 1.43 +++ Makefile 1999/09/05 21:59:39 @@ -8,20 +8,20 @@ XSRCS= annotate.c ax-general.c ax-gdb.c bcache.c blockframe.c \ breakpoint.c buildsym.c c-exp.y c-lang.c c-typeprint.c \ c-valprint.c ch-exp.c ch-lang.c ch-typeprint.c ch-valprint.c \ - coffread.c command.c complaints.c copying.c corefile.c \ - corelow.c core-regset.c cp-valprint.c dcache.c dbxread.c demangle.c \ - dwarfread.c dwarf2read.c elfread.c environ.c eval.c exec.c \ - expprint.c f-exp.y f-lang.c f-typeprint.c f-valprint.c \ - findvar.c fork-child.c gdbarch.c gdbtypes.c infcmd.c inflow.c \ - infptrace.c infrun.c inftarg.c language.c jv-exp.y jv-lang.c \ - jv-valprint.c jv-typeprint.c nlmread.c m2-lang.c m2-exp.y \ - m2-typeprint.c m2-valprint.c main.c maint.c mdebugread.c \ - mem-break.c minsyms.c objfiles.c parse.c printcmd.c remote.c \ - remote-utils.c scm-exp.c scm-lang.c scm-valprint.c solib.c \ - source.c stabsread.c stack.c symfile.c symmisc.c symtab.c \ - target.c thread.c top.c tracepoint.c typeprint.c utils.c \ - valarith.c valops.c valprint.c values.c version.c serial.c \ - ser-unix.c ser-tcp.c callback.c + coffread.c command.c complaints.c copying.c core-regset.c \ + corefile.c corelow.c cp-valprint.c dcache.c dbxread.c \ + demangle.c dwarfread.c dwarf2read.c elfread.c environ.c eval.c \ + exec.c expprint.c f-exp.y f-lang.c f-typeprint.c f-valprint.c \ + findvar.c fork-child.c freebsd-uthread.c gdbarch.c gdbtypes.c \ + infcmd.c inflow.c infptrace.c infrun.c inftarg.c language.c \ + jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c nlmread.c \ + m2-lang.c m2-exp.y m2-typeprint.c m2-valprint.c main.c maint.c \ + mdebugread.c mem-break.c minsyms.c objfiles.c parse.c \ + printcmd.c remote.c remote-utils.c scm-exp.c scm-lang.c \ + scm-valprint.c solib.c source.c stabsread.c stack.c symfile.c \ + symmisc.c symtab.c target.c thread.c top.c tracepoint.c \ + typeprint.c utils.c valarith.c valops.c valprint.c values.c \ + version.c serial.c ser-unix.c ser-tcp.c callback.c SRCS= init.c ${XSRCS} .if exists(${.CURDIR}/Makefile.${MACHINE_ARCH}) @@ -34,6 +34,8 @@ CFLAGS+= -I${SRCDIR}/bfd CFLAGS+= -I${GDBDIR}/gdb CFLAGS+= -I${GDBDIR}/gdb/config +CFLAGS+= -I${.CURDIR}/../../../../lib/libc_r/uthread #pthread_private.h +CFLAGS+= -I${.CURDIR}/../../../../lib/libc/include #spinlock.h LDADD+= -L${RELTOP}/libbfd -lbfd LDADD+= -L${RELTOP}/libopcodes -lopcodes LDADD+= -lreadline Index: freebsd-uthread.c =================================================================== RCS file: freebsd-uthread.c diff -N freebsd-uthread.c --- /dev/null Fri Sep 24 08:17:20 1999 +++ freebsd-uthread.c Wed Aug 18 06:28:01 1999 @@ -0,0 +1,1005 @@ +/* Low level interface for debugging FreeBSD user threads for GDB, the GNU debugger. + Copyright 1996, 1999 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This module implements a sort of half target that sits between the + machine-independent parts of GDB and the ptrace interface (infptrace.c) to + provide access to the FreeBSD user-mode thread implementation. + + FreeBSD threads are true user-mode threads, which are invoked via + the pthread_* interfaces. These are mostly implemented in + user-space, with all thread context kept in various structures that + live in the user's heap. For the most part, the kernel has no + knowlege of these threads. + + Based largely on hpux-thread.c + + */ + + +#include "defs.h" +#define PTHREAD_KERNEL +#include <pthread.h> +#include "pthread_private.h" +#include "gdbthread.h" +#include "target.h" +#include "inferior.h" +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include "gdbcore.h" + +extern int child_suppress_run; +extern struct target_ops child_ops; /* target vector for inftarg.c */ + +extern void _initialize_freebsd_uthread PARAMS ((void)); + +static int main_pid = -1; /* Real process ID */ + +/* Set to true while we are part-way through attaching */ +static int freebsd_uthread_attaching; + +static int freebsd_uthread_active = 0; +static CORE_ADDR P_thread_list; +static CORE_ADDR P_thread_run; + +static struct cleanup * save_inferior_pid PARAMS ((void)); + +static void restore_inferior_pid PARAMS ((int pid)); + +static void freebsd_uthread_resume PARAMS ((int pid, int step, + enum target_signal signo)); + +static void init_freebsd_uthread_ops PARAMS ((void)); + +static struct target_ops freebsd_uthread_ops; +static struct target_thread_vector freebsd_uthread_vec; + +/* + +LOCAL FUNCTION + + save_inferior_pid - Save inferior_pid on the cleanup list + restore_inferior_pid - Restore inferior_pid from the cleanup list + +SYNOPSIS + + struct cleanup *save_inferior_pid () + void restore_inferior_pid (int pid) + +DESCRIPTION + + These two functions act in unison to restore inferior_pid in + case of an error. + +NOTES + + inferior_pid is a global variable that needs to be changed by many of + these routines before calling functions in procfs.c. In order to + guarantee that inferior_pid gets restored (in case of errors), you + need to call save_inferior_pid before changing it. At the end of the + function, you should invoke do_cleanups to restore it. + + */ + +static struct cleanup * +save_inferior_pid () +{ + return make_cleanup ((make_cleanup_func) restore_inferior_pid, + (void *) inferior_pid); +} + +static void +restore_inferior_pid (pid) + int pid; +{ + inferior_pid = pid; +} + +static int find_active_thread PARAMS ((void)); + +static int cached_thread; +static struct pthread cached_pthread; +static CORE_ADDR cached_pthread_addr; + +#define THREADID_TID(id) ((id) >> 17) +#define THREADID_PID(id) ((id) & ((1 << 17) - 1)) + +LIST_HEAD(idmaplist, idmap); + +struct idmap { + LIST_ENTRY(idmap) link; + u_int64_t uniqueid; + int tid; +}; + +#define MAPHASH_SIZE 257 +#define TID_MIN 1 +#define TID_MAX 16383 + +static int tid_to_hash[TID_MAX + 1]; /* set to map_hash index */ +static struct idmaplist map_hash[MAPHASH_SIZE]; +static int next_free_tid = TID_MIN; /* first available tid */ +static int last_free_tid = TID_MIN; /* first unavailable */ + +#define UNIQUEID_HASH(id) (id % MAPHASH_SIZE) +#define TID_ADD1(tid) (((tid) + 1) == TID_MAX + 1 \ + ? TID_MIN : (tid) + 1) +#define IS_TID_FREE(tid) (tid_to_hash[tid] == -1) + +static int +get_new_tid(h) + int h; +{ + int tid = next_free_tid; + + tid_to_hash[tid] = h; + next_free_tid = TID_ADD1(next_free_tid); + if (next_free_tid == last_free_tid) + { + int i; + + for (i = last_free_tid; TID_ADD1(i) != last_free_tid; i = TID_ADD1(i)) + if (IS_TID_FREE(i)) + break; + if (TID_ADD1(i) == last_free_tid) + { + error("too many threads"); + return 0; + } + next_free_tid = i; + for (i = TID_ADD1(i); IS_TID_FREE(i); i = TID_ADD1(i)) + ; + last_free_tid = i; + } + + return tid; +} + +static int +find_pid(thread) + struct pthread *thread; +{ + int h = UNIQUEID_HASH(thread->uniqueid); + struct idmap *im; + + LIST_FOREACH(im, &map_hash[h], link) + if (im->uniqueid == thread->uniqueid) + return (im->tid << 17) + main_pid; + + im = xmalloc(sizeof(struct idmap)); + im->uniqueid = thread->uniqueid; + im->tid = get_new_tid(h); + LIST_INSERT_HEAD(&map_hash[h], im, link); + + return (im->tid << 17) + main_pid; +} + +static void +free_pid(pid) + int pid; +{ + int tid = THREADID_TID(pid); + int h = tid_to_hash[tid]; + struct idmap *im; + + if (!tid) return; + + LIST_FOREACH(im, &map_hash[h], link) + if (im->tid == tid) + break; + + if (!im) return; + + LIST_REMOVE(im, link); + tid_to_hash[tid] = -1; + free(im); +} + +static int +find_active_thread () +{ + static struct pthread pthread; + CORE_ADDR ptr; + + if (main_pid == -1) + return -1; + + read_memory ((CORE_ADDR)P_thread_run, + (char *)&ptr, + sizeof ptr); + + read_memory (ptr, (char *)&pthread, sizeof pthread); + + return find_pid(&pthread); +} + +static CORE_ADDR find_pthread_addr PARAMS ((int thread)); +static struct pthread * find_pthread PARAMS ((int thread)); + +static CORE_ADDR +find_pthread_addr (thread) + int thread; +{ + CORE_ADDR ptr; + + if (thread == cached_thread) + return cached_pthread_addr; + + read_memory ((CORE_ADDR)P_thread_list, + (char *)&ptr, + sizeof ptr); + + while (ptr != 0) + { + read_memory (ptr, (char*)&cached_pthread, sizeof cached_pthread); + + if (find_pid(&cached_pthread) == thread) + { + cached_thread = thread; + cached_pthread_addr = ptr; + return ptr; + } + ptr = (CORE_ADDR) cached_pthread.tle.tqe_next; + } + +#if 0 + error ("Can't find pthread %d,%d", + THREADID_TID(thread), THREADID_PID(thread)); +#endif + return NULL; +} + +static struct pthread * +find_pthread (thread) + int thread; +{ + CORE_ADDR ptr; + + if (thread == cached_thread) + return &cached_pthread; + + read_memory ((CORE_ADDR)P_thread_list, + (char *)&ptr, + sizeof ptr); + + while (ptr != 0) + { + read_memory (ptr, (char*)&cached_pthread, sizeof cached_pthread); + + if (find_pid(&cached_pthread) == thread) + { + cached_thread = thread; + cached_pthread_addr = ptr; + return &cached_pthread; + } + ptr = (CORE_ADDR) cached_pthread.tle.tqe_next; + + } + + error ("Can't find pthread %d,%d", + THREADID_TID(thread), THREADID_PID(thread)); + return NULL; +} + + +/* Most target vector functions from here on actually just pass through to + inftarg.c, as they don't need to do anything specific for threads. */ + +/* ARGSUSED */ +static void +freebsd_uthread_open (arg, from_tty) + char *arg; + int from_tty; +{ + child_ops.to_open (arg, from_tty); +} + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ + +static void +freebsd_uthread_attach (args, from_tty) + char *args; + int from_tty; +{ + child_ops.to_attach (args, from_tty); + push_target (&freebsd_uthread_ops); + freebsd_uthread_attaching = 1; +} + +/* After an attach, see if the target is threaded */ + +static void +freebsd_uthread_post_attach (pid) + int pid; +{ + if (freebsd_uthread_active) + { + main_pid = pid; + + bind_target_thread_vector (&freebsd_uthread_vec); + + inferior_pid = find_active_thread (); + + add_thread (inferior_pid); + } + else + { + unpush_target (&freebsd_uthread_ops); + push_target (&child_ops); + } + + freebsd_uthread_attaching = 0; +} + +/* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + +static void +freebsd_uthread_detach (args, from_tty) + char *args; + int from_tty; +{ + child_ops.to_detach (args, from_tty); +} + +/* Resume execution of process PID. If STEP is nozero, then + just single step it. If SIGNAL is nonzero, restart it with that + signal activated. We may have to convert pid from a thread-id to an LWP id + for procfs. */ + +static void +freebsd_uthread_resume (pid, step, signo) + int pid; + int step; + enum target_signal signo; +{ + struct cleanup *old_chain; + + if (freebsd_uthread_attaching) + { + child_ops.to_resume (pid, step, signo); + return; + } + + old_chain = save_inferior_pid (); + + pid = inferior_pid = main_pid; + + child_ops.to_resume (pid, step, signo); + + cached_thread = 0; + + do_cleanups (old_chain); +} + +/* Wait for any threads to stop. We may have to convert PID from a thread id + to a LWP id, and vice versa on the way out. */ + +static int +freebsd_uthread_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + int rtnval; + struct cleanup *old_chain; + + if (freebsd_uthread_attaching) + { + return child_ops.to_wait (pid, ourstatus); + } + + old_chain = save_inferior_pid (); + + inferior_pid = main_pid; + + if (pid != -1) + pid = main_pid; + + rtnval = child_ops.to_wait (pid, ourstatus); + + if (rtnval >= 0) + { + rtnval = find_active_thread (); + if (!in_thread_list (rtnval)) + add_thread (rtnval); + } + + do_cleanups (old_chain); + + return rtnval; +} + +#ifdef __i386__ + +static char sigmap[NUM_REGS] = /* map reg to sigcontext */ +{ + 16, /* eax */ + 15, /* ecx */ + 14, /* edx */ + 13, /* ebx */ + 2, /* esp */ + 3, /* ebp */ + 12, /* esi */ + 11, /* edi */ + 5, /* eip */ + 6, /* eflags */ + 9, /* cs */ + 10, /* ss */ + 8, /* ds */ + 7, /* es */ + 18, /* fs */ + 17, /* gs */ +}; + +static char jmpmap[NUM_REGS] = /* map reg to jmp_buf */ +{ + 6, /* eax */ + -1, /* ecx */ + -1, /* edx */ + 1, /* ebx */ + 2, /* esp */ + 3, /* ebp */ + 4, /* esi */ + 5, /* edi */ + 0, /* eip */ + -1, /* eflags */ + -1, /* cs */ + -1, /* ss */ + -1, /* ds */ + -1, /* es */ + -1, /* fs */ + -1, /* gs */ +}; + +#endif + +#ifdef __alpha__ + +static char sigmap[NUM_REGS] = /* map reg to sigcontext */ +{ + 4, 5, 6, 7, 8, 9, 10, 11, /* v0 - t6 */ + 12, 13, 14, 15, 16, 17, 18, 19, /* t7 - fp */ + 20, 21, 22, 23, 24, 25, 26, 27, /* a0 - t9 */ + 28, 29, 30, 31, 32, 33, 34, 35, /* t10 - zero */ + 37, 38, 39, 40, 41, 42, 43, 44, /* f0 - f7 */ + 45, 46, 47, 48, 49, 50, 51, 52, /* f8 - f15 */ + 53, 54, 55, 56, 57, 58, 59, 60, /* f16 - f23 */ + 61, 62, 63, 64, 65, 66, 67, 68, /* f24 - f31 */ + 2, -1, /* pc, vfp */ +}; + +/* alpha jmp_buf is the same layout as sigcontext */ +#define jmpmap sigmap + +#endif + +static void +freebsd_uthread_fetch_registers (regno) + int regno; +{ + struct pthread *thread; + struct cleanup *old_chain; + int i; + int active; + int first_regno, last_regno; + u_int32_t *regbase; + char *regmap; + + if (freebsd_uthread_attaching) + { + child_ops.to_fetch_registers (regno); + return; + } + + thread = find_pthread (inferior_pid); + + old_chain = save_inferior_pid (); + + active = (inferior_pid == find_active_thread()); + + inferior_pid = main_pid; + + if (active) + { + child_ops.to_fetch_registers (regno); + + do_cleanups (old_chain); + + return; + } + + if (regno == -1) + { + first_regno = 0; + last_regno = NUM_REGS - 1; + } + else + { + first_regno = regno; + last_regno = regno; + } + + if (thread->sig_saved) + { + regbase = (u_int32_t*) &thread->saved_sigcontext; + regmap = sigmap; + } + else + { + regbase = (u_int32_t*) &thread->saved_jmp_buf[0]; + regmap = jmpmap; + } + + for (regno = first_regno; regno <= last_regno; regno++) + { + if (regmap[regno] == -1) + child_ops.to_fetch_registers (regno); + else + supply_register (regno, (char*) ®base[regmap[regno]]); + } + + do_cleanups (old_chain); +} + +static void +freebsd_uthread_store_registers (regno) + int regno; +{ + struct pthread *thread; + CORE_ADDR ptr; + struct cleanup *old_chain; + int i; + int first_regno, last_regno; + u_int32_t *regbase; + char *regmap; + + if (freebsd_uthread_attaching) + { + child_ops.to_store_registers (regno); + return; + } + + thread = find_pthread (inferior_pid); + + old_chain = save_inferior_pid (); + + inferior_pid = main_pid; + + if (thread->state == PS_RUNNING) + { + child_ops.to_store_registers (regno); + + do_cleanups (old_chain); + + return; + } + + if (regno == -1) + { + first_regno = 0; + last_regno = NUM_REGS - 1; + } + else + { + first_regno = regno; + last_regno = regno; + } + + if (thread->sig_saved) + { + regbase = (u_int32_t*) &thread->saved_sigcontext; + regmap = sigmap; + } + else + { + regbase = (u_int32_t*) &thread->saved_jmp_buf[0]; + regmap = jmpmap; + } + + ptr = find_pthread_addr (inferior_pid); + for (regno = first_regno; regno <= last_regno; regno++) + { + if (regmap[regno] == -1) + child_ops.to_store_registers (regno); + else + { + u_int32_t *reg = ®base[regmap[regno]]; + int off; + + /* Hang onto cached value */ + memcpy(reg, registers + REGISTER_BYTE (regno), + REGISTER_RAW_SIZE (regno)); + + /* And push out to inferior */ + off = (char *) reg - (char *) thread; + write_memory (ptr + off, + registers + REGISTER_BYTE (regno), + REGISTER_RAW_SIZE (regno)); + } + } + + do_cleanups (old_chain); +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +freebsd_uthread_prepare_to_store () +{ + struct cleanup *old_chain; + + if (freebsd_uthread_attaching) + { + child_ops.to_prepare_to_store (); + return; + } + + old_chain = save_inferior_pid (); + inferior_pid = main_pid; + + child_ops.to_prepare_to_store (); + + do_cleanups (old_chain); +} + +static int +freebsd_uthread_xfer_memory (memaddr, myaddr, len, dowrite, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int dowrite; + struct target_ops *target; /* ignored */ +{ + int retval; + struct cleanup *old_chain; + + if (freebsd_uthread_attaching) + { + return child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, target); + } + + old_chain = save_inferior_pid (); + + inferior_pid = main_pid; + + retval = child_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, target); + + do_cleanups (old_chain); + + return retval; +} + +/* Print status information about what we're accessing. */ + +static void +freebsd_uthread_files_info (ignore) + struct target_ops *ignore; +{ + child_ops.to_files_info (ignore); +} + +static void +freebsd_uthread_kill_inferior () +{ + inferior_pid = main_pid; + child_ops.to_kill (); +} + +static void +freebsd_uthread_notice_signals (pid) + int pid; +{ + struct cleanup *old_chain; + old_chain = save_inferior_pid (); + inferior_pid = main_pid; + + child_ops.to_notice_signals (pid); + + do_cleanups (old_chain); +} + +/* Fork an inferior process, and start debugging it with /proc. */ + +static void +freebsd_uthread_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + child_ops.to_create_inferior (exec_file, allargs, env); + + if (inferior_pid && freebsd_uthread_active) + { + main_pid = inferior_pid; + + push_target (&freebsd_uthread_ops); + bind_target_thread_vector (&freebsd_uthread_vec); + + inferior_pid = find_active_thread (); + + add_thread (inferior_pid); + } +} + +/* This routine is called to find out if the inferior is using threads. + We check for the _thread_run and _thread_list globals. */ + +void +freebsd_uthread_new_objfile (objfile) + struct objfile *objfile; +{ + struct minimal_symbol *ms; + + if (!objfile) + { + freebsd_uthread_active = 0; + return; + } + + ms = lookup_minimal_symbol ("_thread_run", NULL, objfile); + + if (!ms) + return; + + P_thread_run = SYMBOL_VALUE_ADDRESS (ms); + + ms = lookup_minimal_symbol ("_thread_list", NULL, objfile); + + if (!ms) + return; + + P_thread_list = SYMBOL_VALUE_ADDRESS (ms); + + freebsd_uthread_active = 1; +} + +int +freebsd_uthread_has_exited (pid, wait_status, exit_status) + int pid; + int wait_status; + int * exit_status; +{ + int t = child_ops.to_has_exited (pid, wait_status, exit_status); + if (t) + main_pid = -1; + return t; +} + +/* Clean up after the inferior dies. */ + +static void +freebsd_uthread_mourn_inferior () +{ + inferior_pid = main_pid; /* don't bother to restore inferior_pid */ + child_ops.to_mourn_inferior (); + unpush_target (&freebsd_uthread_ops); +} + +/* Mark our target-struct as eligible for stray "run" and "attach" commands. */ + +static int +freebsd_uthread_can_run () +{ + return child_suppress_run; +} + +static int +freebsd_uthread_thread_alive (pid) + int pid; +{ + struct cleanup *old_chain; + struct pthread *thread; + int ret = 0; + + if (freebsd_uthread_attaching) + return 1; + + /* + * We can get called from child_ops.to_wait() which passes the underlying + * pid (without a thread number). + */ + if (THREADID_TID(pid) == 0) + return 1; + + old_chain = save_inferior_pid (); + inferior_pid = main_pid; + + if (find_pthread_addr (pid) != 0) + { + thread = find_pthread (pid); + ret = (thread->state != PS_DEAD); + } + + do_cleanups (old_chain); + + if (!ret) + free_pid(pid); + + return ret; +} + +static void +freebsd_uthread_stop () +{ + struct cleanup *old_chain; + old_chain = save_inferior_pid (); + inferior_pid = main_pid; + + child_ops.to_stop (); + + do_cleanups (old_chain); +} + +static int +freebsd_uthread_find_new_threads () +{ + CORE_ADDR ptr; + struct pthread pthread; + struct cleanup *old_chain; + + old_chain = save_inferior_pid (); + inferior_pid = main_pid; + + read_memory ((CORE_ADDR)P_thread_list, + (char *)&ptr, + sizeof ptr); + + while (ptr != 0) + { + read_memory (ptr, (char*)&pthread, sizeof pthread); + + if (pthread.state != PS_DEAD && + !in_thread_list (find_pid(&pthread))) + add_thread (find_pid(&pthread)); + ptr = (CORE_ADDR) pthread.tle.tqe_next; + } + + do_cleanups (old_chain); + + return 0; +} + +/* MUST MATCH enum pthread_state */ +static const char *statenames[] = { + "RUNNING", + "SIGTHREAD", + "MUTEX_WAIT", + "COND_WAIT", + "FDLR_WAIT", + "FDLW_WAIT", + "FDR_WAIT", + "FDW_WAIT", + "FILE_WAIT", + "SELECT_WAIT", + "SLEEP_WAIT", + "WAIT_WAIT", + "SIGSUSPEND", + "SIGWAIT", + "SPINBLOCK", + "JOIN", + "SUSPENDED", + "DEAD", + "DEADLOCK", +}; + +static int +freebsd_uthread_get_thread_info (ref, selection, info) + gdb_threadref *ref; + int selection; + struct gdb_ext_thread_info *info; +{ + int pid = *ref; + struct pthread *thread = find_pthread (pid); + struct cleanup *old_chain; + + old_chain = save_inferior_pid (); + inferior_pid = main_pid; + + memset(&info->threadid, 0, OPAQUETHREADBYTES); + + memcpy(&info->threadid, ref, sizeof *ref); + info->active = thread->state == PS_RUNNING; + strcpy(info->display, statenames[thread->state]); + if (thread->name) + read_memory ((CORE_ADDR) thread->name, info->shortname, 32); + else + strcpy(info->shortname, ""); + + do_cleanups (old_chain); +} + +char * +freebsd_uthread_pid_to_str (pid) + int pid; +{ + static char buf[30]; + + if (STREQ (current_target.to_shortname, "freebsd-uthreads")) + sprintf (buf, "process %d, thread %d\0", + THREADID_PID(pid), THREADID_TID(pid)); + else + sprintf (buf, "process %d\0", pid); + + return buf; +} + + +static void +init_freebsd_uthread_ops () +{ + freebsd_uthread_ops.to_shortname = "freebsd-uthreads"; + freebsd_uthread_ops.to_longname = "FreeBSD uthreads"; + freebsd_uthread_ops.to_doc = "FreeBSD user threads support."; + freebsd_uthread_ops.to_open = freebsd_uthread_open; + freebsd_uthread_ops.to_attach = freebsd_uthread_attach; + freebsd_uthread_ops.to_post_attach = freebsd_uthread_post_attach; + freebsd_uthread_ops.to_detach = freebsd_uthread_detach; + freebsd_uthread_ops.to_resume = freebsd_uthread_resume; + freebsd_uthread_ops.to_wait = freebsd_uthread_wait; + freebsd_uthread_ops.to_fetch_registers = freebsd_uthread_fetch_registers; + freebsd_uthread_ops.to_store_registers = freebsd_uthread_store_registers; + freebsd_uthread_ops.to_prepare_to_store = freebsd_uthread_prepare_to_store; + freebsd_uthread_ops.to_xfer_memory = freebsd_uthread_xfer_memory; + freebsd_uthread_ops.to_files_info = freebsd_uthread_files_info; + freebsd_uthread_ops.to_insert_breakpoint = memory_insert_breakpoint; + freebsd_uthread_ops.to_remove_breakpoint = memory_remove_breakpoint; + freebsd_uthread_ops.to_terminal_init = terminal_init_inferior; + freebsd_uthread_ops.to_terminal_inferior = terminal_inferior; + freebsd_uthread_ops.to_terminal_ours_for_output = terminal_ours_for_output; + freebsd_uthread_ops.to_terminal_ours = terminal_ours; + freebsd_uthread_ops.to_terminal_info = child_terminal_info; + freebsd_uthread_ops.to_kill = freebsd_uthread_kill_inferior; + freebsd_uthread_ops.to_create_inferior = freebsd_uthread_create_inferior; + freebsd_uthread_ops.to_has_exited = freebsd_uthread_has_exited; + freebsd_uthread_ops.to_mourn_inferior = freebsd_uthread_mourn_inferior; + freebsd_uthread_ops.to_can_run = freebsd_uthread_can_run; + freebsd_uthread_ops.to_notice_signals = freebsd_uthread_notice_signals; + freebsd_uthread_ops.to_thread_alive = freebsd_uthread_thread_alive; + freebsd_uthread_ops.to_stop = freebsd_uthread_stop; + freebsd_uthread_ops.to_stratum = process_stratum; + freebsd_uthread_ops.to_has_all_memory = 1; + freebsd_uthread_ops.to_has_memory = 1; + freebsd_uthread_ops.to_has_stack = 1; + freebsd_uthread_ops.to_has_registers = 1; + freebsd_uthread_ops.to_has_execution = 1; + freebsd_uthread_ops.to_has_thread_control = 0; + freebsd_uthread_ops.to_magic = OPS_MAGIC; + + freebsd_uthread_vec.find_new_threads = freebsd_uthread_find_new_threads; + freebsd_uthread_vec.get_thread_info = freebsd_uthread_get_thread_info; +} + +void +_initialize_freebsd_uthread () +{ + init_freebsd_uthread_ops (); + add_target (&freebsd_uthread_ops); + + child_suppress_run = 1; +} Index: alpha/tm.h =================================================================== RCS file: /home/ncvs/src/gnu/usr.bin/binutils/gdb/alpha/tm.h,v retrieving revision 1.2 diff -u -r1.2 tm.h --- tm.h 1999/06/21 15:00:14 1.2 +++ tm.h 1999/07/20 13:45:50 @@ -34,4 +34,11 @@ #undef START_INFERIOR_TRAPS_EXPECTED #define START_INFERIOR_TRAPS_EXPECTED 2 +struct objfile; +void freebsd_uthread_new_objfile PARAMS ((struct objfile *objfile)); +#define target_new_objfile(OBJFILE) freebsd_uthread_new_objfile (OBJFILE) + +extern char *freebsd_uthread_pid_to_str PARAMS ((int pid)); +#define target_pid_to_str(PID) freebsd_uthread_pid_to_str (PID) + #endif /* TM_FREEBSDALPHA_H */ Index: i386/freebsd-nat.c =================================================================== RCS file: /home/ncvs/src/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c,v retrieving revision 1.21 diff -u -r1.21 freebsd-nat.c --- freebsd-nat.c 1999/05/02 11:32:10 1.21 +++ freebsd-nat.c 1999/08/18 05:28:34 @@ -345,20 +345,9 @@ uaddr = (char *)&U_FPSTATE(u) - (char *)&u; if (inferior_pid != 0 && core_bfd == NULL) { - int *ip; - - rounded_addr = uaddr & -sizeof (int); - rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + - sizeof (int) - 1) / sizeof (int); - skip = uaddr - rounded_addr; - - ip = (int *)buf; - for (i = 0; i < rounded_size; i++) - { - *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0); - rounded_addr += sizeof (int); - } - fpstatep = (struct fpstate *)(buf + skip); + int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */ + ptrace(PT_GETFPREGS, pid, &buf[0], sizeof(struct fpreg)); + fpstatep = (struct fpstate *)&buf[0]; } else fpstatep = &pcb_savefpu; Index: i386/tm.h =================================================================== RCS file: /home/ncvs/src/gnu/usr.bin/binutils/gdb/i386/tm.h,v retrieving revision 1.12 diff -u -r1.12 tm.h --- tm.h 1999/06/13 19:41:50 1.12 +++ tm.h 1999/07/20 13:45:50 @@ -55,4 +55,11 @@ #define SIGTRAMP_START(pc) 0xbfbfdfd8 #define SIGTRAMP_END(pc) 0xbfbfdff0 +struct objfile; +void freebsd_uthread_new_objfile PARAMS ((struct objfile *objfile)); +#define target_new_objfile(OBJFILE) freebsd_uthread_new_objfile (OBJFILE) + +extern char *freebsd_uthread_pid_to_str PARAMS ((int pid)); +#define target_pid_to_str(PID) freebsd_uthread_pid_to_str (PID) + #endif /* ifndef TM_FBSD_H */ -- Doug Rabson Mail: dfr@nlsystems.com Nonlinear Systems Ltd. Phone: +44 181 442 9037 To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.10.9909240810100.325-100000>