#include "defs.h"
#ifdef HAVE_TTRACE
#include "command.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "inferior.h"
#include "observer.h"
#include "target.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include <sys/mman.h>
#include <sys/ttrace.h>
#include "inf-child.h"
#include "inf-ttrace.h"
static struct target_ops *ttrace_ops_hack;
static int inf_ttrace_num_lwps;
struct inf_ttrace_page
{
CORE_ADDR addr;
int prot;
int refcount;
struct inf_ttrace_page *next;
struct inf_ttrace_page *prev;
};
struct inf_ttrace_page_dict
{
struct inf_ttrace_page buckets[128];
int pagesize;
int count;
} inf_ttrace_page_dict;
static int inf_ttrace_num_lwps_in_syscall;
static int inf_ttrace_reenable_page_protections;
static void
inf_ttrace_enable_syscall_events (pid_t pid)
{
ttevent_t tte;
ttstate_t tts;
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)
perror_with_name (("ttrace"));
tte.tte_events |= (TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
perror_with_name (("ttrace"));
if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
(uintptr_t)&tts, sizeof tts, 0) == -1)
perror_with_name (("ttrace"));
if (tts.tts_flags & TTS_INSYSCALL)
inf_ttrace_num_lwps_in_syscall++;
}
static void
inf_ttrace_disable_syscall_events (pid_t pid)
{
ttevent_t tte;
gdb_assert (inf_ttrace_page_dict.count == 0);
if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
perror_with_name (("ttrace"));
tte.tte_events &= ~(TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
perror_with_name (("ttrace"));
inf_ttrace_num_lwps_in_syscall = 0;
}
static struct inf_ttrace_page *
inf_ttrace_get_page (pid_t pid, CORE_ADDR addr)
{
const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
const int pagesize = inf_ttrace_page_dict.pagesize;
int bucket;
struct inf_ttrace_page *page;
bucket = (addr / pagesize) % num_buckets;
page = &inf_ttrace_page_dict.buckets[bucket];
while (page)
{
if (page->addr == addr)
break;
page = page->next;
}
return page;
}
static struct inf_ttrace_page *
inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
{
const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
const int pagesize = inf_ttrace_page_dict.pagesize;
int bucket;
struct inf_ttrace_page *page;
struct inf_ttrace_page *prev = NULL;
bucket = (addr / pagesize) % num_buckets;
page = &inf_ttrace_page_dict.buckets[bucket];
while (page)
{
if (page->addr == addr)
break;
prev = page;
page = page->next;
}
if (!page)
{
int prot;
if (ttrace (TT_PROC_GET_MPROTECT, pid, 0,
addr, 0, (uintptr_t)&prot) == -1)
perror_with_name (("ttrace"));
page = XMALLOC (struct inf_ttrace_page);
page->addr = addr;
page->prot = prot;
page->refcount = 0;
page->next = NULL;
page->prev = prev;
prev->next = page;
inf_ttrace_page_dict.count++;
if (inf_ttrace_page_dict.count == 1)
inf_ttrace_enable_syscall_events (pid);
if (inf_ttrace_num_lwps_in_syscall == 0)
{
if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
addr, pagesize, prot & ~PROT_WRITE) == -1)
perror_with_name (("ttrace"));
}
}
return page;
}
static void
inf_ttrace_insert_page (pid_t pid, CORE_ADDR addr)
{
struct inf_ttrace_page *page;
page = inf_ttrace_get_page (pid, addr);
if (!page)
page = inf_ttrace_add_page (pid, addr);
page->refcount++;
}
static void
inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr)
{
const int pagesize = inf_ttrace_page_dict.pagesize;
struct inf_ttrace_page *page;
page = inf_ttrace_get_page (pid, addr);
page->refcount--;
gdb_assert (page->refcount >= 0);
if (page->refcount == 0)
{
if (inf_ttrace_num_lwps_in_syscall == 0)
{
if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
addr, pagesize, page->prot) == -1)
perror_with_name (("ttrace"));
}
inf_ttrace_page_dict.count--;
if (inf_ttrace_page_dict.count == 0)
inf_ttrace_disable_syscall_events (pid);
page->prev->next = page->next;
if (page->next)
page->next->prev = page->prev;
xfree (page);
}
}
static void
inf_ttrace_mask_page_protections (pid_t pid, int prot)
{
const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
const int pagesize = inf_ttrace_page_dict.pagesize;
int bucket;
for (bucket = 0; bucket < num_buckets; bucket++)
{
struct inf_ttrace_page *page;
page = inf_ttrace_page_dict.buckets[bucket].next;
while (page)
{
if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
page->addr, pagesize, page->prot & ~prot) == -1)
perror_with_name (("ttrace"));
page = page->next;
}
}
}
static void
inf_ttrace_enable_page_protections (pid_t pid)
{
inf_ttrace_mask_page_protections (pid, PROT_WRITE);
}
static void
inf_ttrace_disable_page_protections (pid_t pid)
{
inf_ttrace_mask_page_protections (pid, 0);
}
static int
inf_ttrace_insert_watchpoint (CORE_ADDR addr, int len, int type)
{
const int pagesize = inf_ttrace_page_dict.pagesize;
pid_t pid = ptid_get_pid (inferior_ptid);
CORE_ADDR page_addr;
int num_pages;
int page;
gdb_assert (type == hw_write);
page_addr = (addr / pagesize) * pagesize;
num_pages = (len + pagesize - 1) / pagesize;
for (page = 0; page < num_pages; page++, page_addr += pagesize)
inf_ttrace_insert_page (pid, page_addr);
return 1;
}
static int
inf_ttrace_remove_watchpoint (CORE_ADDR addr, int len, int type)
{
const int pagesize = inf_ttrace_page_dict.pagesize;
pid_t pid = ptid_get_pid (inferior_ptid);
CORE_ADDR page_addr;
int num_pages;
int page;
gdb_assert (type == hw_write);
page_addr = (addr / pagesize) * pagesize;
num_pages = (len + pagesize - 1) / pagesize;
for (page = 0; page < num_pages; page++, page_addr += pagesize)
inf_ttrace_remove_page (pid, page_addr);
return 1;
}
static int
inf_ttrace_can_use_hw_breakpoint (int type, int len, int ot)
{
return (type == bp_hardware_watchpoint);
}
static int
inf_ttrace_region_size_ok_for_hw_watchpoint (int len)
{
return 1;
}
static int
inf_ttrace_stopped_by_watchpoint (void)
{
pid_t pid = ptid_get_pid (inferior_ptid);
lwpid_t lwpid = ptid_get_lwp (inferior_ptid);
ttstate_t tts;
if (inf_ttrace_page_dict.count > 0)
{
if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
(uintptr_t)&tts, sizeof tts, 0) == -1)
perror_with_name (("ttrace"));
if (tts.tts_event == TTEVT_SIGNAL
&& tts.tts_u.tts_signal.tts_signo == SIGBUS)
{
const int pagesize = inf_ttrace_page_dict.pagesize;
void *addr = tts.tts_u.tts_signal.tts_siginfo.si_addr;
CORE_ADDR page_addr = ((uintptr_t)addr / pagesize) * pagesize;
if (inf_ttrace_get_page (pid, page_addr))
return 1;
}
}
return 0;
}
static pid_t inf_ttrace_vfork_ppid = -1;
static int
inf_ttrace_follow_fork (int follow_child)
{
pid_t pid, fpid;
lwpid_t lwpid, flwpid;
ttstate_t tts;
{
ptid_t ptid;
struct target_waitstatus status;
get_last_target_status (&ptid, &status);
gdb_assert (status.kind == TARGET_WAITKIND_FORKED
|| status.kind == TARGET_WAITKIND_VFORKED);
pid = ptid_get_pid (ptid);
lwpid = ptid_get_lwp (ptid);
}
if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
(uintptr_t)&tts, sizeof tts, 0) == -1)
perror_with_name (("ttrace"));
gdb_assert (tts.tts_event == TTEVT_FORK || tts.tts_event == TTEVT_VFORK);
if (tts.tts_u.tts_fork.tts_isparent)
{
pid = tts.tts_pid;
lwpid = tts.tts_lwpid;
fpid = tts.tts_u.tts_fork.tts_fpid;
flwpid = tts.tts_u.tts_fork.tts_flwpid;
}
else
{
pid = tts.tts_u.tts_fork.tts_fpid;
lwpid = tts.tts_u.tts_fork.tts_flwpid;
fpid = tts.tts_pid;
flwpid = tts.tts_lwpid;
}
if (follow_child)
{
inferior_ptid = ptid_build (fpid, flwpid, 0);
detach_breakpoints (pid);
target_terminal_ours ();
fprintf_unfiltered (gdb_stdlog, _("\
Attaching after fork to child process %ld.\n"), (long)fpid);
}
else
{
inferior_ptid = ptid_build (pid, lwpid, 0);
detach_breakpoints (fpid);
target_terminal_ours ();
fprintf_unfiltered (gdb_stdlog, _("\
Detaching after fork from child process %ld.\n"), (long)fpid);
}
if (tts.tts_event == TTEVT_VFORK)
{
gdb_assert (!tts.tts_u.tts_fork.tts_isparent);
if (follow_child)
{
inf_ttrace_vfork_ppid = pid;
reattach_breakpoints (fpid);
}
else
{
if (ttrace (TT_PROC_DETACH, fpid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
perror_with_name (("ttrace_wait"));
gdb_assert (tts.tts_event == TTEVT_VFORK);
gdb_assert (tts.tts_u.tts_fork.tts_isparent);
reattach_breakpoints (pid);
}
}
else
{
gdb_assert (tts.tts_u.tts_fork.tts_isparent);
if (follow_child)
{
if (ttrace (TT_PROC_DETACH, pid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
}
else
{
if (ttrace (TT_PROC_DETACH, fpid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
}
}
if (follow_child)
{
inf_ttrace_num_lwps = 0;
inf_ttrace_num_lwps_in_syscall = 0;
follow_inferior_reset_breakpoints ();
}
return 0;
}
static int inf_ttrace_pfd1[2];
static int inf_ttrace_pfd2[2];
static void
do_cleanup_pfds (void *dummy)
{
close (inf_ttrace_pfd1[0]);
close (inf_ttrace_pfd1[1]);
close (inf_ttrace_pfd2[0]);
close (inf_ttrace_pfd2[1]);
}
static void
inf_ttrace_prepare (void)
{
if (pipe (inf_ttrace_pfd1) == -1)
perror_with_name (("pipe"));
if (pipe (inf_ttrace_pfd2) == -1)
{
close (inf_ttrace_pfd1[0]);
close (inf_ttrace_pfd2[0]);
perror_with_name (("pipe"));
}
}
static void
inf_ttrace_me (void)
{
struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
char c;
if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
perror_with_name (("ttrace"));
if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
perror_with_name (("write"));
if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
perror_with_name (("read"));
do_cleanups (old_chain);
}
static void
inf_ttrace_him (int pid)
{
struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
ttevent_t tte;
char c;
if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c)
perror_with_name (("read"));
memset (&tte, 0, sizeof (tte));
tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
#ifdef TTEVT_BPT_SSTEP
tte.tte_events |= TTEVT_BPT_SSTEP;
#endif
tte.tte_opts |= TTEO_PROC_INHERIT;
if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
perror_with_name (("ttrace"));
if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c)
perror_with_name (("write"));
do_cleanups (old_chain);
push_target (ttrace_ops_hack);
target_acknowledge_created_inferior (pid);
startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
target_post_startup_inferior (pid_to_ptid (pid));
}
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_reenable_page_protections == 0);
gdb_assert (inf_ttrace_vfork_ppid == -1);
fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
inf_ttrace_prepare, NULL);
observer_notify_inferior_created (¤t_target, from_tty);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
}
static void
inf_ttrace_kill_inferior (void)
{
pid_t pid = ptid_get_pid (inferior_ptid);
if (pid == 0)
return;
if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
if (inf_ttrace_vfork_ppid != -1)
{
if (ttrace (TT_PROC_DETACH, inf_ttrace_vfork_ppid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
inf_ttrace_vfork_ppid = -1;
}
target_mourn_inferior ();
}
static void
inf_ttrace_mourn_inferior (void)
{
const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
int bucket;
inf_ttrace_num_lwps = 0;
inf_ttrace_num_lwps_in_syscall = 0;
for (bucket = 0; bucket < num_buckets; bucket++)
{
struct inf_ttrace_page *page;
struct inf_ttrace_page *next;
page = inf_ttrace_page_dict.buckets[bucket].next;
while (page)
{
next = page->next;
xfree (page);
page = next;
}
}
inf_ttrace_page_dict.count = 0;
unpush_target (ttrace_ops_hack);
generic_mourn_inferior ();
}
static void
inf_ttrace_attach (char *args, int from_tty)
{
char *exec_file;
pid_t pid;
char *dummy;
ttevent_t tte;
if (!args)
error_no_arg (_("process-id to attach"));
dummy = args;
pid = strtol (args, &dummy, 0);
if (pid == 0 && args == dummy)
error (_("Illegal process-id: %s."), args);
if (pid == getpid ())
error (_("I refuse to debug myself!"));
if (from_tty)
{
exec_file = (char *) get_exec_file (0);
if (exec_file)
printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
target_pid_to_str (pid_to_ptid (pid)));
else
printf_unfiltered (_("Attaching to %s\n"),
target_pid_to_str (pid_to_ptid (pid)));
gdb_flush (gdb_stdout);
}
gdb_assert (inf_ttrace_num_lwps == 0);
gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
gdb_assert (inf_ttrace_vfork_ppid == -1);
if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
perror_with_name (("ttrace"));
attach_flag = 1;
memset (&tte, 0, sizeof (tte));
tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
#ifdef TTEVT_BPT_SSTEP
tte.tte_events |= TTEVT_BPT_SSTEP;
#endif
tte.tte_opts |= TTEO_PROC_INHERIT;
if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
(uintptr_t)&tte, sizeof tte, 0) == -1)
perror_with_name (("ttrace"));
inferior_ptid = pid_to_ptid (pid);
push_target (ttrace_ops_hack);
observer_notify_inferior_created (¤t_target, from_tty);
}
static void
inf_ttrace_detach (char *args, int from_tty)
{
pid_t pid = ptid_get_pid (inferior_ptid);
int sig = 0;
if (from_tty)
{
char *exec_file = get_exec_file (0);
if (exec_file == 0)
exec_file = "";
printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
target_pid_to_str (pid_to_ptid (pid)));
gdb_flush (gdb_stdout);
}
if (args)
sig = atoi (args);
if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
perror_with_name (("ttrace"));
if (inf_ttrace_vfork_ppid != -1)
{
if (ttrace (TT_PROC_DETACH, inf_ttrace_vfork_ppid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
inf_ttrace_vfork_ppid = -1;
}
inf_ttrace_num_lwps = 0;
inf_ttrace_num_lwps_in_syscall = 0;
unpush_target (ttrace_ops_hack);
inferior_ptid = null_ptid;
}
static int
inf_ttrace_resume_callback (struct thread_info *info, void *arg)
{
if (!ptid_equal (info->ptid, inferior_ptid))
{
pid_t pid = ptid_get_pid (info->ptid);
lwpid_t lwpid = ptid_get_lwp (info->ptid);
if (ttrace (TT_LWP_CONTINUE, pid, lwpid, TT_NOPC, 0, 0) == -1)
perror_with_name (("ttrace"));
}
return 0;
}
static void
inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
{
pid_t pid = ptid_get_pid (ptid);
lwpid_t lwpid = ptid_get_lwp (ptid);
ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE;
int sig = target_signal_to_host (signal);
if (pid == -1)
{
pid = ptid_get_pid (inferior_ptid);
lwpid = ptid_get_lwp (inferior_ptid);
}
if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
perror_with_name (("ttrace"));
if (ptid_equal (ptid, minus_one_ptid) && inf_ttrace_num_lwps > 0)
{
iterate_over_threads (inf_ttrace_resume_callback, NULL);
}
}
static ptid_t
inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
{
pid_t pid = ptid_get_pid (ptid);
lwpid_t lwpid = ptid_get_lwp (ptid);
ttstate_t tts;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
if (pid == -1)
pid = lwpid = 0;
gdb_assert (pid != 0 || lwpid == 0);
do
{
set_sigint_trap ();
set_sigio_trap ();
if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
perror_with_name (("ttrace_wait"));
if (tts.tts_event == TTEVT_VFORK && tts.tts_u.tts_fork.tts_isparent)
{
if (inf_ttrace_vfork_ppid != -1)
{
gdb_assert (inf_ttrace_vfork_ppid == tts.tts_pid);
if (ttrace (TT_PROC_DETACH, tts.tts_pid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
inf_ttrace_vfork_ppid = -1;
}
tts.tts_event = TTEVT_NONE;
}
clear_sigio_trap ();
clear_sigint_trap ();
}
while (tts.tts_event == TTEVT_NONE);
if (inf_ttrace_reenable_page_protections)
{
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)
{
#ifdef TTEVT_BPT_SSTEP
case TTEVT_BPT_SSTEP:
ourstatus->kind = TARGET_WAITKIND_STOPPED;
ourstatus->value.sig = TARGET_SIGNAL_TRAP;
break;
#endif
case TTEVT_EXEC:
ourstatus->kind = TARGET_WAITKIND_EXECD;
ourstatus->value.execd_pathname =
xmalloc (tts.tts_u.tts_exec.tts_pathlen + 1);
if (ttrace (TT_PROC_GET_PATHNAME, tts.tts_pid, 0,
(uintptr_t)ourstatus->value.execd_pathname,
tts.tts_u.tts_exec.tts_pathlen, 0) == -1)
perror_with_name (("ttrace"));
ourstatus->value.execd_pathname[tts.tts_u.tts_exec.tts_pathlen] = 0;
break;
case TTEVT_EXIT:
store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
inf_ttrace_num_lwps = 0;
break;
case TTEVT_FORK:
ourstatus->kind = TARGET_WAITKIND_FORKED;
ourstatus->value.related_pid = tts.tts_u.tts_fork.tts_fpid;
if (ttrace_wait (tts.tts_u.tts_fork.tts_fpid,
tts.tts_u.tts_fork.tts_flwpid,
TTRACE_WAITOK, &tts, sizeof tts) == -1)
perror_with_name (("ttrace_wait"));
gdb_assert (tts.tts_event == TTEVT_FORK);
if (tts.tts_u.tts_fork.tts_isparent)
{
ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
ourstatus->value.related_pid = tts.tts_u.tts_fork.tts_fpid;
}
break;
case TTEVT_VFORK:
gdb_assert (!tts.tts_u.tts_fork.tts_isparent);
ourstatus->kind = TARGET_WAITKIND_VFORKED;
ourstatus->value.related_pid = tts.tts_u.tts_fork.tts_fpid;
inferior_ptid = ptid;
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)
{
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--;
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:
ourstatus->kind = TARGET_WAITKIND_STOPPED;
ourstatus->value.sig =
target_signal_from_host (tts.tts_u.tts_signal.tts_signo);
break;
case TTEVT_SYSCALL_ENTRY:
gdb_assert (inf_ttrace_reenable_page_protections == 0);
inf_ttrace_num_lwps_in_syscall++;
if (inf_ttrace_num_lwps_in_syscall == 1)
{
inf_ttrace_disable_page_protections (tts.tts_pid);
}
ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
ourstatus->value.syscall_id = tts.tts_scno;
break;
case TTEVT_SYSCALL_RETURN:
if (inf_ttrace_num_lwps_in_syscall > 0)
{
inf_ttrace_reenable_page_protections =
(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;
}
if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1)
perror_with_name (("ttrace"));
if (ptid_get_lwp (inferior_ptid) == 0)
inferior_ptid = ptid;
return ptid;
}
static LONGEST
inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len,
void *readbuf, const void *writebuf)
{
pid_t pid = ptid_get_pid (inferior_ptid);
if (readbuf
&& ttrace (TT_PROC_RDTEXT, pid, 0, addr, len, (uintptr_t)readbuf) == -1
&& ttrace (TT_PROC_RDDATA, pid, 0, addr, len, (uintptr_t)readbuf) == -1)
return 0;
if (writebuf
&& ttrace (TT_PROC_WRTEXT, pid, 0, addr, len, (uintptr_t)writebuf) == -1
&& ttrace (TT_PROC_WRDATA, pid, 0, addr, len, (uintptr_t)writebuf) == -1)
return 0;
return len;
}
static LONGEST
inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
switch (object)
{
case TARGET_OBJECT_MEMORY:
return inf_ttrace_xfer_memory (offset, len, readbuf, writebuf);
case TARGET_OBJECT_UNWIND_TABLE:
return -1;
case TARGET_OBJECT_AUXV:
return -1;
case TARGET_OBJECT_WCOOKIE:
return -1;
default:
return -1;
}
}
static void
inf_ttrace_files_info (struct target_ops *ignore)
{
printf_unfiltered (_("\tUsing the running image of %s %s.\n"),
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[128];
xsnprintf (buf, sizeof buf, "process %ld, lwp %ld",
(long)pid, (long)lwpid);
return buf;
}
return normal_pid_to_str (ptid);
}
struct target_ops *
inf_ttrace_target (void)
{
struct target_ops *t = inf_child_target ();
t->to_create_inferior = inf_ttrace_create_inferior;
t->to_kill = inf_ttrace_kill_inferior;
t->to_mourn_inferior = inf_ttrace_mourn_inferior;
t->to_attach = inf_ttrace_attach;
t->to_detach = inf_ttrace_detach;
t->to_resume = inf_ttrace_resume;
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_follow_fork = inf_ttrace_follow_fork;
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;
t->to_insert_watchpoint = inf_ttrace_insert_watchpoint;
t->to_remove_watchpoint = inf_ttrace_remove_watchpoint;
t->to_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint;
ttrace_ops_hack = t;
return t;
}
#endif
void _initialize_hppa_hpux_nat (void);
void
_initialize_inf_ttrace (void)
{
#ifdef HAVE_TTRACE
inf_ttrace_page_dict.pagesize = getpagesize();
#endif
}