-/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
+/* Copyright (C) 2009-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include <sys/types.h>
#include "gdb_wait.h"
#include <signal.h>
+#include "filestuff.h"
int using_threads = 1;
+const struct target_desc *lynx_tdesc;
+
/* Per-process private data. */
struct process_info_private
struct process_info *proc;
proc = add_process (pid, attached);
- proc->private = xcalloc (1, sizeof (*proc->private));
- proc->private->last_wait_event_ptid = null_ptid;
+ proc->tdesc = lynx_tdesc;
+ proc->priv = xcalloc (1, sizeof (*proc->priv));
+ proc->priv->last_wait_event_ptid = null_ptid;
return proc;
}
{
int pgrp;
+ close_most_fds ();
+
/* Switch child to its own process group so that signals won't
directly affect gdbserver. */
pgrp = getpid();
return pid;
}
+/* Assuming we've just attached to a running inferior whose pid is PID,
+ add all threads running in that process. */
+
+static void
+lynx_add_threads_after_attach (int pid)
+{
+ /* Ugh! There appears to be no way to get the list of threads
+ in the program we just attached to. So get the list by calling
+ the "ps" command. This is only needed now, as we will then
+ keep the thread list up to date thanks to thread creation and
+ exit notifications. */
+ FILE *f;
+ char buf[256];
+ int thread_pid, thread_tid;
+
+ f = popen ("ps atx", "r");
+ if (f == NULL)
+ perror_with_name ("Cannot get thread list");
+
+ while (fgets (buf, sizeof (buf), f) != NULL)
+ if ((sscanf (buf, "%d %d", &thread_pid, &thread_tid) == 2
+ && thread_pid == pid))
+ {
+ ptid_t thread_ptid = lynx_ptid_build (pid, thread_tid);
+
+ if (!find_thread_ptid (thread_ptid))
+ {
+ lynx_debug ("New thread: (pid = %d, tid = %d)",
+ pid, thread_tid);
+ add_thread (thread_ptid, NULL);
+ }
+ }
+
+ pclose (f);
+}
+
/* Implement the attach target_ops method. */
static int
strerror (errno), errno);
lynx_add_process (pid, 1);
- add_thread (ptid, NULL);
+ lynx_add_threads_after_attach (pid);
return 0;
}
static void
lynx_resume (struct thread_resume *resume_info, size_t n)
{
- /* FIXME: Assume for now that n == 1. */
ptid_t ptid = resume_info[0].thread;
- const int request = (resume_info[0].kind == resume_step
- ? PTRACE_SINGLESTEP : PTRACE_CONT);
+ const int request
+ = (resume_info[0].kind == resume_step
+ ? (n == 1 ? PTRACE_SINGLESTEP_ONE : PTRACE_SINGLESTEP)
+ : PTRACE_CONT);
const int signal = resume_info[0].sig;
/* If given a minus_one_ptid, then try using the current_process'
unexpected signals (Eg SIG61) when we resume the inferior
using a different thread. */
if (ptid_equal (ptid, minus_one_ptid))
- ptid = current_process()->private->last_wait_event_ptid;
+ ptid = current_process()->priv->last_wait_event_ptid;
/* The ptid might still be minus_one_ptid; this can happen between
the moment we create the inferior or attach to a process, and
the moment we resume its execution for the first time. It is
- fine to use the current_inferior's ptid in those cases. */
+ fine to use the current_thread's ptid in those cases. */
if (ptid_equal (ptid, minus_one_ptid))
- ptid = thread_to_gdb_id (current_inferior);
+ ptid = thread_to_gdb_id (current_thread);
regcache_invalidate ();
ptid_t new_ptid;
if (ptid_equal (ptid, minus_one_ptid))
- pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior));
+ pid = lynx_ptid_get_pid (thread_to_gdb_id (current_thread));
else
pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid));
ret = lynx_waitpid (pid, &wstat);
new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
- find_process_pid (ret)->private->last_wait_event_ptid = new_ptid;
+ find_process_pid (ret)->priv->last_wait_event_ptid = new_ptid;
/* If this is a new thread, then add it now. The reason why we do
this here instead of when handling new-thread events is because
lynx_mourn (struct process_info *proc)
{
/* Free our private data. */
- free (proc->private);
- proc->private = NULL;
+ free (proc->priv);
+ proc->priv = NULL;
clear_inferiors ();
}
lynx_fetch_registers (struct regcache *regcache, int regno)
{
struct lynx_regset_info *regset = lynx_target_regsets;
- ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+ ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
lynx_debug ("lynx_fetch_registers (regno = %d)", regno);
lynx_store_registers (struct regcache *regcache, int regno)
{
struct lynx_regset_info *regset = lynx_target_regsets;
- ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+ ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
lynx_debug ("lynx_store_registers (regno = %d)", regno);
int buf;
const int xfer_size = sizeof (buf);
CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
- ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+ ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
while (addr < memaddr + len)
{
int buf;
const int xfer_size = sizeof (buf);
CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size;
- ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+ ptid_t inferior_ptid = thread_to_gdb_id (current_thread);
while (addr < memaddr + len)
{
if (addr + xfer_size > memaddr + len)
truncate = addr + xfer_size - memaddr - len;
if (skip > 0 || truncate > 0)
- /* We need to read the memory at this address in order to preserve
- the data that we are not overwriting. */
- lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
- if (errno)
- return errno;
+ {
+ /* We need to read the memory at this address in order to preserve
+ the data that we are not overwriting. */
+ lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
+ if (errno)
+ return errno;
+ }
memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
xfer_size - skip - truncate);
errno = 0;
static void
lynx_request_interrupt (void)
{
- ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+ ptid_t inferior_ptid = thread_to_gdb_id (get_first_thread ());
kill (lynx_ptid_get_pid (inferior_ptid), SIGINT);
}
static struct target_ops lynx_target_ops = {
lynx_create_inferior,
+ NULL, /* arch_setup */
lynx_attach,
lynx_kill,
lynx_detach,
NULL, /* look_up_symbols */
lynx_request_interrupt,
NULL, /* read_auxv */
+ NULL, /* supports_z_point_type */
NULL, /* insert_point */
NULL, /* remove_point */
+ NULL, /* stopped_by_sw_breakpoint */
+ NULL, /* supports_stopped_by_sw_breakpoint */
+ NULL, /* stopped_by_hw_breakpoint */
+ NULL, /* supports_stopped_by_hw_breakpoint */
+ /* Although lynx has hardware single step, still disable this
+ feature for lynx, because it is implemented in linux-low.c instead
+ of in generic code. */
+ NULL, /* supports_conditional_breakpoints */
NULL, /* stopped_by_watchpoint */
NULL, /* stopped_data_address */
NULL, /* read_offsets */
NULL, /* async */
NULL, /* start_non_stop */
NULL, /* supports_multi_process */
+ NULL, /* supports_fork_events */
+ NULL, /* supports_vfork_events */
+ NULL, /* handle_new_gdb_connection */
NULL, /* handle_monitor_command */
};