* inf-ttrace.c: Include "gdbthread.h".

(inf_ttrace_num_lwps): New variable.
(inf_ttrace_num_lwps_in_syscall): Renamed from
inf_ttrace_num_threads_in_syscall.
(inf_ttrace_him): Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
TTEVT_LWP_TERMINATE events.
(inf_ttrace_create_inferior): Assert that INF_TTRACE_NUM_LWPS is
zero.
(inf_ttrace_mourn_inferior): Set INF_TTRACE_NUM_LWPS to zero.
(inf_ttrace_attach): Assert that INF_TTRACE_NUM_LWPS is zero.
Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and TTEVT_LWP_TERMINATE
events.
(inf_ttrace_wait): Report status as TARGET_WAITKIND_SPURIOUS by
default.  Handle TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
TTEVT_LWP_TERMINATE events.
(inf_ttrace_thread_alive, inf_ttrace_pid_to_str): New functions.
(inf_ttrace_target): Set to_thread_alive and to_pid_to_str.
* Makefile.in (inf-ttrace.o): Update dependencies.
This commit is contained in:
Mark Kettenis 2004-12-07 19:57:21 +00:00
parent cc72850f95
commit a7be7fa8ef
3 changed files with 129 additions and 25 deletions

View File

@ -1,5 +1,24 @@
2004-12-07 Mark Kettenis <kettenis@gnu.org>
* inf-ttrace.c: Include "gdbthread.h".
(inf_ttrace_num_lwps): New variable.
(inf_ttrace_num_lwps_in_syscall): Renamed from
inf_ttrace_num_threads_in_syscall.
(inf_ttrace_him): Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
TTEVT_LWP_TERMINATE events.
(inf_ttrace_create_inferior): Assert that INF_TTRACE_NUM_LWPS is
zero.
(inf_ttrace_mourn_inferior): Set INF_TTRACE_NUM_LWPS to zero.
(inf_ttrace_attach): Assert that INF_TTRACE_NUM_LWPS is zero.
Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and TTEVT_LWP_TERMINATE
events.
(inf_ttrace_wait): Report status as TARGET_WAITKIND_SPURIOUS by
default. Handle TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
TTEVT_LWP_TERMINATE events.
(inf_ttrace_thread_alive, inf_ttrace_pid_to_str): New functions.
(inf_ttrace_target): Set to_thread_alive and to_pid_to_str.
* Makefile.in (inf-ttrace.o): Update dependencies.
* hppa-tdep.h (hppa_read_pc, hppa_write_pc, hppa_unwind_pc): New
prototypes.
* hppa-tdep.c (hppa_read_pc): Rename from hppa_target_read_pc.

View File

@ -2088,9 +2088,9 @@ inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
inf-ptrace.o: inf-ptrace.c $(defs_h) $(command_h) $(inferior_h) $(inflow_h) \
$(gdbcore_h) $(observer_h) $(gdb_string_h) $(gdb_ptrace_h) \
$(gdb_wait_h) $(inf_child_h)
inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(inferior_h) \
$(observer_h) $(target_h) $(gdb_assert_h) $(gdb_string_h) \
$(inf_child_h) $(inf_ttrace_h)
inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(gdbcore_h) \
$(gdbthread_h)$(inferior_h) $(observer_h) $(target_h) \
$(gdb_assert_h) $(gdb_string_h) $(inf_child_h) $(inf_ttrace_h)
infptrace.o: infptrace.c $(defs_h) $(command_h) $(frame_h) $(gdbcore_h) \
$(inferior_h) $(regcache_h) $(target_h) $(gdb_assert_h) \
$(gdb_wait_h) $(gdb_string_h) $(gdb_dirent_h) $(gdb_ptrace_h)

View File

@ -27,6 +27,7 @@
#include "command.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "inferior.h"
#include "observer.h"
#include "target.h"
@ -43,6 +44,19 @@
static struct target_ops *ttrace_ops_hack;
/* HP-UX uses a threading model where each user-space thread
corresponds to a kernel thread. These kernel threads are called
lwps. The ttrace(2) interface gives us almost full control over
the threads, which makes it very easy to support them in GDB. We
identify the threads by process ID and lwp ID. The ttrace(2) also
provides us with a thread's user ID (in the `tts_user_tid' member
of `ttstate_t') but we don't use that (yet) as it isn't necessary
to uniquely label the thread. */
/* Number of active lwps. */
static int inf_ttrace_num_lwps;
/* On HP-UX versions that have the ttrace(2) system call, we can
implement "hardware" watchpoints by fiddling with the protection of
pages in the address space that contain the variable being watched.
@ -65,8 +79,8 @@ struct inf_ttrace_page_dict
int count; /* Number of pages in this dictionary. */
} inf_ttrace_page_dict;
/* Number of threads that are currently in a system call. */
static int inf_ttrace_num_threads_in_syscall;
/* Number of lwps that are currently in a system call. */
static int inf_ttrace_num_lwps_in_syscall;
/* Flag to indicate whether we should re-enable page protections after
the next wait. */
@ -80,7 +94,7 @@ inf_ttrace_enable_syscall_events (pid_t pid)
ttevent_t tte;
ttstate_t tts;
gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
@ -97,7 +111,7 @@ inf_ttrace_enable_syscall_events (pid_t pid)
perror_with_name ("ttrace");
if (tts.tts_flags & TTS_INSYSCALL)
inf_ttrace_num_threads_in_syscall++;
inf_ttrace_num_lwps_in_syscall++;
/* FIXME: Handle multiple threads. */
}
@ -121,7 +135,7 @@ inf_ttrace_disable_syscall_events (pid_t pid)
(uintptr_t)&tte, sizeof tte, 0) == -1)
perror_with_name ("ttrace");
inf_ttrace_num_threads_in_syscall = 0;
inf_ttrace_num_lwps_in_syscall = 0;
}
/* Get information about the page at address ADDR for process PID from
@ -191,7 +205,7 @@ inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
if (inf_ttrace_page_dict.count == 1)
inf_ttrace_enable_syscall_events (pid);
if (inf_ttrace_num_threads_in_syscall == 0)
if (inf_ttrace_num_lwps_in_syscall == 0)
{
if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
addr, pagesize, prot & ~PROT_WRITE) == -1)
@ -231,7 +245,7 @@ inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr)
if (page->refcount == 0)
{
if (inf_ttrace_num_threads_in_syscall == 0)
if (inf_ttrace_num_lwps_in_syscall == 0)
{
if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
addr, pagesize, page->prot) == -1)
@ -449,7 +463,8 @@ inf_ttrace_him (int pid)
/* Set the initial event mask. */
memset (&tte, 0, sizeof (tte));
tte.tte_events = TTEVT_EXEC | TTEVT_EXIT;
tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT;
tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
tte.tte_opts = TTEO_NOSTRCCHLD;
if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
@ -484,8 +499,9 @@ static void
inf_ttrace_create_inferior (char *exec_file, char *allargs, char **env,
int from_tty)
{
gdb_assert (inf_ttrace_num_lwps == 0);
gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
gdb_assert (inf_ttrace_page_dict.count == 0);
gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
gdb_assert (inf_ttrace_reenable_page_protections == 0);
fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
@ -518,7 +534,8 @@ inf_ttrace_mourn_inferior (void)
const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
int bucket;
inf_ttrace_num_threads_in_syscall = 0;
inf_ttrace_num_lwps = 0;
inf_ttrace_num_lwps_in_syscall = 0;
for (bucket = 0; bucket < num_buckets; bucket++)
{
@ -572,14 +589,17 @@ inf_ttrace_attach (char *args, int from_tty)
gdb_flush (gdb_stdout);
}
gdb_assert (inf_ttrace_num_lwps == 0);
gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
perror_with_name ("ttrace");
attach_flag = 1;
/* Set the initial event mask. */
gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
memset (&tte, 0, sizeof (tte));
tte.tte_events = TTEVT_EXEC | TTEVT_EXIT;
tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT;
tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
tte.tte_opts = TTEO_NOSTRCCHLD;
if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
@ -616,7 +636,8 @@ inf_ttrace_detach (char *args, int from_tty)
if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
perror_with_name ("ttrace");
inf_ttrace_num_threads_in_syscall = 0;
inf_ttrace_num_lwps = 0;
inf_ttrace_num_lwps_in_syscall = 0;
unpush_target (ttrace_ops_hack);
inferior_ptid = null_ptid;
@ -655,7 +676,7 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
ttstate_t tts;
/* Until proven otherwise. */
ourstatus->kind = TARGET_WAITKIND_IGNORE;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
if (pid == -1)
pid = 0;
@ -678,11 +699,13 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
/* Now that we've waited, we can re-enable the page protections. */
if (inf_ttrace_reenable_page_protections)
{
gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
inf_ttrace_enable_page_protections (tts.tts_pid);
inf_ttrace_reenable_page_protections = 0;
}
ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
switch (tts.tts_event)
{
case TTEVT_EXEC:
@ -693,6 +716,40 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
case TTEVT_EXIT:
store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
inf_ttrace_num_lwps = 0;
break;
case TTEVT_LWP_CREATE:
lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
ptid = ptid_build (tts.tts_pid, lwpid, 0);
if (inf_ttrace_num_lwps == 0)
{
/* Now that we're going to be multi-threaded, add the
origional thread to the list first. */
add_thread (ptid_build (tts.tts_pid, tts.tts_lwpid, 0));
inf_ttrace_num_lwps++;
}
printf_filtered ("[New %s]\n", target_pid_to_str (ptid));
add_thread (ptid);
inf_ttrace_num_lwps++;
ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
break;
case TTEVT_LWP_EXIT:
printf_filtered("[%s exited]\n", target_pid_to_str (ptid));
delete_thread (ptid);
inf_ttrace_num_lwps--;
/* If we don't return -1 here, core GDB will re-add the thread. */
ptid = minus_one_ptid;
break;
case TTEVT_LWP_TERMINATE:
lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
ptid = ptid_build (tts.tts_pid, lwpid, 0);
printf_filtered("[%s has been terminated]\n", target_pid_to_str (ptid));
delete_thread (ptid);
inf_ttrace_num_lwps--;
ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
break;
case TTEVT_SIGNAL:
@ -703,8 +760,8 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
case TTEVT_SYSCALL_ENTRY:
gdb_assert (inf_ttrace_reenable_page_protections == 0);
inf_ttrace_num_threads_in_syscall++;
if (inf_ttrace_num_threads_in_syscall == 1)
inf_ttrace_num_lwps_in_syscall++;
if (inf_ttrace_num_lwps_in_syscall == 1)
{
/* A thread has just entered a system call. Disable any
page protections as the kernel can't deal with them. */
@ -715,19 +772,23 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
break;
case TTEVT_SYSCALL_RETURN:
if (inf_ttrace_num_threads_in_syscall > 0)
if (inf_ttrace_num_lwps_in_syscall > 0)
{
/* If the last thread has just left the system call, this
would be a logical place to re-enable the page
protections, but that doesn't work. We can't re-enable
them until we've done another wait. */
inf_ttrace_reenable_page_protections =
(inf_ttrace_num_threads_in_syscall == 1);
inf_ttrace_num_threads_in_syscall--;
(inf_ttrace_num_lwps_in_syscall == 1);
inf_ttrace_num_lwps_in_syscall--;
}
ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
ourstatus->value.syscall_id = tts.tts_scno;
break;
default:
gdb_assert (!"Unexpected ttrace event");
break;
}
/* Make sure all threads within the process are stopped. */
@ -737,9 +798,9 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
/* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
process isn't recognized as a new thread. */
if (ptid_get_lwp (inferior_ptid) == 0)
inferior_ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
inferior_ptid = ptid;
return ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
return ptid;
}
/* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
@ -805,6 +866,28 @@ inf_ttrace_files_info (struct target_ops *ignore)
attach_flag ? "attached" : "child",
target_pid_to_str (inferior_ptid));
}
static int
inf_ttrace_thread_alive (ptid_t ptid)
{
return 1;
}
static char *
inf_ttrace_pid_to_str (ptid_t ptid)
{
if (inf_ttrace_num_lwps > 0)
{
pid_t pid = ptid_get_pid (ptid);
lwpid_t lwpid = ptid_get_lwp (ptid);
static char buf[80];
sprintf (buf, "process %ld, lwp %ld", (long)pid, (long)lwpid);
return buf;
}
return normal_pid_to_str (ptid);
}
struct target_ops *
@ -821,6 +904,8 @@ inf_ttrace_target (void)
t->to_wait = inf_ttrace_wait;
t->to_xfer_partial = inf_ttrace_xfer_partial;
t->to_files_info = inf_ttrace_files_info;
t->to_thread_alive = inf_ttrace_thread_alive;
t->to_pid_to_str = inf_ttrace_pid_to_str;
t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
t->to_region_size_ok_for_hw_watchpoint =
inf_ttrace_region_size_ok_for_hw_watchpoint;