X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fthread-db.c;h=86c4e1814722c9f2c68366421c50c50b9db5c809;hb=9836d6ea69b99b5ed77e0f2c2c500b144ab95018;hp=e169a50f3e5517bbe11d08e38ca271a448771ef1;hpb=10e86dd77848e00024b5de420c18e13db9a103c9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index e169a50f3e..86c4e18147 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -1,5 +1,5 @@ /* Thread management interface, for the remote server for GDB. - Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009 + Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -47,11 +47,26 @@ struct thread_db /* Connection to the libthread_db library. */ td_thragent_t *thread_agent; + /* If this flag has been set, we've already asked GDB for all + symbols we might need; assume symbol cache misses are + failures. */ + int all_symbols_looked_up; + #ifndef USE_LIBTHREAD_DB_DIRECTLY /* Handle of the libthread_db from dlopen. */ void *handle; #endif + /* Thread creation event breakpoint. The code at this location in + the child process will be called by the pthread library whenever + a new thread is created. By setting a special breakpoint at this + location, GDB can detect when a new thread is created. We obtain + this location via the td_ta_event_addr call. Note that if the + running kernel supports tracing clones, then we don't need to use + (and in fact don't use) this magic thread event breakpoint to + learn about threads. */ + struct breakpoint *td_create_bp; + /* Addresses of libthread_db functions. */ td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta); td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta, @@ -205,7 +220,7 @@ thread_db_create_event (CORE_ADDR where) } static int -thread_db_enable_reporting () +thread_db_enable_reporting (void) { td_thr_events_t events; td_notify_t notify; @@ -239,8 +254,9 @@ thread_db_enable_reporting () thread_db_err_str (err)); return 0; } - set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr, - thread_db_create_event); + thread_db->td_create_bp + = set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr, + thread_db_create_event); return 1; } @@ -441,7 +457,25 @@ thread_db_look_up_symbols (void) CORE_ADDR unused; for (sym_list = thread_db->td_symbol_list_p (); *sym_list; sym_list++) - look_up_one_symbol (*sym_list, &unused); + look_up_one_symbol (*sym_list, &unused, 1); + + /* We're not interested in any other libraries loaded after this + point, only in symbols in libpthread.so. */ + thread_db->all_symbols_looked_up = 1; +} + +int +thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp) +{ + struct thread_db *thread_db = current_process ()->private->thread_db; + int may_ask_gdb = !thread_db->all_symbols_looked_up; + + /* If we've passed the call to thread_db_look_up_symbols, then + anything not in the cache must not exist; we're not interested + in any libraries loaded after that point, only in symbols in + libpthread.so. It might not be an appropriate time to look + up a symbol, e.g. while we're trying to fetch registers. */ + return look_up_one_symbol (name, addrp, may_ask_gdb); } int @@ -459,7 +493,7 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, thread_db = proc->private->thread_db; /* If the thread layer is not (yet) initialized, fail. */ - if (!proc->all_symbols_looked_up) + if (!thread_db->all_symbols_looked_up) return TD_ERR; if (thread_db->td_thr_tls_get_addr_p == NULL) @@ -495,39 +529,41 @@ static int thread_db_load_search (void) { td_err_e err; - struct thread_db tdb; + struct thread_db *tdb; struct process_info *proc = current_process (); if (proc->private->thread_db != NULL) fatal ("unexpected: proc->private->thread_db != NULL"); - tdb.td_ta_new_p = &td_ta_new; + tdb = xcalloc (1, sizeof (*tdb)); + proc->private->thread_db = tdb; + + tdb->td_ta_new_p = &td_ta_new; /* Attempt to open a connection to the thread library. */ - err = tdb.td_ta_new_p (&tdb.proc_handle, &tdb.thread_agent); + err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent); if (err != TD_OK) { if (debug_threads) fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err)); + free (tdb); + proc->private->thread_db = NULL; return 0; } - tdb.td_ta_map_lwp2thr_p = &td_ta_map_lwp2thr; - tdb.td_thr_get_info_p = &td_thr_get_info; - tdb.td_ta_thr_iter_p = &td_ta_thr_iter; - tdb.td_symbol_list_p = &td_symbol_list; + tdb->td_ta_map_lwp2thr_p = &td_ta_map_lwp2thr; + tdb->td_thr_get_info_p = &td_thr_get_info; + tdb->td_ta_thr_iter_p = &td_ta_thr_iter; + tdb->td_symbol_list_p = &td_symbol_list; /* This is required only when thread_db_use_events is on. */ - tdb.td_thr_event_enable_p = &td_thr_event_enable; + tdb->td_thr_event_enable_p = &td_thr_event_enable; /* These are not essential. */ - tdb.td_ta_event_addr_p = &td_ta_event_addr; - tdb.td_ta_set_event_p = &td_ta_set_event; - tdb.td_ta_event_getmsg_p = &td_ta_event_getmsg; - tdb.td_thr_tls_get_addr_p = &td_thr_tls_get_addr; - - proc->private->thread_db = xmalloc (sizeof (tdb)); - memcpy (proc->private->thread_db, &tdb, sizeof (tdb)); + tdb->td_ta_event_addr_p = &td_ta_event_addr; + tdb->td_ta_set_event_p = &td_ta_set_event; + tdb->td_ta_event_getmsg_p = &td_ta_event_getmsg; + tdb->td_thr_tls_get_addr_p = &td_thr_tls_get_addr; return 1; } @@ -538,13 +574,16 @@ static int try_thread_db_load_1 (void *handle) { td_err_e err; - struct thread_db tdb; + struct thread_db *tdb; struct process_info *proc = current_process (); if (proc->private->thread_db != NULL) fatal ("unexpected: proc->private->thread_db != NULL"); - tdb.handle = handle; + tdb = xcalloc (1, sizeof (*tdb)); + proc->private->thread_db = tdb; + + tdb->handle = handle; /* Initialize pointers to the dynamic library functions we will use. Essential functions first. */ @@ -557,42 +596,45 @@ try_thread_db_load_1 (void *handle) if (debug_threads) \ fprintf (stderr, "dlsym: %s\n", dlerror ()); \ if (required) \ - return 0; \ + { \ + free (tdb); \ + proc->private->thread_db = NULL; \ + return 0; \ + } \ } \ } \ while (0) - CHK (1, tdb.td_ta_new_p = dlsym (handle, "td_ta_new")); + CHK (1, tdb->td_ta_new_p = dlsym (handle, "td_ta_new")); /* Attempt to open a connection to the thread library. */ - err = tdb.td_ta_new_p (&tdb.proc_handle, &tdb.thread_agent); + err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent); if (err != TD_OK) { if (debug_threads) fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err)); + free (tdb); + proc->private->thread_db = NULL; return 0; } - CHK (1, tdb.td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr")); - CHK (1, tdb.td_thr_get_info_p = dlsym (handle, "td_thr_get_info")); - CHK (1, tdb.td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter")); - CHK (1, tdb.td_symbol_list_p = dlsym (handle, "td_symbol_list")); + CHK (1, tdb->td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr")); + CHK (1, tdb->td_thr_get_info_p = dlsym (handle, "td_thr_get_info")); + CHK (1, tdb->td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter")); + CHK (1, tdb->td_symbol_list_p = dlsym (handle, "td_symbol_list")); /* This is required only when thread_db_use_events is on. */ CHK (thread_db_use_events, - tdb.td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable")); + tdb->td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable")); /* These are not essential. */ - CHK (0, tdb.td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr")); - CHK (0, tdb.td_ta_set_event_p = dlsym (handle, "td_ta_set_event")); - CHK (0, tdb.td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg")); - CHK (0, tdb.td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr")); + CHK (0, tdb->td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr")); + CHK (0, tdb->td_ta_set_event_p = dlsym (handle, "td_ta_set_event")); + CHK (0, tdb->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg")); + CHK (0, tdb->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr")); #undef CHK - proc->private->thread_db = xmalloc (sizeof (tdb)); - memcpy (proc->private->thread_db, &tdb, sizeof (tdb)); - return 1; } @@ -743,47 +785,117 @@ thread_db_init (int use_events) if (use_events && thread_db_enable_reporting () == 0) { /* Keep trying; maybe event reporting will work later. */ - thread_db_free (proc, 0); + thread_db_mourn (proc); return 0; } thread_db_find_new_threads (); thread_db_look_up_symbols (); - proc->all_symbols_looked_up = 1; return 1; } return 0; } +static int +any_thread_of (struct inferior_list_entry *entry, void *args) +{ + int *pid_p = args; + + if (ptid_get_pid (entry->id) == *pid_p) + return 1; + + return 0; +} + +static void +switch_to_process (struct process_info *proc) +{ + int pid = pid_of (proc); + + current_inferior = + (struct thread_info *) find_inferior (&all_threads, + any_thread_of, &pid); +} + /* Disconnect from libthread_db and free resources. */ -void -thread_db_free (struct process_info *proc, int detaching) +static void +disable_thread_event_reporting (struct process_info *proc) { struct thread_db *thread_db = proc->private->thread_db; if (thread_db) { - td_err_e (*td_ta_delete_p) (td_thragent_t *); td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta, td_thr_events_t *event); #ifndef USE_LIBTHREAD_DB_DIRECTLY td_ta_clear_event_p = dlsym (thread_db->handle, "td_ta_clear_event"); - td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete"); #else - td_ta_delete_p = &td_ta_delete; td_ta_clear_event_p = &td_ta_clear_event; #endif - if (detaching && td_ta_clear_event_p != NULL) + if (td_ta_clear_event_p != NULL) { + struct thread_info *saved_inferior = current_inferior; td_thr_events_t events; + switch_to_process (proc); + /* Set the process wide mask saying we aren't interested in any events anymore. */ td_event_fillset (&events); (*td_ta_clear_event_p) (thread_db->thread_agent, &events); + + current_inferior = saved_inferior; } + } +} + +static void +remove_thread_event_breakpoints (struct process_info *proc) +{ + struct thread_db *thread_db = proc->private->thread_db; + + if (thread_db->td_create_bp != NULL) + { + struct thread_info *saved_inferior = current_inferior; + + switch_to_process (proc); + + delete_breakpoint (thread_db->td_create_bp); + thread_db->td_create_bp = NULL; + + current_inferior = saved_inferior; + } +} + +void +thread_db_detach (struct process_info *proc) +{ + struct thread_db *thread_db = proc->private->thread_db; + + if (thread_db) + { + disable_thread_event_reporting (proc); + remove_thread_event_breakpoints (proc); + } +} + +/* Disconnect from libthread_db and free resources. */ + +void +thread_db_mourn (struct process_info *proc) +{ + struct thread_db *thread_db = proc->private->thread_db; + if (thread_db) + { + td_err_e (*td_ta_delete_p) (td_thragent_t *); + +#ifndef USE_LIBTHREAD_DB_DIRECTLY + td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete"); +#else + td_ta_delete_p = &td_ta_delete; +#endif if (td_ta_delete_p != NULL) (*td_ta_delete_p) (thread_db->thread_agent);