From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10147 invoked by alias); 4 Nov 2004 18:25:44 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 10131 invoked from network); 4 Nov 2004 18:25:41 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org with SMTP; 4 Nov 2004 18:25:41 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.11/8.12.11) with ESMTP id iA4IPai7005397 for ; Thu, 4 Nov 2004 13:25:41 -0500 Received: from pobox.toronto.redhat.com (pobox.toronto.redhat.com [172.16.14.4]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id iA4IPar29101; Thu, 4 Nov 2004 13:25:36 -0500 Received: from touchme.toronto.redhat.com (IDENT:postfix@touchme.toronto.redhat.com [172.16.14.9]) by pobox.toronto.redhat.com (8.12.8/8.12.8) with ESMTP id iA4IPXbU024359; Thu, 4 Nov 2004 13:25:35 -0500 Received: from redhat.com (toocool.toronto.redhat.com [172.16.14.72]) by touchme.toronto.redhat.com (Postfix) with ESMTP id D9FF980002E; Thu, 4 Nov 2004 13:25:32 -0500 (EST) Message-ID: <418A741C.4080306@redhat.com> Date: Thu, 04 Nov 2004 18:25:00 -0000 From: Jeff Johnston User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 MIME-Version: 1.0 To: Eli Zaretskii Cc: drow@false.org, cagney@gnu.org, gdb-patches@sources.redhat.com Subject: Re: [RFA]: Watchpoints per thread patch References: <4175A9C9.8040300@redhat.com> <41769FF3.7010801@gnu.org> <20041020173035.GA26622@nevyn.them.org> <418022DE.204@redhat.com> <01c4bca9$Blat.v2.2.2$adcffb00@zahav.net.il> In-Reply-To: <01c4bca9$Blat.v2.2.2$adcffb00@zahav.net.il> Content-Type: multipart/mixed; boundary="------------070203080606030801070906" X-SW-Source: 2004-11/txt/msg00064.txt.bz2 This is a multi-part message in MIME format. --------------070203080606030801070906 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Content-length: 6455 Eli Zaretskii wrote: >>Date: Wed, 27 Oct 2004 18:36:14 -0400 >>From: Jeff Johnston >>Cc: Andrew Cagney , gdb-patches@sources.redhat.com >> >>The attached patch is the rework of my original attempt. It no longer uses >>configuration or magic defines. Per Mark's suggestion, it uses an observer to >>handle inserting watchpoints on a new thread and only the low-level code knows >>about inserting/removing watchpoints on all threads. >> >>Ok to commit? > > > A few comments: > > >>+/* External function to insert all existing watchpoints on a newly >>+ attached thread. IWPFN is a callback function to perform >>+ the target insert watchpoint. This function is used to support >>+ platforms whereby a watchpoint must be inserted/removed on each >>+ individual thread (e.g. ia64-linux and s390-linux). For >>+ ia64 and s390 linux, this function is called via a new thread >>+ observer. */ > > > In this comment, the word "whereby" should be replaced by "where", I > think. > Ok, done. > >>--- target.h 8 Oct 2004 20:29:55 -0000 1.65 >>+++ target.h 27 Oct 2004 21:43:51 -0000 >>@@ -178,6 +178,15 @@ extern char *target_signal_to_name (enum >> /* Given a name (SIGHUP, etc.), return its signal. */ >> enum target_signal target_signal_from_name (char *); >> >>+ >>+/* Watchpoint specification. */ >>+struct target_watchpoint >>+ { >>+ CORE_ADDR addr; >>+ int len; >>+ int type; >>+ }; >>+ > > > Why do we put on target.h, which is a general header, a definition of > a struct used only on certain platforms? > I have moved this to linux-nat.h and renamed it struct linux_watchpoint. > >>--- doc/observer.texi 1 Sep 2004 17:59:37 -0000 1.8 >>+++ doc/observer.texi 27 Oct 2004 21:43:51 -0000 >>@@ -95,3 +95,7 @@ inferior, and before any information on >> The specified shared library has been discovered to be unloaded. >> @end deftypefun >> >>+@deftypefun void new_thread (ptid_t @var{ptid}) >>+A new thread has been attached to. > > > "A new thread has been attached" to what? The description of the > observer should at least reference the argument @var{ptid}. > I have changed the definition to be more meaningful now that it is being used generically by all. On Thu, Oct 28, 2004 at 03:47:22PM -0400, Jeff Johnston wrote: >> Daniel Jacobowitz wrote: > >>> >On Wed, Oct 27, 2004 at 07:17:13PM -0400, Jeff Johnston wrote: >>> > >> >>>> >>Were you thinking of add_thread()? If so, we would have to move the >>>> >>calls to add_thread so they never occur before an attach because the >>>> >>low-level observers will need the thread already attached. >> >>> > >>> > >>> >Oh, that's a good point. Do you think that's a reasonable change to >>> >make? >>> > > >> Daniel, I have moved the observer notification to add_thread as suggested. To do this, I had to move a few things in attach_thread. As well, I had to add another part of my full patch in because the ptid that add_thread knows about is in the wrong format (pid, 0, tid). The low-level insert watchpoint code needs the lwp so I have added in my target_get_lwp change. I realize you have plans to change how the ptid is kept, but until that is fleshed out, this change is required. I used a call-back to allow breakpoint.c which knows how to handle watchpoints to communicate with the low-level linux code that knows how to insert/remove a watchpoint. I have tested on ia64 and s390 linux. The ia64 requires another patch to make it pass the watchthreads.exp test. S390 linux can't pass that test without additional hardware support, however, I will note that s390 is properly recognizing hardware watchpoints on threads which is a major step forward. Ok to commit? 2004-11-04 Jeff Johnston * breakpoint.c (insert_watchpoints_for_new_thread): New function. (print_it_typical): Do not issue an error for bp_thread_event if a subsequent event is on the chain. * breakpoint.h (insert_watchpoints_for_new_thread): New prototype. * ia64-linux-nat.c (ia64_linux_insert_one_watchpoint): New function. (ia64_linux_insert_watchpoint_callback): Ditto. (ia64_linux_insert_watchpoint): Change to iterate through lwps and insert the specified watchpoint per thread. (ia64_stopped_data_address): Call target_get_lwp to ensure the ptid has its lwp field filled in. (ia64_linux_remove_one_watchpoint): New function. (ia64_linux_remove_watchpoint_callback): Ditto. (ia64_linux_remove_watchpoint): Change to iterate through lwps and remove the specified watchpoint for each thread. (ia64_linux_new_thread): New thread observer. (_initialize_ia64_linux_nat): New function. Initialize new thread observer. * linux-nat.h (struct linux_watchpoint): New structure. * thread-db.c (attach_thread): Add the thread after attaching to it. Before allocating the thread private info area, check to see if it has already been allocated. (thread_db_get_info): Allocate a thread private info area if one doesn't already exist. (init_thread_db_ops): Point to_get_lwp to lwp_from_thread function. * thread.c (add_thread): Notify any observers of a new thread event. * s390-nat.c (s390_tid): New function. (s390_inferior_tid): Change to call s390_tid. (s390_remove_one_watchpoint): New function. (s390_remove_watchpoint_callback): Ditto. (s390_remove_watchpoint): Change to iterate through lwps and remove the specified watchpoint for each thread. (s390_insert_one_watchpoint): New function. (s390_insert_watchpoint_callback): Ditto. (s390_insert_watchpoint): Change to iterate through lwps and insert the specified watchpoint on each thread. (s390_new_thread): New thread observer. (_initialize_s390_nat): New function. Initialize new thread observer. * target.c (return_ptid): New static function. (update_current_target): Add support for new to_get_lwp. (init_dummy_target): Ditto. * target.h (struct target_ops): Add to_get_lwp. (target_get_lwp): New macro. doc/ChangeLog: 2004-11-04 Jeff Johnston * observer.texi (new_thread): New observer. --------------070203080606030801070906 Content-Type: text/plain; name="newwatchthreads3.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="newwatchthreads3.patch" Content-length: 20750 Index: breakpoint.c =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.184 diff -u -p -r1.184 breakpoint.c --- breakpoint.c 29 Oct 2004 20:23:04 -0000 1.184 +++ breakpoint.c 4 Nov 2004 18:19:11 -0000 @@ -748,6 +748,91 @@ insert_catchpoint (struct ui_out *uo, vo return 0; } +/* External function to insert all existing watchpoints on a newly + attached thread. IWPFN is a callback function to perform + the target insert watchpoint. This function is used to support + platforms where a watchpoint must be inserted/removed on each + individual thread (e.g. ia64-linux and s390-linux). For + ia64 and s390 linux, this function is called via a new thread + observer. */ +int +insert_watchpoints_for_new_thread (ptid_t new_thread, + insert_watchpoint_ftype *iwpfn) +{ + struct bp_location *b; + int val = 0; + int return_val = 0; + struct ui_file *tmp_error_stream = mem_fileopen (); + make_cleanup_ui_file_delete (tmp_error_stream); + + /* Explicitly mark the warning -- this will only be printed if + there was an error. */ + fprintf_unfiltered (tmp_error_stream, "Warning:\n"); + + ALL_BP_LOCATIONS (b) + { + /* Skip disabled breakpoints. */ + if (!breakpoint_enabled (b->owner)) + continue; + + /* For every active watchpoint, we need to insert the watchpoint on + the new thread. */ + if ((b->loc_type == bp_loc_hardware_watchpoint + || b->owner->type == bp_watchpoint)) + { + struct value *v = b->owner->val_chain; + + /* Look at each value on the value chain. */ + for (; v; v = v->next) + { + /* If it's a memory location, and GDB actually needed + its contents to evaluate the expression, then we + must watch it. */ + if (VALUE_LVAL (v) == lval_memory + && ! VALUE_LAZY (v)) + { + struct type *vtype = check_typedef (VALUE_TYPE (v)); + + /* We only watch structs and arrays if user asked + for it explicitly, never if they just happen to + appear in the middle of some value chain. */ + if (v == b->owner->val_chain + || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT + && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) + { + CORE_ADDR addr; + int len, type; + + addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v); + len = TYPE_LENGTH (VALUE_TYPE (v)); + type = hw_write; + if (b->owner->type == bp_read_watchpoint) + type = hw_read; + else if (b->owner->type == bp_access_watchpoint) + type = hw_access; + val = (*iwpfn) (new_thread, addr, len, type); + } + } + } + } + + if (val) + return_val = val; + } + + /* Failure to insert a watchpoint on any memory value in the + value chain brings us here. */ + if (return_val) + { + fprintf_unfiltered (tmp_error_stream, + "%s\n", + "Could not insert hardware watchpoints on new thread."); + target_terminal_ours_for_output (); + error_stream (tmp_error_stream); + } + return return_val; +} + /* Helper routine: free the value chain for a breakpoint (watchpoint). */ static void free_valchain (struct bp_location *b) @@ -2122,8 +2207,13 @@ print_it_typical (bpstat bs) break; case bp_thread_event: - /* Not sure how we will get here. - GDB should not stop for these breakpoints. */ + /* We can only get here legitimately if something further on the bs + list has caused the stop status to be noisy. A valid example + of this is a new thread event and a software watchpoint have + both occurred. */ + if (bs->next) + return PRINT_UNKNOWN; + printf_filtered ("Thread Event Breakpoint: gdb should not stop!\n"); return PRINT_NOTHING; break; Index: breakpoint.h =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.h,v retrieving revision 1.34 diff -u -p -r1.34 breakpoint.h --- breakpoint.h 13 May 2004 16:39:11 -0000 1.34 +++ breakpoint.h 4 Nov 2004 18:19:11 -0000 @@ -663,6 +663,12 @@ extern void tbreak_command (char *, int) extern int insert_breakpoints (void); +/* The following provides a callback mechanism to insert watchpoints + for a new thread. This is needed, for example, on ia64 linux. */ +typedef int (insert_watchpoint_ftype) (ptid_t, CORE_ADDR, int, int); +extern int insert_watchpoints_for_new_thread (ptid_t ptid, + insert_watchpoint_ftype *fn); + extern int remove_breakpoints (void); /* This function can be used to physically insert eventpoints from the Index: ia64-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/ia64-linux-nat.c,v retrieving revision 1.26 diff -u -p -r1.26 ia64-linux-nat.c --- ia64-linux-nat.c 13 Oct 2004 21:40:41 -0000 1.26 +++ ia64-linux-nat.c 4 Nov 2004 18:19:11 -0000 @@ -39,6 +39,8 @@ #include #include +#include "observer.h" +#include "linux-nat.h" /* Prototypes for supply_gregset etc. */ #include "gregset.h" @@ -559,8 +561,9 @@ is_power_of_2 (int val) return onecount <= 1; } -int -ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw) +/* Internal routine to insert one watchpoint for a specified thread. */ +static int +ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw) { int idx; long dbr_addr, dbr_mask; @@ -606,8 +609,38 @@ ia64_linux_insert_watchpoint (ptid_t pti return 0; } +/* Internal callback routine which can be used via iterate_over_lwps + to insert a specific watchpoint from all active threads. */ +static int +ia64_linux_insert_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *)data; + + return ia64_linux_insert_one_watchpoint (lwp->ptid, args->addr, + args->len, args->type); +} + +/* Insert a watchpoint for all threads. */ int -ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len) +ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw) +{ + struct linux_watchpoint args; + + args.addr = addr; + args.len = len; + args.type = rw; + + /* For ia64, watchpoints must be inserted/removed on each thread so + we iterate over the lwp list. */ + if (iterate_over_lwps (&ia64_linux_insert_watchpoint_callback, &args)) + return -1; + + return 0; +} + +/* Internal routine to remove one watchpoint for a specified thread. */ +static int +ia64_linux_remove_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len) { int idx; long dbr_addr, dbr_mask; @@ -630,13 +663,41 @@ ia64_linux_remove_watchpoint (ptid_t pti return -1; } +/* Internal callback routine which can be used via iterate_over_lwps + to remove a specific watchpoint from all active threads. */ +static int +ia64_linux_remove_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *)data; + + return ia64_linux_remove_one_watchpoint (lwp->ptid, args->addr, + args->len); +} + +/* Remove a watchpoint for all threads. */ +int +ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len) +{ + struct linux_watchpoint args; + + args.addr = addr; + args.len = len; + + /* For ia64, watchpoints must be inserted/removed on each thread so + we iterate over the lwp list. */ + if (iterate_over_lwps (&ia64_linux_remove_watchpoint_callback, &args)) + return -1; + + return 0; +} + int ia64_linux_stopped_data_address (CORE_ADDR *addr_p) { CORE_ADDR psr; int tid; struct siginfo siginfo; - ptid_t ptid = inferior_ptid; + ptid_t ptid = target_get_lwp (inferior_ptid); tid = TIDGET(ptid); if (tid == 0) @@ -674,3 +735,31 @@ ia64_linux_xfer_unwind_table (struct tar { return syscall (__NR_getunwind, readbuf, len); } + +/* Internal callback for insert_watchpoints_for_new_thread to call. + The PTID will be in the thread-level format and must be + translated to the lwp-level format before calling + ia64_linux_insert_one_watchpoint to insert any watchpoint. */ +static int +ia64_linux_insert_watchpoint_for_thread (ptid_t ptid, CORE_ADDR addr, + int len, int rw) +{ + ptid_t lwp_ptid = target_get_lwp (ptid); + return ia64_linux_insert_one_watchpoint (lwp_ptid, addr, len, rw); +} + +/* Observer function for a new thread attach. We need to insert + existing watchpoints on the new thread. */ +static void +ia64_linux_new_thread (ptid_t ptid) +{ + insert_watchpoints_for_new_thread (ptid, + &ia64_linux_insert_watchpoint_for_thread); +} + +void +_initialize_ia64_linux_nat (void) +{ + observer_attach_new_thread (ia64_linux_new_thread); +} + Index: linux-nat.h =================================================================== RCS file: /cvs/src/src/gdb/linux-nat.h,v retrieving revision 1.6 diff -u -p -r1.6 linux-nat.h --- linux-nat.h 29 Mar 2004 18:07:14 -0000 1.6 +++ linux-nat.h 4 Nov 2004 18:19:11 -0000 @@ -63,6 +63,14 @@ struct lwp_info struct lwp_info *next; }; +/* Watchpoint description. */ +struct linux_watchpoint +{ + CORE_ADDR addr; + int len; + int type; +}; + /* Read/write to target memory via the Linux kernel's "proc file system". */ struct mem_attrib; Index: s390-nat.c =================================================================== RCS file: /cvs/src/src/gdb/s390-nat.c,v retrieving revision 1.12 diff -u -p -r1.12 s390-nat.c --- s390-nat.c 18 Feb 2004 04:17:35 -0000 1.12 +++ s390-nat.c 4 Nov 2004 18:19:12 -0000 @@ -27,6 +27,8 @@ #include "inferior.h" #include "s390-tdep.h" +#include "linux-nat.h" +#include "observer.h" #include #include @@ -112,18 +114,32 @@ fill_fpregset (fpregset_t *regp, int reg ((char *)regp) + regmap_fpregset[i]); } -/* Find the TID for the current inferior thread to use with ptrace. */ +/* Find the TID for use with ptrace. */ static int -s390_inferior_tid (void) +s390_tid (ptid_t ptid) { /* GNU/Linux LWP ID's are process ID's. */ - int tid = TIDGET (inferior_ptid); + int tid = TIDGET (ptid); if (tid == 0) - tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + { + /* In some cases, we have a thread-level format ptid which + must be converted to an lwp-level format ptid. */ + ptid_t lwp_ptid = target_get_lwp (ptid); + tid = TIDGET (lwp_ptid); + if (tid == 0) + tid = PIDGET (lwp_ptid); /* Not a threaded program. */ + } return tid; } +/* Find the TID for the current inferior thread to use with ptrace. */ +static int +s390_inferior_tid (void) +{ + return s390_tid (inferior_ptid); +} + /* Fetch all general-purpose registers from process/thread TID and store their values in GDB's register cache. */ static void @@ -269,9 +285,9 @@ s390_stopped_by_watchpoint (void) } static void -s390_fix_watch_points (void) +s390_fix_watch_points (ptid_t ptid) { - int tid = s390_inferior_tid (); + int tid = s390_tid (ptid); per_struct per_info; ptrace_area parea; @@ -308,8 +324,9 @@ s390_fix_watch_points (void) perror_with_name ("Couldn't modify watchpoint status"); } -int -s390_insert_watchpoint (CORE_ADDR addr, int len) +/* Insert a specified watchpoint on a specified thread. */ +static int +s390_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int type) { struct watch_area *area = xmalloc (sizeof (struct watch_area)); if (!area) @@ -321,12 +338,36 @@ s390_insert_watchpoint (CORE_ADDR addr, area->next = watch_base; watch_base = area; - s390_fix_watch_points (); + s390_fix_watch_points (ptid); return 0; } +/* Callback routine to use with iterate_over_lwps to insert a specified + watchpoint on all threads. */ +static int +s390_insert_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *)data; + + return s390_insert_one_watchpoint (lwp->ptid, args->addr, args->len, 0); +} + +/* Insert a specified watchpoint on all threads. */ int -s390_remove_watchpoint (CORE_ADDR addr, int len) +s390_insert_watchpoint (CORE_ADDR addr, int len) +{ + struct linux_watchpoint args; + + args.addr = addr; + args.len = len; + /* For the S390, a watchpoint must be inserted/removed for each + thread so we iterate over the list of existing lwps. */ + return iterate_over_lwps (&s390_insert_watchpoint_callback, &args); +} + +/* Remove a specified watchpoint from a specified thread. */ +static int +s390_remove_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len) { struct watch_area *area, **parea; @@ -346,10 +387,32 @@ s390_remove_watchpoint (CORE_ADDR addr, *parea = area->next; xfree (area); - s390_fix_watch_points (); + s390_fix_watch_points (ptid); return 0; } +/* Callback routine to use with iterate_over_lwps to remove a specified + watchpoint from all threads. */ +static int +s390_remove_watchpoint_callback (struct lwp_info *lwp, void *data) +{ + struct linux_watchpoint *args = (struct linux_watchpoint *)data; + + return s390_remove_one_watchpoint (lwp->ptid, args->addr, args->len); +} + +/* Remove a specified watchpoint from all threads. */ +int +s390_remove_watchpoint (CORE_ADDR addr, int len) +{ + struct linux_watchpoint args; + + args.addr = addr; + args.len = len; + /* For the S390, a watchpoint must be inserted/removed for each + thread so we iterate over the list of existing lwps. */ + return iterate_over_lwps (&s390_remove_watchpoint_callback, &args); +} int kernel_u_size (void) @@ -357,3 +420,18 @@ kernel_u_size (void) return sizeof (struct user); } +/* New thread observer that inserts all existing watchpoints on the + new thread. */ +static void +s390_new_thread (ptid_t ptid) +{ + insert_watchpoints_for_new_thread (ptid, &s390_insert_one_watchpoint); +} + +void +_initialize_s390_nat (void) +{ + observer_attach_new_thread (s390_new_thread); +} + + Index: target.c =================================================================== RCS file: /cvs/src/src/gdb/target.c,v retrieving revision 1.90 diff -u -p -r1.90 target.c --- target.c 8 Oct 2004 20:29:55 -0000 1.90 +++ target.c 4 Nov 2004 18:19:12 -0000 @@ -61,6 +61,8 @@ static int return_one (void); static int return_minus_one (void); +static ptid_t return_ptid (ptid_t ptid); + void target_ignore (void); static void target_command (char *, int); @@ -430,6 +432,7 @@ update_current_target (void) INHERIT (to_notice_signals, t); INHERIT (to_thread_alive, t); INHERIT (to_find_new_threads, t); + INHERIT (to_get_lwp, t); INHERIT (to_pid_to_str, t); INHERIT (to_extra_thread_info, t); INHERIT (to_stop, t); @@ -606,6 +609,9 @@ update_current_target (void) de_fault (to_find_new_threads, (void (*) (void)) target_ignore); + de_fault (to_get_lwp, + (ptid_t (*) (ptid_t)) + return_ptid); de_fault (to_extra_thread_info, (char *(*) (struct thread_info *)) return_zero); @@ -1541,6 +1547,12 @@ return_minus_one (void) return -1; } +static ptid_t +return_ptid (ptid_t ptid) +{ + return ptid; +} + /* * Resize the to_sections pointer. Also make sure that anyone that * was holding on to an old value of it gets updated. @@ -1793,6 +1805,7 @@ init_dummy_target (void) dummy_target.to_find_memory_regions = dummy_find_memory_regions; dummy_target.to_make_corefile_notes = dummy_make_corefile_notes; dummy_target.to_xfer_partial = default_xfer_partial; + dummy_target.to_get_lwp = return_ptid; dummy_target.to_magic = OPS_MAGIC; } Index: target.h =================================================================== RCS file: /cvs/src/src/gdb/target.h,v retrieving revision 1.65 diff -u -p -r1.65 target.h --- target.h 8 Oct 2004 20:29:55 -0000 1.65 +++ target.h 4 Nov 2004 18:19:12 -0000 @@ -372,6 +372,7 @@ struct target_ops void (*to_notice_signals) (ptid_t ptid); int (*to_thread_alive) (ptid_t ptid); void (*to_find_new_threads) (void); + ptid_t (*to_get_lwp) (ptid_t ptid); char *(*to_pid_to_str) (ptid_t); char *(*to_extra_thread_info) (struct thread_info *); void (*to_stop) (void); @@ -802,6 +803,10 @@ extern void target_load (char *arg, int #define target_find_new_threads() \ (*current_target.to_find_new_threads) (); \ +/* Get the lwp for a thread. */ +#define target_get_lwp(ptid) \ + (*current_target.to_get_lwp) (ptid); \ + /* Make target stop in a continuable fashion. (For instance, under Unix, this should act like SIGSTOP). This function is normally used by GUIs to implement a stop button. */ Index: thread-db.c =================================================================== RCS file: /cvs/src/src/gdb/thread-db.c,v retrieving revision 1.46 diff -u -p -r1.46 thread-db.c --- thread-db.c 8 Oct 2004 20:29:56 -0000 1.46 +++ thread-db.c 4 Nov 2004 18:19:12 -0000 @@ -34,6 +34,7 @@ #include "target.h" #include "regcache.h" #include "solib-svr4.h" +#include "observer.h" #ifdef HAVE_GNU_LIBC_VERSION_H #include @@ -333,6 +334,17 @@ thread_db_get_info (struct thread_info * { td_err_e err; + /* Allocate a private area if needed. This can occur for ia64 or + s390 linux which must insert breakpoints on newly found threads. + The observer for a new thread event will be called on an add_thread + call before the private area has been set up and will need to + get the lwp for the new ptid using this function. */ + if (!thread_info->private) + { + thread_info->private = xmalloc (sizeof (struct private_thread_info)); + memset (thread_info->private, 0, sizeof (struct private_thread_info)); + } + if (thread_info->private->ti_valid) return &thread_info->private->ti; @@ -746,14 +758,6 @@ attach_thread (ptid_t ptid, const td_thr check_thread_signals (); - /* Add the thread to GDB's thread list. */ - tp = add_thread (ptid); - tp->private = xmalloc (sizeof (struct private_thread_info)); - memset (tp->private, 0, sizeof (struct private_thread_info)); - - if (verbose) - printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid)); - if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE) return; /* A zombie thread -- do not attach. */ @@ -762,6 +766,21 @@ attach_thread (ptid_t ptid, const td_thr ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0); #endif + /* Add the thread to GDB's thread list. + We do this after attaching so any observers of a new + thread event can perform PTRACE operations on the thread + if needed. An observer may end up allocating the + private info area, so check first. */ + tp = add_thread (ptid); + if (!tp->private) + { + tp->private = xmalloc (sizeof (struct private_thread_info)); + memset (tp->private, 0, sizeof (struct private_thread_info)); + } + + if (verbose) + printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid)); + /* Enable thread event reporting for this thread. */ err = td_thr_event_enable_p (th_p, 1); if (err != TD_OK) @@ -1346,6 +1365,7 @@ init_thread_db_ops (void) thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior; thread_db_ops.to_thread_alive = thread_db_thread_alive; thread_db_ops.to_find_new_threads = thread_db_find_new_threads; + thread_db_ops.to_get_lwp = lwp_from_thread; thread_db_ops.to_pid_to_str = thread_db_pid_to_str; thread_db_ops.to_stratum = thread_stratum; thread_db_ops.to_has_thread_control = tc_schedlock; Index: thread.c =================================================================== RCS file: /cvs/src/src/gdb/thread.c,v retrieving revision 1.39 diff -u -p -r1.39 thread.c --- thread.c 29 Oct 2004 20:23:13 -0000 1.39 +++ thread.c 4 Nov 2004 18:19:12 -0000 @@ -130,6 +130,10 @@ add_thread (ptid_t ptid) tp->num = ++highest_thread_num; tp->next = thread_list; thread_list = tp; + + /* Inform any observers of the new thread. */ + observer_notify_new_thread (ptid); + return tp; } Index: doc/observer.texi =================================================================== RCS file: /cvs/src/src/gdb/doc/observer.texi,v retrieving revision 1.8 diff -u -p -r1.8 observer.texi --- doc/observer.texi 1 Sep 2004 17:59:37 -0000 1.8 +++ doc/observer.texi 4 Nov 2004 18:19:12 -0000 @@ -95,3 +95,7 @@ inferior, and before any information on The specified shared library has been discovered to be unloaded. @end deftypefun +@deftypefun void new_thread (ptid_t @var{ptid}) +A new thread described by @var{ptid} has been detected by gdb. +@end deftypefun + --------------070203080606030801070906--