| Index: gdb/gdbserver/lynx-low.c
|
| diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
|
| index 2c7ab6e3dfa193fe433bf2eece609d3c419fcbd1..3c061b8f0779e3e4966d1c45f71ea3a8162c0799 100644
|
| --- a/gdb/gdbserver/lynx-low.c
|
| +++ b/gdb/gdbserver/lynx-low.c
|
| @@ -1,4 +1,4 @@
|
| -/* Copyright (C) 2009-2012 Free Software Foundation, Inc.
|
| +/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -25,11 +25,23 @@
|
| #include <unistd.h>
|
| #include <sys/ioctl.h>
|
| #include <sys/types.h>
|
| -#include <sys/wait.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
|
| +{
|
| + /* The PTID obtained from the last wait performed on this process.
|
| + Initialized to null_ptid until the first wait is performed. */
|
| + ptid_t last_wait_event_ptid;
|
| +};
|
| +
|
| /* Print a debug trace on standard output if debug_threads is set. */
|
|
|
| static void
|
| @@ -96,169 +108,79 @@ lynx_ptrace_pid_from_ptid (ptid_t ptid)
|
| static char *
|
| ptrace_request_to_str (int request)
|
| {
|
| +#define CASE(X) case X: return #X
|
| switch (request)
|
| {
|
| - case PTRACE_TRACEME:
|
| - return "PTRACE_TRACEME";
|
| - break;
|
| - case PTRACE_PEEKTEXT:
|
| - return "PTRACE_PEEKTEXT";
|
| - break;
|
| - case PTRACE_PEEKDATA:
|
| - return "PTRACE_PEEKDATA";
|
| - break;
|
| - case PTRACE_PEEKUSER:
|
| - return "PTRACE_PEEKUSER";
|
| - break;
|
| - case PTRACE_POKETEXT:
|
| - return "PTRACE_POKETEXT";
|
| - break;
|
| - case PTRACE_POKEDATA:
|
| - return "PTRACE_POKEDATA";
|
| - break;
|
| - case PTRACE_POKEUSER:
|
| - return "PTRACE_POKEUSER";
|
| - break;
|
| - case PTRACE_CONT:
|
| - return "PTRACE_CONT";
|
| - break;
|
| - case PTRACE_KILL:
|
| - return "PTRACE_KILL";
|
| - break;
|
| - case PTRACE_SINGLESTEP:
|
| - return "PTRACE_SINGLESTEP";
|
| - break;
|
| - case PTRACE_ATTACH:
|
| - return "PTRACE_ATTACH";
|
| - break;
|
| - case PTRACE_DETACH:
|
| - return "PTRACE_DETACH";
|
| - break;
|
| - case PTRACE_GETREGS:
|
| - return "PTRACE_GETREGS";
|
| - break;
|
| - case PTRACE_SETREGS:
|
| - return "PTRACE_SETREGS";
|
| - break;
|
| - case PTRACE_GETFPREGS:
|
| - return "PTRACE_GETFPREGS";
|
| - break;
|
| - case PTRACE_SETFPREGS:
|
| - return "PTRACE_SETFPREGS";
|
| - break;
|
| - case PTRACE_READDATA:
|
| - return "PTRACE_READDATA";
|
| - break;
|
| - case PTRACE_WRITEDATA:
|
| - return "PTRACE_WRITEDATA";
|
| - break;
|
| - case PTRACE_READTEXT:
|
| - return "PTRACE_READTEXT";
|
| - break;
|
| - case PTRACE_WRITETEXT:
|
| - return "PTRACE_WRITETEXT";
|
| - break;
|
| - case PTRACE_GETFPAREGS:
|
| - return "PTRACE_GETFPAREGS";
|
| - break;
|
| - case PTRACE_SETFPAREGS:
|
| - return "PTRACE_SETFPAREGS";
|
| - break;
|
| - case PTRACE_GETWINDOW:
|
| - return "PTRACE_GETWINDOW";
|
| - break;
|
| - case PTRACE_SETWINDOW:
|
| - return "PTRACE_SETWINDOW";
|
| - break;
|
| - case PTRACE_SYSCALL:
|
| - return "PTRACE_SYSCALL";
|
| - break;
|
| - case PTRACE_DUMPCORE:
|
| - return "PTRACE_DUMPCORE";
|
| - break;
|
| - case PTRACE_SETWRBKPT:
|
| - return "PTRACE_SETWRBKPT";
|
| - break;
|
| - case PTRACE_SETACBKPT:
|
| - return "PTRACE_SETACBKPT";
|
| - break;
|
| - case PTRACE_CLRBKPT:
|
| - return "PTRACE_CLRBKPT";
|
| - break;
|
| - case PTRACE_GET_UCODE:
|
| - return "PTRACE_GET_UCODE";
|
| - break;
|
| + CASE(PTRACE_TRACEME);
|
| + CASE(PTRACE_PEEKTEXT);
|
| + CASE(PTRACE_PEEKDATA);
|
| + CASE(PTRACE_PEEKUSER);
|
| + CASE(PTRACE_POKETEXT);
|
| + CASE(PTRACE_POKEDATA);
|
| + CASE(PTRACE_POKEUSER);
|
| + CASE(PTRACE_CONT);
|
| + CASE(PTRACE_KILL);
|
| + CASE(PTRACE_SINGLESTEP);
|
| + CASE(PTRACE_ATTACH);
|
| + CASE(PTRACE_DETACH);
|
| + CASE(PTRACE_GETREGS);
|
| + CASE(PTRACE_SETREGS);
|
| + CASE(PTRACE_GETFPREGS);
|
| + CASE(PTRACE_SETFPREGS);
|
| + CASE(PTRACE_READDATA);
|
| + CASE(PTRACE_WRITEDATA);
|
| + CASE(PTRACE_READTEXT);
|
| + CASE(PTRACE_WRITETEXT);
|
| + CASE(PTRACE_GETFPAREGS);
|
| + CASE(PTRACE_SETFPAREGS);
|
| + CASE(PTRACE_GETWINDOW);
|
| + CASE(PTRACE_SETWINDOW);
|
| + CASE(PTRACE_SYSCALL);
|
| + CASE(PTRACE_DUMPCORE);
|
| + CASE(PTRACE_SETWRBKPT);
|
| + CASE(PTRACE_SETACBKPT);
|
| + CASE(PTRACE_CLRBKPT);
|
| + CASE(PTRACE_GET_UCODE);
|
| #ifdef PT_READ_GPR
|
| - case PT_READ_GPR:
|
| - return "PT_READ_GPR";
|
| - break;
|
| + CASE(PT_READ_GPR);
|
| #endif
|
| #ifdef PT_WRITE_GPR
|
| - case PT_WRITE_GPR:
|
| - return "PT_WRITE_GPR";
|
| - break;
|
| + CASE(PT_WRITE_GPR);
|
| #endif
|
| #ifdef PT_READ_FPR
|
| - case PT_READ_FPR:
|
| - return "PT_READ_FPR";
|
| - break;
|
| + CASE(PT_READ_FPR);
|
| #endif
|
| #ifdef PT_WRITE_FPR
|
| - case PT_WRITE_FPR:
|
| - return "PT_WRITE_FPR";
|
| - break;
|
| + CASE(PT_WRITE_FPR);
|
| #endif
|
| #ifdef PT_READ_VPR
|
| - case PT_READ_VPR:
|
| - return "PT_READ_VPR";
|
| - break;
|
| + CASE(PT_READ_VPR);
|
| #endif
|
| #ifdef PT_WRITE_VPR
|
| - case PT_WRITE_VPR:
|
| - return "PT_WRITE_VPR";
|
| - break;
|
| + CASE(PT_WRITE_VPR);
|
| #endif
|
| #ifdef PTRACE_PEEKUSP
|
| - case PTRACE_PEEKUSP:
|
| - return "PTRACE_PEEKUSP";
|
| - break;
|
| + CASE(PTRACE_PEEKUSP);
|
| #endif
|
| #ifdef PTRACE_POKEUSP
|
| - case PTRACE_POKEUSP:
|
| - return "PTRACE_POKEUSP";
|
| - break;
|
| + CASE(PTRACE_POKEUSP);
|
| +#endif
|
| + CASE(PTRACE_PEEKTHREAD);
|
| + CASE(PTRACE_THREADUSER);
|
| + CASE(PTRACE_FPREAD);
|
| + CASE(PTRACE_FPWRITE);
|
| + CASE(PTRACE_SETSIG);
|
| + CASE(PTRACE_CONT_ONE);
|
| + CASE(PTRACE_KILL_ONE);
|
| + CASE(PTRACE_SINGLESTEP_ONE);
|
| + CASE(PTRACE_GETLOADINFO);
|
| + CASE(PTRACE_GETTRACESIG);
|
| +#ifdef PTRACE_GETTHREADLIST
|
| + CASE(PTRACE_GETTHREADLIST);
|
| #endif
|
| - case PTRACE_PEEKTHREAD:
|
| - return "PTRACE_PEEKTHREAD";
|
| - break;
|
| - case PTRACE_THREADUSER:
|
| - return "PTRACE_THREADUSER";
|
| - break;
|
| - case PTRACE_FPREAD:
|
| - return "PTRACE_FPREAD";
|
| - break;
|
| - case PTRACE_FPWRITE:
|
| - return "PTRACE_FPWRITE";
|
| - break;
|
| - case PTRACE_SETSIG:
|
| - return "PTRACE_SETSIG";
|
| - break;
|
| - case PTRACE_CONT_ONE:
|
| - return "PTRACE_CONT_ONE";
|
| - break;
|
| - case PTRACE_KILL_ONE:
|
| - return "PTRACE_KILL_ONE";
|
| - break;
|
| - case PTRACE_SINGLESTEP_ONE:
|
| - return "PTRACE_SINGLESTEP_ONE";
|
| - break;
|
| - case PTRACE_GETLOADINFO:
|
| - return "PTRACE_GETLOADINFO";
|
| - break;
|
| - case PTRACE_GETTHREADLIST:
|
| - return "PTRACE_GETTHREADLIST";
|
| - break;
|
| }
|
| +#undef CASE
|
| +
|
| return "<unknown-request>";
|
| }
|
|
|
| @@ -286,12 +208,27 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
|
| return result;
|
| }
|
|
|
| +/* Call add_process with the given parameters, and initializes
|
| + the process' private data. */
|
| +
|
| +static struct process_info *
|
| +lynx_add_process (int pid, int attached)
|
| +{
|
| + struct process_info *proc;
|
| +
|
| + proc = add_process (pid, attached);
|
| + proc->tdesc = lynx_tdesc;
|
| + proc->private = xcalloc (1, sizeof (*proc->private));
|
| + proc->private->last_wait_event_ptid = null_ptid;
|
| +
|
| + return proc;
|
| +}
|
| +
|
| /* Implement the create_inferior method of the target_ops vector. */
|
|
|
| static int
|
| lynx_create_inferior (char *program, char **allargs)
|
| {
|
| - struct process_info *new_process;
|
| int pid;
|
|
|
| lynx_debug ("lynx_create_inferior ()");
|
| @@ -304,6 +241,8 @@ lynx_create_inferior (char *program, char **allargs)
|
| {
|
| int pgrp;
|
|
|
| + close_most_fds ();
|
| +
|
| /* Switch child to its own process group so that signals won't
|
| directly affect gdbserver. */
|
| pgrp = getpid();
|
| @@ -316,27 +255,62 @@ lynx_create_inferior (char *program, char **allargs)
|
| _exit (0177);
|
| }
|
|
|
| - new_process = add_process (pid, 0);
|
| + lynx_add_process (pid, 0);
|
| /* Do not add the process thread just yet, as we do not know its tid.
|
| We will add it later, during the wait for the STOP event corresponding
|
| to the lynx_ptrace (PTRACE_TRACEME) call above. */
|
| 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
|
| lynx_attach (unsigned long pid)
|
| {
|
| - struct process_info *new_process;
|
| ptid_t ptid = lynx_ptid_build (pid, 0);
|
|
|
| if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0)
|
| error ("Cannot attach to process %lu: %s (%d)\n", pid,
|
| strerror (errno), errno);
|
|
|
| - new_process = add_process (pid, 1);
|
| - add_thread (ptid, NULL);
|
| + lynx_add_process (pid, 1);
|
| + lynx_add_threads_after_attach (pid);
|
|
|
| return 0;
|
| }
|
| @@ -346,15 +320,34 @@ lynx_attach (unsigned long pid)
|
| static void
|
| lynx_resume (struct thread_resume *resume_info, size_t n)
|
| {
|
| - ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
|
| /* 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 signal = resume_info[0].sig;
|
| - int ret;
|
| +
|
| + /* If given a minus_one_ptid, then try using the current_process'
|
| + private->last_wait_event_ptid. On most LynxOS versions,
|
| + using any of the process' thread works well enough, but
|
| + LynxOS 178 is a little more sensitive, and triggers some
|
| + 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;
|
| +
|
| + /* 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. */
|
| + if (ptid_equal (ptid, minus_one_ptid))
|
| + ptid = thread_to_gdb_id (current_inferior);
|
|
|
| regcache_invalidate ();
|
| - ret = lynx_ptrace (request, inferior_ptid, 1, signal, 0);
|
| +
|
| + errno = 0;
|
| + lynx_ptrace (request, ptid, 1, signal, 0);
|
| + if (errno)
|
| + perror_with_name ("ptrace");
|
| }
|
|
|
| /* Resume the execution of the given PTID. */
|
| @@ -371,16 +364,6 @@ lynx_continue (ptid_t ptid)
|
| lynx_resume (&resume_info, 1);
|
| }
|
|
|
| -/* Remove all inferiors and associated threads. */
|
| -
|
| -static void
|
| -lynx_clear_inferiors (void)
|
| -{
|
| - /* We do not use private data, so nothing much to do except calling
|
| - clear_inferiors. */
|
| - clear_inferiors ();
|
| -}
|
| -
|
| /* A wrapper around waitpid that handles the various idiosyncrasies
|
| of LynxOS' waitpid. */
|
|
|
| @@ -438,6 +421,7 @@ retry:
|
|
|
| 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;
|
|
|
| /* 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
|
| @@ -445,7 +429,11 @@ retry:
|
| for non-threaded applications where the new-thread events are not
|
| generated. */
|
| if (!find_thread_ptid (new_ptid))
|
| - add_thread (new_ptid, NULL);
|
| + {
|
| + lynx_debug ("New thread: (pid = %d, tid = %d)",
|
| + lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid));
|
| + add_thread (new_ptid, NULL);
|
| + }
|
|
|
| if (WIFSTOPPED (wstat))
|
| {
|
| @@ -491,12 +479,12 @@ retry:
|
| case SIGNEWTHREAD:
|
| /* We just added the new thread above. No need to do anything
|
| further. Just resume the execution again. */
|
| - lynx_continue (ptid);
|
| + lynx_continue (new_ptid);
|
| goto retry;
|
|
|
| case SIGTHREADEXIT:
|
| remove_thread (find_thread_ptid (new_ptid));
|
| - lynx_continue (ptid);
|
| + lynx_continue (new_ptid);
|
| goto retry;
|
| }
|
| }
|
| @@ -562,7 +550,11 @@ lynx_detach (int pid)
|
| static void
|
| lynx_mourn (struct process_info *proc)
|
| {
|
| - lynx_clear_inferiors ();
|
| + /* Free our private data. */
|
| + free (proc->private);
|
| + proc->private = NULL;
|
| +
|
| + clear_inferiors ();
|
| }
|
|
|
| /* Implement the join target_ops method. */
|
|
|