2008-03-21 Daniel Jacobowitz <dan@codesourcery.com>

* gdbthread.h (add_thread_with_info): New.
	* linux-thread-db.c: Add some documentation.
	(GET_LWP, GET_PID, GET_THREAD, is_lwp, is_thread, BUILD_LWP): Delete.
	(struct private_thread_info): Remove th_valid and ti_valid.
	Replace ti with tid.
	(thread_get_info_callback): Do not add TID to the new ptid.  Do
	not cache th or ti.
	(thread_db_map_id2thr, lwp_from_thread): Delete functions.
	(thread_from_lwp): Assert that the LWP is set.  Do not add TID to the
	new PTID.
	(attach_thread): Handle an already-existing thread.  Use
	add_thread_with_info.  Cache the th and tid.
	(detach_thread): Verify that private was set.  Remove verbose
	argument and printing.  Update caller.
	(thread_db_detach): Do not adjust inferior_ptid.
	(clear_lwpid_callback, thread_db_resume, thread_db_kill): Delete.
	(check_event, find_new_threads_callback): Do not add TID to the new PTID.
	(thread_db_wait): Do not use lwp_from_thread.
	(thread_db_pid_to_str): Use the cached TID.
	(thread_db_extra_thread_info): Check that private is set.
	(same_ptid_callback): Delete.
	(thread_db_get_thread_local_address): Do not use it or check
	is_thread.  Check that private is set.  Assume that the thread
	handle is already cached.
	(init_thread_db_ops): Remove to_resume and to_kill.
	* thread.c (add_thread_with_info): New.
	(add_thread): Use it.
	* linux-nat.c (find_thread_from_lwp): Delete.
	(exit_lwp): Do not use it.  Check print_thread_events.  Print before
	deleting the thread.
	(GET_PID, GET_LWP, BUILD_LWP, is_lwp): Move to...
	* linux-nat.h (GET_PID, GET_LWP, BUILD_LWP, is_lwp): ...here.
	* inf-ttrace.c (inf_ttrace_wait): Use print_thread_events and
	printf_unfiltered for thread exits.
	* procfs.c (procfs_wait): Likewise.

2008-03-21  Pedro Alves  <pedro@codesourcery.com>

	* gdb.threads/fork-child-threads.exp: Test next over fork.
This commit is contained in:
Daniel Jacobowitz 2008-03-21 15:44:53 +00:00
parent 93f9b40865
commit 17faa917e0
10 changed files with 167 additions and 215 deletions

View file

@ -1,3 +1,41 @@
2008-03-21 Daniel Jacobowitz <dan@codesourcery.com>
* gdbthread.h (add_thread_with_info): New.
* linux-thread-db.c: Add some documentation.
(GET_LWP, GET_PID, GET_THREAD, is_lwp, is_thread, BUILD_LWP): Delete.
(struct private_thread_info): Remove th_valid and ti_valid.
Replace ti with tid.
(thread_get_info_callback): Do not add TID to the new ptid. Do
not cache th or ti.
(thread_db_map_id2thr, lwp_from_thread): Delete functions.
(thread_from_lwp): Assert that the LWP is set. Do not add TID to the
new PTID.
(attach_thread): Handle an already-existing thread. Use
add_thread_with_info. Cache the th and tid.
(detach_thread): Verify that private was set. Remove verbose
argument and printing. Update caller.
(thread_db_detach): Do not adjust inferior_ptid.
(clear_lwpid_callback, thread_db_resume, thread_db_kill): Delete.
(check_event, find_new_threads_callback): Do not add TID to the new PTID.
(thread_db_wait): Do not use lwp_from_thread.
(thread_db_pid_to_str): Use the cached TID.
(thread_db_extra_thread_info): Check that private is set.
(same_ptid_callback): Delete.
(thread_db_get_thread_local_address): Do not use it or check
is_thread. Check that private is set. Assume that the thread
handle is already cached.
(init_thread_db_ops): Remove to_resume and to_kill.
* thread.c (add_thread_with_info): New.
(add_thread): Use it.
* linux-nat.c (find_thread_from_lwp): Delete.
(exit_lwp): Do not use it. Check print_thread_events. Print before
deleting the thread.
(GET_PID, GET_LWP, BUILD_LWP, is_lwp): Move to...
* linux-nat.h (GET_PID, GET_LWP, BUILD_LWP, is_lwp): ...here.
* inf-ttrace.c (inf_ttrace_wait): Use print_thread_events and
printf_unfiltered for thread exits.
* procfs.c (procfs_wait): Likewise.
2008-03-21 Chris Demetriou <cgd@google.com>
* symtab.c (rbreak_command): Quote symbol name before passing

View file

@ -81,6 +81,10 @@ extern struct thread_info *add_thread (ptid_t ptid);
about new thread. */
extern struct thread_info *add_thread_silent (ptid_t ptid);
/* Same as add_thread, and sets the private info. */
extern struct thread_info *add_thread_with_info (ptid_t ptid,
struct private_thread_info *);
/* Delete an existing thread list entry. */
extern void delete_thread (ptid_t);

View file

@ -964,7 +964,8 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
break;
case TTEVT_LWP_EXIT:
printf_filtered(_("[%s exited]\n"), target_pid_to_str (ptid));
if (print_thread_events)
printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (ptid));
ti = find_thread_pid (ptid);
gdb_assert (ti != NULL);
((struct inf_ttrace_private_thread_info *)ti->private)->dying = 1;

View file

@ -588,11 +588,6 @@ struct lwp_info *lwp_list;
static int num_lwps;
#define GET_LWP(ptid) ptid_get_lwp (ptid)
#define GET_PID(ptid) ptid_get_pid (ptid)
#define is_lwp(ptid) (GET_LWP (ptid) != 0)
#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
/* If the last reported event was a SIGTRAP, this variable is set to
the process id of the LWP/thread that got it. */
ptid_t trap_ptid;
@ -813,20 +808,6 @@ prune_lwps (void)
p = &(*p)->next;
}
/* Callback for iterate_over_threads that finds a thread corresponding
to the given LWP. */
static int
find_thread_from_lwp (struct thread_info *thr, void *dummy)
{
ptid_t *ptid_p = dummy;
if (GET_LWP (thr->ptid) && GET_LWP (thr->ptid) == GET_LWP (*ptid_p))
return 1;
else
return 0;
}
/* Handle the exit of a single thread LP. */
static void
@ -834,32 +815,14 @@ exit_lwp (struct lwp_info *lp)
{
if (in_thread_list (lp->ptid))
{
if (print_thread_events)
printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (lp->ptid));
/* Core GDB cannot deal with us deleting the current thread. */
if (!ptid_equal (lp->ptid, inferior_ptid))
delete_thread (lp->ptid);
else
record_dead_thread (lp->ptid);
printf_unfiltered (_("[%s exited]\n"),
target_pid_to_str (lp->ptid));
}
else
{
/* Even if LP->PTID is not in the global GDB thread list, the
LWP may be - with an additional thread ID. We don't need
to print anything in this case; thread_db is in use and
already took care of that. But it didn't delete the thread
in order to handle zombies correctly. */
struct thread_info *thr;
thr = iterate_over_threads (find_thread_from_lwp, &lp->ptid);
if (thr)
{
if (!ptid_equal (thr->ptid, inferior_ptid))
delete_thread (thr->ptid);
else
record_dead_thread (thr->ptid);
}
}
delete_lwp (lp->ptid);

View file

@ -83,6 +83,11 @@ extern struct lwp_info *lwp_list;
(LP) != NULL; \
(LP) = (LP)->next, (PTID) = (LP) ? (LP)->ptid : (PTID))
#define GET_LWP(ptid) ptid_get_lwp (ptid)
#define GET_PID(ptid) ptid_get_pid (ptid)
#define is_lwp(ptid) (GET_LWP (ptid) != 0)
#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
/* Attempt to initialize libthread_db. */
void check_for_thread_db (void);

View file

@ -48,6 +48,32 @@
#define LIBTHREAD_DB_SO "libthread_db.so.1"
#endif
/* GNU/Linux libthread_db support.
libthread_db is a library, provided along with libpthread.so, which
exposes the internals of the thread library to a debugger. It
allows GDB to find existing threads, new threads as they are
created, thread IDs (usually, the result of pthread_self), and
thread-local variables.
The libthread_db interface originates on Solaris, where it is
both more powerful and more complicated. This implementation
only works for LinuxThreads and NPTL, the two glibc threading
libraries. It assumes that each thread is permanently assigned
to a single light-weight process (LWP).
libthread_db-specific information is stored in the "private" field
of struct thread_info. When the field is NULL we do not yet have
information about the new thread; this could be temporary (created,
but the thread library's data structures do not reflect it yet)
or permanent (created using clone instead of pthread_create).
Process IDs managed by linux-thread-db.c match those used by
linux-nat.c: a common PID for all processes, an LWP ID for each
thread, and no TID. We save the TID in private. Keeping it out
of the ptid_t prevents thread IDs changing when libpthread is
loaded or unloaded. */
/* If we're running on GNU/Linux, we must explicitly attach to any new
threads. */
@ -119,19 +145,7 @@ static CORE_ADDR td_death_bp_addr;
static void thread_db_find_new_threads (void);
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
const td_thrinfo_t *ti_p);
static void detach_thread (ptid_t ptid, int verbose);
/* Building process ids. */
#define GET_PID(ptid) ptid_get_pid (ptid)
#define GET_LWP(ptid) ptid_get_lwp (ptid)
#define GET_THREAD(ptid) ptid_get_tid (ptid)
#define is_lwp(ptid) (GET_LWP (ptid) != 0)
#define is_thread(ptid) (GET_THREAD (ptid) != 0)
#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0)
static void detach_thread (ptid_t ptid);
/* Use "struct private_thread_info" to cache thread state. This is
@ -143,11 +157,8 @@ struct private_thread_info
unsigned int dying:1;
/* Cached thread state. */
unsigned int th_valid:1;
unsigned int ti_valid:1;
td_thrhandle_t th;
td_thrinfo_t ti;
thread_t tid;
};
@ -257,7 +268,7 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *infop)
thread_db_err_str (err));
/* Fill the cache. */
thread_ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, ti.ti_tid);
thread_ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, 0);
thread_info = find_thread_pid (thread_ptid);
/* In the case of a zombie thread, don't continue. We don't want to
@ -266,13 +277,6 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *infop)
{
if (infop != NULL)
*(struct thread_info **) infop = thread_info;
if (thread_info != NULL)
{
memcpy (&thread_info->private->th, thp, sizeof (*thp));
thread_info->private->th_valid = 1;
memcpy (&thread_info->private->ti, &ti, sizeof (ti));
thread_info->private->ti_valid = 1;
}
return TD_THR_ZOMBIE;
}
@ -284,39 +288,11 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *infop)
gdb_assert (thread_info != NULL);
}
memcpy (&thread_info->private->th, thp, sizeof (*thp));
thread_info->private->th_valid = 1;
memcpy (&thread_info->private->ti, &ti, sizeof (ti));
thread_info->private->ti_valid = 1;
if (infop != NULL)
*(struct thread_info **) infop = thread_info;
return 0;
}
/* Accessor functions for the thread_db information, with caching. */
static void
thread_db_map_id2thr (struct thread_info *thread_info, int fatal)
{
td_err_e err;
if (thread_info->private->th_valid)
return;
err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (thread_info->ptid),
&thread_info->private->th);
if (err != TD_OK)
{
if (fatal)
error (_("Cannot find thread %ld: %s"),
(long) GET_THREAD (thread_info->ptid),
thread_db_err_str (err));
}
else
thread_info->private->th_valid = 1;
}
/* Convert between user-level thread ids and LWP ids. */
@ -328,10 +304,9 @@ thread_from_lwp (ptid_t ptid)
struct thread_info *thread_info;
ptid_t thread_ptid;
if (GET_LWP (ptid) == 0)
ptid = BUILD_LWP (GET_PID (ptid), GET_PID (ptid));
gdb_assert (is_lwp (ptid));
/* This ptid comes from linux-nat.c, which should always fill in the
LWP. */
gdb_assert (GET_LWP (ptid) != 0);
err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
if (err != TD_OK)
@ -352,16 +327,8 @@ thread_from_lwp (ptid_t ptid)
&& thread_info == NULL)
return pid_to_ptid (-1);
gdb_assert (thread_info && thread_info->private->ti_valid);
return ptid_build (GET_PID (ptid), GET_LWP (ptid),
thread_info->private->ti.ti_tid);
}
static ptid_t
lwp_from_thread (ptid_t ptid)
{
return BUILD_LWP (GET_LWP (ptid), GET_PID (ptid));
gdb_assert (ptid_get_tid (ptid) == 0);
return ptid;
}
@ -672,7 +639,8 @@ static void
attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
const td_thrinfo_t *ti_p)
{
struct thread_info *tp;
struct private_thread_info *private;
struct thread_info *tp = NULL;
td_err_e err;
/* If we're being called after a TD_CREATE event, we may already
@ -690,10 +658,21 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
tp = find_thread_pid (ptid);
gdb_assert (tp != NULL);
if (!tp->private->dying)
return;
/* If tp->private is NULL, then GDB is already attached to this
thread, but we do not know anything about it. We can learn
about it here. This can only happen if we have some other
way besides libthread_db to notice new threads (i.e.
PTRACE_EVENT_CLONE); assume the same mechanism notices thread
exit, so this can not be a stale thread recreated with the
same ID. */
if (tp->private != NULL)
{
if (!tp->private->dying)
return;
delete_thread (ptid);
delete_thread (ptid);
tp = NULL;
}
}
check_thread_signals ();
@ -702,13 +681,28 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
return; /* A zombie thread -- do not attach. */
/* Under GNU/Linux, we have to attach to each and every thread. */
if (lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))) < 0)
if (tp == NULL
&& lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))) < 0)
return;
/* Construct the thread's private data. */
private = xmalloc (sizeof (struct private_thread_info));
memset (private, 0, sizeof (struct private_thread_info));
/* A thread ID of zero may mean the thread library has not initialized
yet. But we shouldn't even get here if that's the case. FIXME:
if we change GDB to always have at least one thread in the thread
list this will have to go somewhere else; maybe private == NULL
until the thread_db target claims it. */
gdb_assert (ti_p->ti_tid != 0);
private->th = *th_p;
private->tid = ti_p->ti_tid;
/* 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 (tp == NULL)
tp = add_thread_with_info (ptid, private);
else
tp->private = private;
/* Enable thread event reporting for this thread. */
err = td_thr_event_enable_p (th_p, 1);
@ -718,22 +712,20 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
}
static void
detach_thread (ptid_t ptid, int verbose)
detach_thread (ptid_t ptid)
{
struct thread_info *thread_info;
if (verbose)
printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (ptid));
/* Don't delete the thread now, because it still reports as active
until it has executed a few instructions after the event
breakpoint - if we deleted it now, "info threads" would cause us
to re-attach to it. Just mark it as having had a TD_DEATH
event. This means that we won't delete it from our thread list
until we notice that it's dead (via prune_threads), or until
something re-uses its thread ID. */
something re-uses its thread ID. We'll report the thread exit
when the underlying LWP dies. */
thread_info = find_thread_pid (ptid);
gdb_assert (thread_info != NULL);
gdb_assert (thread_info != NULL && thread_info->private != NULL);
thread_info->private->dying = 1;
}
@ -742,47 +734,12 @@ thread_db_detach (char *args, int from_tty)
{
disable_thread_event_reporting ();
/* There's no need to save & restore inferior_ptid here, since the
inferior is not supposed to survive this function call. */
inferior_ptid = lwp_from_thread (inferior_ptid);
target_beneath->to_detach (args, from_tty);
/* Should this be done by detach_command? */
target_mourn_inferior ();
}
static int
clear_lwpid_callback (struct thread_info *thread, void *dummy)
{
/* If we know that our thread implementation is 1-to-1, we could save
a certain amount of information; it's not clear how much, so we
are always conservative. */
thread->private->th_valid = 0;
thread->private->ti_valid = 0;
return 0;
}
static void
thread_db_resume (ptid_t ptid, int step, enum target_signal signo)
{
struct cleanup *old_chain = save_inferior_ptid ();
if (GET_PID (ptid) == -1)
inferior_ptid = lwp_from_thread (inferior_ptid);
else if (is_thread (ptid))
ptid = lwp_from_thread (ptid);
/* Clear cached data which may not be valid after the resume. */
iterate_over_threads (clear_lwpid_callback, NULL);
target_beneath->to_resume (ptid, step, signo);
do_cleanups (old_chain);
}
/* Check if PID is currently stopped at the location of a thread event
breakpoint location. If it is, read the event message and act upon
the event. */
@ -833,7 +790,7 @@ check_event (ptid_t ptid)
if (err != TD_OK)
error (_("Cannot get thread info: %s"), thread_db_err_str (err));
ptid = ptid_build (GET_PID (ptid), ti.ti_lid, ti.ti_tid);
ptid = ptid_build (GET_PID (ptid), ti.ti_lid, 0);
switch (msg.event)
{
@ -849,7 +806,7 @@ check_event (ptid_t ptid)
if (!in_thread_list (ptid))
error (_("Spurious thread death event."));
detach_thread (ptid, print_thread_events);
detach_thread (ptid);
break;
@ -865,9 +822,6 @@ thread_db_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
{
extern ptid_t trap_ptid;
if (GET_PID (ptid) != -1 && is_thread (ptid))
ptid = lwp_from_thread (ptid);
ptid = target_beneath->to_wait (ptid, ourstatus);
if (ourstatus->kind == TARGET_WAITKIND_EXITED
@ -912,15 +866,6 @@ thread_db_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
return ptid;
}
static void
thread_db_kill (void)
{
/* There's no need to save & restore inferior_ptid here, since the
inferior isn't supposed to survive this function call. */
inferior_ptid = lwp_from_thread (inferior_ptid);
target_beneath->to_kill ();
}
static void
thread_db_mourn_inferior (void)
{
@ -954,7 +899,7 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
return 0; /* A zombie -- ignore. */
ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, ti.ti_tid);
ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, 0);
if (ti.ti_tid == 0)
{
@ -994,18 +939,17 @@ thread_db_find_new_threads (void)
static char *
thread_db_pid_to_str (ptid_t ptid)
{
if (is_thread (ptid))
struct thread_info *thread_info = find_thread_pid (ptid);
if (thread_info != NULL && thread_info->private != NULL)
{
static char buf[64];
struct thread_info *thread_info;
thread_t tid;
tid = thread_info->private->tid;
thread_info = find_thread_pid (ptid);
if (thread_info == NULL)
snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld) (Missing)",
GET_THREAD (ptid), GET_LWP (ptid));
else
snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)",
GET_THREAD (ptid), GET_LWP (ptid));
snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)",
tid, GET_LWP (ptid));
return buf;
}
@ -1022,22 +966,15 @@ thread_db_pid_to_str (ptid_t ptid)
static char *
thread_db_extra_thread_info (struct thread_info *info)
{
if (info->private == NULL)
return NULL;
if (info->private->dying)
return "Exiting";
return NULL;
}
/* Return 1 if this thread has the same LWP as the passed PTID. */
static int
same_ptid_callback (struct thread_info *thread, void *arg)
{
ptid_t *ptid_p = arg;
return GET_LWP (thread->ptid) == GET_LWP (*ptid_p);
}
/* Get the address of the thread local variable in load module LM which
is stored at OFFSET within the thread local storage for thread PTID. */
@ -1046,26 +983,19 @@ thread_db_get_thread_local_address (ptid_t ptid,
CORE_ADDR lm,
CORE_ADDR offset)
{
struct thread_info *thread_info;
/* If we have not discovered any threads yet, check now. */
if (!is_thread (ptid) && !have_threads ())
if (!have_threads ())
thread_db_find_new_threads ();
/* Try to find a matching thread if we still have the LWP ID instead
of the thread ID. */
if (!is_thread (ptid))
{
struct thread_info *thread;
/* Find the matching thread. */
thread_info = find_thread_pid (ptid);
thread = iterate_over_threads (same_ptid_callback, &ptid);
if (thread != NULL)
ptid = thread->ptid;
}
if (is_thread (ptid))
if (thread_info != NULL && thread_info->private != NULL)
{
td_err_e err;
void *address;
struct thread_info *thread_info;
/* glibc doesn't provide the needed interface. */
if (!td_thr_tls_get_addr_p)
@ -1075,11 +1005,6 @@ thread_db_get_thread_local_address (ptid_t ptid,
/* Caller should have verified that lm != 0. */
gdb_assert (lm != 0);
/* Get info about the thread. */
thread_info = find_thread_pid (ptid);
gdb_assert (thread_info);
thread_db_map_id2thr (thread_info, 1);
/* Finally, get the address of the variable. */
err = td_thr_tls_get_addr_p (&thread_info->private->th,
(void *)(size_t) lm,
@ -1122,9 +1047,7 @@ init_thread_db_ops (void)
thread_db_ops.to_longname = "multi-threaded child process.";
thread_db_ops.to_doc = "Threads and pthreads support.";
thread_db_ops.to_detach = thread_db_detach;
thread_db_ops.to_resume = thread_db_resume;
thread_db_ops.to_wait = thread_db_wait;
thread_db_ops.to_kill = thread_db_kill;
thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
thread_db_ops.to_find_new_threads = thread_db_find_new_threads;
thread_db_ops.to_pid_to_str = thread_db_pid_to_str;

View file

@ -4034,8 +4034,9 @@ wait_again:
case PR_SYSENTRY:
if (syscall_is_lwp_exit (pi, what))
{
printf_filtered (_("[%s exited]\n"),
target_pid_to_str (retval));
if (print_thread_events)
printf_unfiltered (_("[%s exited]\n"),
target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;
@ -4165,8 +4166,9 @@ wait_again:
}
else if (syscall_is_lwp_exit (pi, what))
{
printf_filtered (_("[%s exited]\n"),
target_pid_to_str (retval));
if (print_thread_events)
printf_unfiltered (_("[%s exited]\n"),
target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;

View file

@ -1,3 +1,7 @@
2008-03-21 Pedro Alves <pedro@codesourcery.com>
* gdb.threads/fork-child-threads.exp: Test next over fork.
2008-03-21 Chris Demetriou <cgd@google.com>
* gdb.base/break.exp (rbreak junk): New test for rbreak

View file

@ -38,6 +38,10 @@ if ![runto_main] then {
gdb_test "set follow-fork-mode child"
gdb_breakpoint "start"
# Make sure we can step over fork without losing our breakpoint.
gdb_test "next" ".*pthread_create \\(&thread, NULL, start, NULL\\);.*" "next over fork"
gdb_test "continue" "Breakpoint 2, start.*" "get to the spawned thread"
# Wrong:

View file

@ -132,10 +132,12 @@ add_thread_silent (ptid_t ptid)
}
struct thread_info *
add_thread (ptid_t ptid)
add_thread_with_info (ptid_t ptid, struct private_thread_info *private)
{
struct thread_info *result = add_thread_silent (ptid);
result->private = private;
if (print_thread_events)
printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
@ -144,6 +146,12 @@ add_thread (ptid_t ptid)
return result;
}
struct thread_info *
add_thread (ptid_t ptid)
{
return add_thread_with_info (ptid, NULL);
}
void
delete_thread (ptid_t ptid)
{