* 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:
Daniel Jacobowitz
2003-10-13 16:17:21 +00:00
parent 86d30acc85
commit 64386c31df
4 changed files with 231 additions and 30 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)