mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-22 19:09:31 +08:00
* linux-low.c (linux_resume): Take a struct thread_resume *
argument. (linux_wait): Update call. (resume_ptr): New static variable. (linux_continue_one_thread): Renamed from linux_continue_one_process. Use resume_ptr. (linux_resume): Use linux_continue_one_thread. * server.c (handle_v_cont, handle_v_requests): New functions. (myresume): New function. (main): Handle 'v' case. * target.h (struct thread_resume): New type. (struct target_ops): Change argument of "resume" to struct thread_resume *. (myresume): Delete macro.
This commit is contained in:
@ -1,3 +1,20 @@
|
|||||||
|
2003-10-13 Daniel Jacobowitz <drow@mvista.com>
|
||||||
|
|
||||||
|
* linux-low.c (linux_resume): Take a struct thread_resume *
|
||||||
|
argument.
|
||||||
|
(linux_wait): Update call.
|
||||||
|
(resume_ptr): New static variable.
|
||||||
|
(linux_continue_one_thread): Renamed from
|
||||||
|
linux_continue_one_process. Use resume_ptr.
|
||||||
|
(linux_resume): Use linux_continue_one_thread.
|
||||||
|
* server.c (handle_v_cont, handle_v_requests): New functions.
|
||||||
|
(myresume): New function.
|
||||||
|
(main): Handle 'v' case.
|
||||||
|
* target.h (struct thread_resume): New type.
|
||||||
|
(struct target_ops): Change argument of "resume" to struct
|
||||||
|
thread_resume *.
|
||||||
|
(myresume): Delete macro.
|
||||||
|
|
||||||
2003-08-08 H.J. Lu <hongjiu.lu@intel.com>
|
2003-08-08 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* Makefile.in (install-only): Create dest dir. Support DESTDIR.
|
* Makefile.in (install-only): Create dest dir. Support DESTDIR.
|
||||||
|
@ -52,7 +52,7 @@ int using_threads;
|
|||||||
|
|
||||||
static void linux_resume_one_process (struct inferior_list_entry *entry,
|
static void linux_resume_one_process (struct inferior_list_entry *entry,
|
||||||
int step, int signal);
|
int step, int signal);
|
||||||
static void linux_resume (int step, int signal);
|
static void linux_resume (struct thread_resume *resume_info);
|
||||||
static void stop_all_processes (void);
|
static void stop_all_processes (void);
|
||||||
static int linux_wait_for_event (struct thread_info *child);
|
static int linux_wait_for_event (struct thread_info *child);
|
||||||
|
|
||||||
@ -652,7 +652,12 @@ retry:
|
|||||||
|
|
||||||
/* No stepping, no signal - unless one is pending already, of course. */
|
/* No stepping, no signal - unless one is pending already, of course. */
|
||||||
if (child == NULL)
|
if (child == NULL)
|
||||||
linux_resume (0, 0);
|
{
|
||||||
|
struct thread_resume resume_info;
|
||||||
|
resume_info.thread = -1;
|
||||||
|
resume_info.step = resume_info.sig = resume_info.leave_stopped = 0;
|
||||||
|
linux_resume (&resume_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enable_async_io ();
|
enable_async_io ();
|
||||||
@ -868,33 +873,48 @@ linux_resume_one_process (struct inferior_list_entry *entry,
|
|||||||
perror_with_name ("ptrace");
|
perror_with_name ("ptrace");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called once per process other than the first
|
static struct thread_resume *resume_ptr;
|
||||||
one. The first process we are told the signal to continue
|
|
||||||
with, and whether to step or continue; for all others, any
|
/* This function is called once per thread. We look up the thread
|
||||||
existing signals will be marked in status_pending_p to be
|
in RESUME_PTR, which will tell us whether to resume, step, or leave
|
||||||
reported momentarily, and we preserve the stepping flag. */
|
the thread stopped; and what signal, if any, it should be sent.
|
||||||
|
For threads which we aren't explicitly told otherwise, we preserve
|
||||||
|
the stepping flag; this is used for stepping over gdbserver-placed
|
||||||
|
breakpoints. If the thread has a status pending, it may not actually
|
||||||
|
be resumed. */
|
||||||
static void
|
static void
|
||||||
linux_continue_one_process (struct inferior_list_entry *entry)
|
linux_continue_one_thread (struct inferior_list_entry *entry)
|
||||||
{
|
{
|
||||||
struct process_info *process;
|
struct process_info *process;
|
||||||
|
struct thread_info *thread;
|
||||||
|
int ndx, step;
|
||||||
|
|
||||||
process = (struct process_info *) entry;
|
thread = (struct thread_info *) entry;
|
||||||
linux_resume_one_process (entry, process->stepping, 0);
|
process = get_thread_process (thread);
|
||||||
|
|
||||||
|
ndx = 0;
|
||||||
|
while (resume_ptr[ndx].thread != -1 && resume_ptr[ndx].thread != entry->id)
|
||||||
|
ndx++;
|
||||||
|
|
||||||
|
if (resume_ptr[ndx].leave_stopped)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (resume_ptr[ndx].thread == -1)
|
||||||
|
step = process->stepping || resume_ptr[ndx].step;
|
||||||
|
else
|
||||||
|
step = resume_ptr[ndx].step;
|
||||||
|
|
||||||
|
linux_resume_one_process (&process->head, step, resume_ptr[ndx].sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
linux_resume (int step, int signal)
|
linux_resume (struct thread_resume *resume_info)
|
||||||
{
|
{
|
||||||
struct process_info *process;
|
/* Yes, this is quadratic. If it ever becomes a problem then it's
|
||||||
|
fairly easy to fix. Yes, the use of a global here is rather ugly. */
|
||||||
|
|
||||||
process = get_thread_process (current_inferior);
|
resume_ptr = resume_info;
|
||||||
|
for_each_inferior (&all_threads, linux_continue_one_thread);
|
||||||
/* If the current process has a status pending, this signal will
|
|
||||||
be enqueued and sent later. */
|
|
||||||
linux_resume_one_process (&process->head, step, signal);
|
|
||||||
|
|
||||||
if (cont_thread == 0 || cont_thread == -1)
|
|
||||||
for_each_inferior (&all_processes, linux_continue_one_process);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_USRREGS
|
#ifdef HAVE_LINUX_USRREGS
|
||||||
|
@ -125,6 +125,155 @@ handle_query (char *own_buf)
|
|||||||
own_buf[0] = 0;
|
own_buf[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse vCont packets. */
|
||||||
|
void
|
||||||
|
handle_v_cont (char *own_buf, char *status, unsigned char *signal)
|
||||||
|
{
|
||||||
|
char *p, *q;
|
||||||
|
int n = 0, i = 0;
|
||||||
|
struct thread_resume *resume_info, default_action;
|
||||||
|
|
||||||
|
/* Count the number of semicolons in the packet. There should be one
|
||||||
|
for every action. */
|
||||||
|
p = &own_buf[5];
|
||||||
|
while (p)
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
p++;
|
||||||
|
p = strchr (p, ';');
|
||||||
|
}
|
||||||
|
/* Allocate room for one extra action, for the default remain-stopped
|
||||||
|
behavior; if no default action is in the list, we'll need the extra
|
||||||
|
slot. */
|
||||||
|
resume_info = malloc ((n + 1) * sizeof (resume_info[0]));
|
||||||
|
|
||||||
|
default_action.thread = -1;
|
||||||
|
default_action.leave_stopped = 1;
|
||||||
|
default_action.step = 0;
|
||||||
|
default_action.sig = 0;
|
||||||
|
|
||||||
|
p = &own_buf[5];
|
||||||
|
i = 0;
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
|
||||||
|
resume_info[i].leave_stopped = 0;
|
||||||
|
|
||||||
|
if (p[0] == 's' || p[0] == 'S')
|
||||||
|
resume_info[i].step = 1;
|
||||||
|
else if (p[0] == 'c' || p[0] == 'C')
|
||||||
|
resume_info[i].step = 0;
|
||||||
|
else
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (p[0] == 'S' || p[0] == 'C')
|
||||||
|
{
|
||||||
|
int sig;
|
||||||
|
sig = strtol (p + 1, &q, 16);
|
||||||
|
if (p == q)
|
||||||
|
goto err;
|
||||||
|
p = q;
|
||||||
|
|
||||||
|
if (!target_signal_to_host_p (sig))
|
||||||
|
goto err;
|
||||||
|
resume_info[i].sig = target_signal_to_host (sig);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resume_info[i].sig = 0;
|
||||||
|
p = p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p[0] == 0)
|
||||||
|
{
|
||||||
|
resume_info[i].thread = -1;
|
||||||
|
default_action = resume_info[i];
|
||||||
|
|
||||||
|
/* Note: we don't increment i here, we'll overwrite this entry
|
||||||
|
the next time through. */
|
||||||
|
}
|
||||||
|
else if (p[0] == ':')
|
||||||
|
{
|
||||||
|
resume_info[i].thread = strtol (p + 1, &q, 16);
|
||||||
|
if (p == q)
|
||||||
|
goto err;
|
||||||
|
p = q;
|
||||||
|
if (p[0] != ';' && p[0] != 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resume_info[i] = default_action;
|
||||||
|
|
||||||
|
/* Still used in occasional places in the backend. */
|
||||||
|
if (n == 1 && resume_info[0].thread != -1)
|
||||||
|
cont_thread = resume_info[0].thread;
|
||||||
|
else
|
||||||
|
cont_thread = -1;
|
||||||
|
|
||||||
|
(*the_target->resume) (resume_info);
|
||||||
|
|
||||||
|
free (resume_info);
|
||||||
|
|
||||||
|
*signal = mywait (status, 1);
|
||||||
|
prepare_resume_reply (own_buf, *status, *signal);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
/* No other way to report an error... */
|
||||||
|
strcpy (own_buf, "");
|
||||||
|
free (resume_info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle all of the extended 'v' packets. */
|
||||||
|
void
|
||||||
|
handle_v_requests (char *own_buf, char *status, unsigned char *signal)
|
||||||
|
{
|
||||||
|
if (strncmp (own_buf, "vCont;", 6) == 0)
|
||||||
|
{
|
||||||
|
handle_v_cont (own_buf, status, signal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp (own_buf, "vCont?", 6) == 0)
|
||||||
|
{
|
||||||
|
strcpy (own_buf, "vCont;c;C;s;S");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise we didn't know what packet it was. Say we didn't
|
||||||
|
understand it. */
|
||||||
|
own_buf[0] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
myresume (int step, int sig)
|
||||||
|
{
|
||||||
|
struct thread_resume resume_info[2];
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if (step || sig || cont_thread > 0)
|
||||||
|
{
|
||||||
|
resume_info[0].thread
|
||||||
|
= ((struct inferior_list_entry *) current_inferior)->id;
|
||||||
|
resume_info[0].step = step;
|
||||||
|
resume_info[0].sig = sig;
|
||||||
|
resume_info[0].leave_stopped = 0;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
resume_info[n].thread = -1;
|
||||||
|
resume_info[n].step = 0;
|
||||||
|
resume_info[n].sig = 0;
|
||||||
|
resume_info[n].leave_stopped = (cont_thread > 0);
|
||||||
|
|
||||||
|
(*the_target->resume) (resume_info);
|
||||||
|
}
|
||||||
|
|
||||||
static int attached;
|
static int attached;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -383,6 +532,10 @@ main (int argc, char *argv[])
|
|||||||
own_buf[0] = '\0';
|
own_buf[0] = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'v':
|
||||||
|
/* Extended (long) request. */
|
||||||
|
handle_v_requests (own_buf, &status, &signal);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* It is a request we don't understand. Respond with an
|
/* It is a request we don't understand. Respond with an
|
||||||
empty packet so that gdb knows that we don't support this
|
empty packet so that gdb knows that we don't support this
|
||||||
|
@ -24,6 +24,25 @@
|
|||||||
#ifndef TARGET_H
|
#ifndef TARGET_H
|
||||||
#define TARGET_H
|
#define TARGET_H
|
||||||
|
|
||||||
|
/* This structure describes how to resume a particular thread (or
|
||||||
|
all threads) based on the client's request. If thread is -1, then
|
||||||
|
this entry applies to all threads. These are generally passed around
|
||||||
|
as an array, and terminated by a thread == -1 entry. */
|
||||||
|
|
||||||
|
struct thread_resume
|
||||||
|
{
|
||||||
|
int thread;
|
||||||
|
|
||||||
|
/* If non-zero, leave this thread stopped. */
|
||||||
|
int leave_stopped;
|
||||||
|
|
||||||
|
/* If non-zero, we want to single-step. */
|
||||||
|
int step;
|
||||||
|
|
||||||
|
/* If non-zero, send this signal when we resume. */
|
||||||
|
int sig;
|
||||||
|
};
|
||||||
|
|
||||||
struct target_ops
|
struct target_ops
|
||||||
{
|
{
|
||||||
/* Start a new process.
|
/* Start a new process.
|
||||||
@ -56,14 +75,9 @@ struct target_ops
|
|||||||
|
|
||||||
int (*thread_alive) (int pid);
|
int (*thread_alive) (int pid);
|
||||||
|
|
||||||
/* Resume the inferior process.
|
/* Resume the inferior process. */
|
||||||
|
|
||||||
If STEP is non-zero, we want to single-step.
|
void (*resume) (struct thread_resume *resume_info);
|
||||||
|
|
||||||
If SIGNAL is nonzero, send the process that signal as we resume it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void (*resume) (int step, int signo);
|
|
||||||
|
|
||||||
/* Wait for the inferior process to change state.
|
/* Wait for the inferior process to change state.
|
||||||
|
|
||||||
@ -132,9 +146,6 @@ void set_target_ops (struct target_ops *);
|
|||||||
#define mythread_alive(pid) \
|
#define mythread_alive(pid) \
|
||||||
(*the_target->thread_alive) (pid)
|
(*the_target->thread_alive) (pid)
|
||||||
|
|
||||||
#define myresume(step,signo) \
|
|
||||||
(*the_target->resume) (step, signo)
|
|
||||||
|
|
||||||
#define fetch_inferior_registers(regno) \
|
#define fetch_inferior_registers(regno) \
|
||||||
(*the_target->fetch_registers) (regno)
|
(*the_target->fetch_registers) (regno)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user