Teach linux gdbserver to step-over-breakpoints.
* linux-low.c (can_hardware_single_step): New. (supports_breakpoints): New. (handle_extended_wait): If stopping threads, read the stop pc of the new cloned LWP. (get_pc): New. (get_stop_pc): Add `lwp' parameter. Handle it. Bail out if the low target doesn't support retrieving the PC. (add_lwp): Set last_resume_kind to resume_continue. (linux_attach_lwp_1): Adjust comments. Always set stop_expected. (linux_attach): Don't clear stop_expected. Set the lwp's last_resume_kind to resume_stop. (linux_detach_one_lwp): Don't check for removed breakpoints. (check_removed_breakpoint): Delete. (status_pending_p): Rename to ... (status_pending_p_callback): ... this. Don't check for removed breakpoints. Don't consider threads that are stopped from GDB's perspective. (linux_wait_for_lwp): Always read the stop_pc here. (cancel_breakpoint): New. (step_over_bkpt): New global. (linux_wait_for_event_1): Implement stepping over breakpoints. (gdb_wants_lwp_stopped): New. (gdb_wants_all_stopped): New. (linux_wait_1): Tag threads as gdb-wants-stopped. Cancel finished single-step traps here. Store the thread's last reported target wait status. (send_sigstop): Don't clear stop_expected. Always set it, instead. (mark_lwp_dead): Remove reference to pending_is_breakpoint. (cancel_finished_single_step): New. (cancel_finished_single_steps): New. (wait_for_sigstop): Don't cancel finished single-step traps here. (linux_resume_one_lwp): Don't check for removed breakpoints. Don't set `step' on non-hardware step archs. (linux_set_resume_request): Ignore resume_stop requests if already stopping or stopped. Set the lwp's last_resume_kind. (resume_status_pending_p): Don't check for removed breakpoints. (need_step_over_p): New. (start_step_over): New. (finish_step_over): New. (linux_resume_one_thread): Always queue a sigstop for resume_stop requests. Clear the thread's last reported target waitstatus. Don't use the `suspended' flag. Don't consider pending breakpoints. (linux_resume): Start a step-over if necessary. (proceed_one_lwp): New. (proceed_all_lwps): New. (unstop_all_lwps): New. * linux-low.h (struct lwp_info): Rewrite comment for the `suspended' flag. Add the `stop_pc' field. Delete the `pending_stop_pc' field. Tweak the `stepping' flag's comment. Add `'last_resume_kind' and `need_step_over' fields. * inferiors.c (struct thread_info): Delete, moved elsewhere. * mem-break.c (struct breakpoint): Delete `reinserting' flag. Delete `breakpoint_to_reinsert' field. New flag `inserted'. (set_raw_breakpoint_at): New. (set_breakpoint_at): Rewrite to use it. (reinsert_breakpoint_handler): Delete. (set_reinsert_breakpoint): New. (reinsert_breakpoint_by_bp): Delete. (delete_reinsert_breakpoints): New. (uninsert_breakpoint): Rewrite. (uninsert_breakpoints_at): New. (reinsert_breakpoint): Rewrite. (reinsert_breakpoints_at): New. (check_breakpoints): Rewrite. (breakpoint_here): New. (breakpoint_inserted_here): New. (check_mem_read): Adjust. * mem-break.h (breakpoints_supported, breakpoint_here) (breakpoint_inserted_here, set_reinsert_breakpoint): Declare. (reinsert_breakpoint_by_bp): Delete declaration. (delete_reinsert_breakpoints): Declare. (reinsert_breakpoint): Delete declaration. (reinsert_breakpoints_at): Declare. (uninsert_breakpoint): Delete declaration. (uninsert_breakpoints_at): Declare. (check_breakpoints): Adjust prototype. * server.h: Adjust include order. (struct thread_info): Declare here. Add a `last_status' field.
This commit is contained in:
parent
8541339168
commit
d50171e439
7 changed files with 1290 additions and 443 deletions
|
@ -1,3 +1,87 @@
|
||||||
|
2010-03-24 Pedro Alves <pedro@codesourcery.com>
|
||||||
|
|
||||||
|
Teach linux gdbserver to step-over-breakpoints.
|
||||||
|
|
||||||
|
* linux-low.c (can_hardware_single_step): New.
|
||||||
|
(supports_breakpoints): New.
|
||||||
|
(handle_extended_wait): If stopping threads, read the stop pc of
|
||||||
|
the new cloned LWP.
|
||||||
|
(get_pc): New.
|
||||||
|
(get_stop_pc): Add `lwp' parameter. Handle it. Bail out if the
|
||||||
|
low target doesn't support retrieving the PC.
|
||||||
|
(add_lwp): Set last_resume_kind to resume_continue.
|
||||||
|
(linux_attach_lwp_1): Adjust comments. Always set stop_expected.
|
||||||
|
(linux_attach): Don't clear stop_expected. Set the lwp's
|
||||||
|
last_resume_kind to resume_stop.
|
||||||
|
(linux_detach_one_lwp): Don't check for removed breakpoints.
|
||||||
|
(check_removed_breakpoint): Delete.
|
||||||
|
(status_pending_p): Rename to ...
|
||||||
|
(status_pending_p_callback): ... this. Don't check for removed
|
||||||
|
breakpoints. Don't consider threads that are stopped from GDB's
|
||||||
|
perspective.
|
||||||
|
(linux_wait_for_lwp): Always read the stop_pc here.
|
||||||
|
(cancel_breakpoint): New.
|
||||||
|
(step_over_bkpt): New global.
|
||||||
|
(linux_wait_for_event_1): Implement stepping over breakpoints.
|
||||||
|
(gdb_wants_lwp_stopped): New.
|
||||||
|
(gdb_wants_all_stopped): New.
|
||||||
|
(linux_wait_1): Tag threads as gdb-wants-stopped. Cancel finished
|
||||||
|
single-step traps here. Store the thread's last reported target
|
||||||
|
wait status.
|
||||||
|
(send_sigstop): Don't clear stop_expected. Always set it,
|
||||||
|
instead.
|
||||||
|
(mark_lwp_dead): Remove reference to pending_is_breakpoint.
|
||||||
|
(cancel_finished_single_step): New.
|
||||||
|
(cancel_finished_single_steps): New.
|
||||||
|
(wait_for_sigstop): Don't cancel finished single-step traps here.
|
||||||
|
(linux_resume_one_lwp): Don't check for removed breakpoints.
|
||||||
|
Don't set `step' on non-hardware step archs.
|
||||||
|
(linux_set_resume_request): Ignore resume_stop requests if already
|
||||||
|
stopping or stopped. Set the lwp's last_resume_kind.
|
||||||
|
(resume_status_pending_p): Don't check for removed breakpoints.
|
||||||
|
(need_step_over_p): New.
|
||||||
|
(start_step_over): New.
|
||||||
|
(finish_step_over): New.
|
||||||
|
(linux_resume_one_thread): Always queue a sigstop for resume_stop
|
||||||
|
requests. Clear the thread's last reported target waitstatus.
|
||||||
|
Don't use the `suspended' flag. Don't consider pending breakpoints.
|
||||||
|
(linux_resume): Start a step-over if necessary.
|
||||||
|
(proceed_one_lwp): New.
|
||||||
|
(proceed_all_lwps): New.
|
||||||
|
(unstop_all_lwps): New.
|
||||||
|
* linux-low.h (struct lwp_info): Rewrite comment for the
|
||||||
|
`suspended' flag. Add the `stop_pc' field. Delete the
|
||||||
|
`pending_stop_pc' field. Tweak the `stepping' flag's comment.
|
||||||
|
Add `'last_resume_kind' and `need_step_over' fields.
|
||||||
|
* inferiors.c (struct thread_info): Delete, moved elsewhere.
|
||||||
|
* mem-break.c (struct breakpoint): Delete `reinserting' flag.
|
||||||
|
Delete `breakpoint_to_reinsert' field. New flag `inserted'.
|
||||||
|
(set_raw_breakpoint_at): New.
|
||||||
|
(set_breakpoint_at): Rewrite to use it.
|
||||||
|
(reinsert_breakpoint_handler): Delete.
|
||||||
|
(set_reinsert_breakpoint): New.
|
||||||
|
(reinsert_breakpoint_by_bp): Delete.
|
||||||
|
(delete_reinsert_breakpoints): New.
|
||||||
|
(uninsert_breakpoint): Rewrite.
|
||||||
|
(uninsert_breakpoints_at): New.
|
||||||
|
(reinsert_breakpoint): Rewrite.
|
||||||
|
(reinsert_breakpoints_at): New.
|
||||||
|
(check_breakpoints): Rewrite.
|
||||||
|
(breakpoint_here): New.
|
||||||
|
(breakpoint_inserted_here): New.
|
||||||
|
(check_mem_read): Adjust.
|
||||||
|
* mem-break.h (breakpoints_supported, breakpoint_here)
|
||||||
|
(breakpoint_inserted_here, set_reinsert_breakpoint): Declare.
|
||||||
|
(reinsert_breakpoint_by_bp): Delete declaration.
|
||||||
|
(delete_reinsert_breakpoints): Declare.
|
||||||
|
(reinsert_breakpoint): Delete declaration.
|
||||||
|
(reinsert_breakpoints_at): Declare.
|
||||||
|
(uninsert_breakpoint): Delete declaration.
|
||||||
|
(uninsert_breakpoints_at): Declare.
|
||||||
|
(check_breakpoints): Adjust prototype.
|
||||||
|
* server.h: Adjust include order.
|
||||||
|
(struct thread_info): Declare here. Add a `last_status' field.
|
||||||
|
|
||||||
2010-03-23 Michael Snyder <msnyder@vmware.com>
|
2010-03-23 Michael Snyder <msnyder@vmware.com>
|
||||||
|
|
||||||
* server.c (crc32): New function.
|
* server.c (crc32): New function.
|
||||||
|
|
|
@ -23,14 +23,6 @@
|
||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
struct thread_info
|
|
||||||
{
|
|
||||||
struct inferior_list_entry entry;
|
|
||||||
void *target_data;
|
|
||||||
void *regcache_data;
|
|
||||||
unsigned int gdb_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct inferior_list all_processes;
|
struct inferior_list all_processes;
|
||||||
struct inferior_list all_threads;
|
struct inferior_list all_threads;
|
||||||
struct inferior_list all_dlls;
|
struct inferior_list all_dlls;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -137,7 +137,8 @@ struct lwp_info
|
||||||
yet. */
|
yet. */
|
||||||
int stop_expected;
|
int stop_expected;
|
||||||
|
|
||||||
/* True if this thread was suspended (with vCont;t). */
|
/* When this is true, we shall not try to resume this thread, even
|
||||||
|
if last_resume_kind isn't resume_stop. */
|
||||||
int suspended;
|
int suspended;
|
||||||
|
|
||||||
/* If this flag is set, the lwp is known to be stopped right now (stop
|
/* If this flag is set, the lwp is known to be stopped right now (stop
|
||||||
|
@ -152,15 +153,15 @@ struct lwp_info
|
||||||
/* When stopped is set, the last wait status recorded for this lwp. */
|
/* When stopped is set, the last wait status recorded for this lwp. */
|
||||||
int last_status;
|
int last_status;
|
||||||
|
|
||||||
|
/* When stopped is set, this is where the lwp stopped, with
|
||||||
|
decr_pc_after_break already accounted for. */
|
||||||
|
CORE_ADDR stop_pc;
|
||||||
|
|
||||||
/* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
|
/* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
|
||||||
been reported. */
|
been reported. */
|
||||||
int status_pending_p;
|
int status_pending_p;
|
||||||
int status_pending;
|
int status_pending;
|
||||||
|
|
||||||
/* If this flag is set, the pending status is a (GDB-placed) breakpoint. */
|
|
||||||
int pending_is_breakpoint;
|
|
||||||
CORE_ADDR pending_stop_pc;
|
|
||||||
|
|
||||||
/* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data
|
/* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data
|
||||||
watchpoint trap. */
|
watchpoint trap. */
|
||||||
int stopped_by_watchpoint;
|
int stopped_by_watchpoint;
|
||||||
|
@ -175,8 +176,8 @@ struct lwp_info
|
||||||
stop (SIGTRAP stops only). */
|
stop (SIGTRAP stops only). */
|
||||||
CORE_ADDR bp_reinsert;
|
CORE_ADDR bp_reinsert;
|
||||||
|
|
||||||
/* If this flag is set, the last continue operation on this process
|
/* If this flag is set, the last continue operation at the ptrace
|
||||||
was a single-step. */
|
level on this process was a single-step. */
|
||||||
int stepping;
|
int stepping;
|
||||||
|
|
||||||
/* If this flag is set, we need to set the event request flags the
|
/* If this flag is set, we need to set the event request flags the
|
||||||
|
@ -189,9 +190,15 @@ struct lwp_info
|
||||||
|
|
||||||
/* A link used when resuming. It is initialized from the resume request,
|
/* A link used when resuming. It is initialized from the resume request,
|
||||||
and then processed and cleared in linux_resume_one_lwp. */
|
and then processed and cleared in linux_resume_one_lwp. */
|
||||||
|
|
||||||
struct thread_resume *resume;
|
struct thread_resume *resume;
|
||||||
|
|
||||||
|
/* The last resume GDB requested on this thread. */
|
||||||
|
enum resume_kind last_resume_kind;
|
||||||
|
|
||||||
|
/* True if the LWP was seen stop at an internal breakpoint and needs
|
||||||
|
stepping over later when it is resumed. */
|
||||||
|
int need_step_over;
|
||||||
|
|
||||||
int thread_known;
|
int thread_known;
|
||||||
#ifdef HAVE_THREAD_DB_H
|
#ifdef HAVE_THREAD_DB_H
|
||||||
/* The thread handle, used for e.g. TLS access. Only valid if
|
/* The thread handle, used for e.g. TLS access. Only valid if
|
||||||
|
|
|
@ -32,38 +32,75 @@ struct breakpoint
|
||||||
CORE_ADDR pc;
|
CORE_ADDR pc;
|
||||||
unsigned char old_data[MAX_BREAKPOINT_LEN];
|
unsigned char old_data[MAX_BREAKPOINT_LEN];
|
||||||
|
|
||||||
/* Non-zero iff we are stepping over this breakpoint. */
|
/* Non-zero if this breakpoint is currently inserted in the
|
||||||
int reinserting;
|
inferior. */
|
||||||
|
int inserted;
|
||||||
/* Non-NULL iff this breakpoint was inserted to step over
|
|
||||||
another one. Points to the other breakpoint (which is also
|
|
||||||
in the *next chain somewhere). */
|
|
||||||
struct breakpoint *breakpoint_to_reinsert;
|
|
||||||
|
|
||||||
/* Function to call when we hit this breakpoint. If it returns 1,
|
/* Function to call when we hit this breakpoint. If it returns 1,
|
||||||
the breakpoint will be deleted; 0, it will be reinserted for
|
the breakpoint shall be deleted; 0, it will be left inserted. */
|
||||||
another round. */
|
|
||||||
int (*handler) (CORE_ADDR);
|
int (*handler) (CORE_ADDR);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct breakpoint *
|
||||||
|
set_raw_breakpoint_at (CORE_ADDR where)
|
||||||
|
{
|
||||||
|
struct process_info *proc = current_process ();
|
||||||
|
struct breakpoint *bp;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (breakpoint_data == NULL)
|
||||||
|
error ("Target does not support breakpoints.");
|
||||||
|
|
||||||
|
bp = xcalloc (1, sizeof (*bp));
|
||||||
|
bp->pc = where;
|
||||||
|
|
||||||
|
err = (*the_target->read_memory) (where, bp->old_data,
|
||||||
|
breakpoint_len);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
if (debug_threads)
|
||||||
|
fprintf (stderr,
|
||||||
|
"Failed to read shadow memory of"
|
||||||
|
" breakpoint at 0x%s (%s).\n",
|
||||||
|
paddress (where), strerror (err));
|
||||||
|
free (bp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*the_target->write_memory) (where, breakpoint_data,
|
||||||
|
breakpoint_len);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
if (debug_threads)
|
||||||
|
fprintf (stderr,
|
||||||
|
"Failed to insert breakpoint at 0x%s (%s).\n",
|
||||||
|
paddress (where), strerror (err));
|
||||||
|
free (bp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link the breakpoint in. */
|
||||||
|
bp->inserted = 1;
|
||||||
|
bp->next = proc->breakpoints;
|
||||||
|
proc->breakpoints = bp;
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
|
set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
|
||||||
{
|
{
|
||||||
struct process_info *proc = current_process ();
|
struct process_info *proc = current_process ();
|
||||||
struct breakpoint *bp;
|
struct breakpoint *bp;
|
||||||
|
|
||||||
if (breakpoint_data == NULL)
|
bp = set_raw_breakpoint_at (where);
|
||||||
error ("Target does not support breakpoints.");
|
|
||||||
|
|
||||||
bp = xmalloc (sizeof (struct breakpoint));
|
if (bp == NULL)
|
||||||
memset (bp, 0, sizeof (struct breakpoint));
|
{
|
||||||
|
/* warn? */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(*the_target->read_memory) (where, bp->old_data,
|
bp = xcalloc (1, sizeof (struct breakpoint));
|
||||||
breakpoint_len);
|
|
||||||
(*the_target->write_memory) (where, breakpoint_data,
|
|
||||||
breakpoint_len);
|
|
||||||
|
|
||||||
bp->pc = where;
|
|
||||||
bp->handler = handler;
|
bp->handler = handler;
|
||||||
|
|
||||||
bp->next = proc->breakpoints;
|
bp->next = proc->breakpoints;
|
||||||
|
@ -123,97 +160,145 @@ delete_breakpoint_at (CORE_ADDR addr)
|
||||||
delete_breakpoint (bp);
|
delete_breakpoint (bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
void
|
||||||
reinsert_breakpoint_handler (CORE_ADDR stop_pc)
|
set_reinsert_breakpoint (CORE_ADDR stop_at)
|
||||||
{
|
{
|
||||||
struct breakpoint *stop_bp, *orig_bp;
|
set_breakpoint_at (stop_at, NULL);
|
||||||
|
|
||||||
stop_bp = find_breakpoint_at (stop_pc);
|
|
||||||
if (stop_bp == NULL)
|
|
||||||
error ("lost the stopping breakpoint.");
|
|
||||||
|
|
||||||
orig_bp = stop_bp->breakpoint_to_reinsert;
|
|
||||||
if (orig_bp == NULL)
|
|
||||||
error ("no breakpoint to reinsert");
|
|
||||||
|
|
||||||
(*the_target->write_memory) (orig_bp->pc, breakpoint_data,
|
|
||||||
breakpoint_len);
|
|
||||||
orig_bp->reinserting = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
|
delete_reinsert_breakpoints (void)
|
||||||
{
|
{
|
||||||
struct breakpoint *bp, *orig_bp;
|
struct process_info *proc = current_process ();
|
||||||
|
struct breakpoint *bp, **bp_link;
|
||||||
|
|
||||||
orig_bp = find_breakpoint_at (stop_pc);
|
bp = proc->breakpoints;
|
||||||
if (orig_bp == NULL)
|
bp_link = &proc->breakpoints;
|
||||||
error ("Could not find original breakpoint in list.");
|
|
||||||
|
|
||||||
set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
|
while (bp)
|
||||||
|
{
|
||||||
|
*bp_link = bp->next;
|
||||||
|
delete_breakpoint (bp);
|
||||||
|
bp = *bp_link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bp = find_breakpoint_at (stop_at);
|
static void
|
||||||
if (bp == NULL)
|
uninsert_breakpoint (struct breakpoint *bp)
|
||||||
error ("Could not find breakpoint in list (reinserting by breakpoint).");
|
{
|
||||||
bp->breakpoint_to_reinsert = orig_bp;
|
if (bp->inserted)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
(*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
|
bp->inserted = 0;
|
||||||
breakpoint_len);
|
err = (*the_target->write_memory) (bp->pc, bp->old_data,
|
||||||
orig_bp->reinserting = 1;
|
breakpoint_len);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
bp->inserted = 1;
|
||||||
|
|
||||||
|
if (debug_threads)
|
||||||
|
fprintf (stderr,
|
||||||
|
"Failed to uninsert raw breakpoint at 0x%s (%s).\n",
|
||||||
|
paddress (bp->pc), strerror (err));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
uninsert_breakpoint (CORE_ADDR stopped_at)
|
uninsert_breakpoints_at (CORE_ADDR pc)
|
||||||
{
|
{
|
||||||
struct breakpoint *bp;
|
struct breakpoint *bp;
|
||||||
|
|
||||||
bp = find_breakpoint_at (stopped_at);
|
bp = find_breakpoint_at (pc);
|
||||||
if (bp == NULL)
|
if (bp == NULL)
|
||||||
error ("Could not find breakpoint in list (uninserting).");
|
{
|
||||||
|
/* This can happen when we remove all breakpoints while handling
|
||||||
|
a step-over. */
|
||||||
|
if (debug_threads)
|
||||||
|
fprintf (stderr,
|
||||||
|
"Could not find breakpoint at 0x%s "
|
||||||
|
"in list (uninserting).\n",
|
||||||
|
paddress (pc));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(*the_target->write_memory) (bp->pc, bp->old_data,
|
if (bp->inserted)
|
||||||
breakpoint_len);
|
uninsert_breakpoint (bp);
|
||||||
bp->reinserting = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
reinsert_breakpoint (CORE_ADDR stopped_at)
|
reinsert_breakpoint (struct breakpoint *bp)
|
||||||
{
|
{
|
||||||
struct breakpoint *bp;
|
int err;
|
||||||
|
|
||||||
bp = find_breakpoint_at (stopped_at);
|
if (bp->inserted)
|
||||||
if (bp == NULL)
|
|
||||||
error ("Could not find breakpoint in list (uninserting).");
|
|
||||||
if (! bp->reinserting)
|
|
||||||
error ("Breakpoint already inserted at reinsert time.");
|
error ("Breakpoint already inserted at reinsert time.");
|
||||||
|
|
||||||
(*the_target->write_memory) (bp->pc, breakpoint_data,
|
err = (*the_target->write_memory) (bp->pc, breakpoint_data,
|
||||||
breakpoint_len);
|
breakpoint_len);
|
||||||
bp->reinserting = 0;
|
if (err == 0)
|
||||||
|
bp->inserted = 1;
|
||||||
|
else if (debug_threads)
|
||||||
|
fprintf (stderr,
|
||||||
|
"Failed to reinsert breakpoint at 0x%s (%s).\n",
|
||||||
|
paddress (bp->pc), strerror (err));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
check_breakpoints (CORE_ADDR stop_pc)
|
reinsert_breakpoints_at (CORE_ADDR pc)
|
||||||
{
|
{
|
||||||
struct breakpoint *bp;
|
struct breakpoint *bp;
|
||||||
|
|
||||||
bp = find_breakpoint_at (stop_pc);
|
bp = find_breakpoint_at (pc);
|
||||||
if (bp == NULL)
|
if (bp == NULL)
|
||||||
return 0;
|
|
||||||
if (bp->reinserting)
|
|
||||||
{
|
{
|
||||||
warning ("Hit a removed breakpoint?");
|
/* This can happen when we remove all breakpoints while handling
|
||||||
return 0;
|
a step-over. */
|
||||||
|
if (debug_threads)
|
||||||
|
fprintf (stderr,
|
||||||
|
"Could not find breakpoint at 0x%s "
|
||||||
|
"in list (reinserting).\n",
|
||||||
|
paddress (pc));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*bp->handler) (bp->pc))
|
reinsert_breakpoint (bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
check_breakpoints (CORE_ADDR stop_pc)
|
||||||
|
{
|
||||||
|
struct process_info *proc = current_process ();
|
||||||
|
struct breakpoint *bp, **bp_link;
|
||||||
|
|
||||||
|
bp = proc->breakpoints;
|
||||||
|
bp_link = &proc->breakpoints;
|
||||||
|
|
||||||
|
while (bp)
|
||||||
{
|
{
|
||||||
delete_breakpoint (bp);
|
if (bp->pc == stop_pc)
|
||||||
return 2;
|
{
|
||||||
|
if (!bp->inserted)
|
||||||
|
{
|
||||||
|
warning ("Hit a removed breakpoint?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bp->handler != NULL && (*bp->handler) (stop_pc))
|
||||||
|
{
|
||||||
|
*bp_link = bp->next;
|
||||||
|
|
||||||
|
delete_breakpoint (bp);
|
||||||
|
|
||||||
|
bp = *bp_link;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bp_link = &bp->next;
|
||||||
|
bp = *bp_link;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -223,6 +308,32 @@ set_breakpoint_data (const unsigned char *bp_data, int bp_len)
|
||||||
breakpoint_len = bp_len;
|
breakpoint_len = bp_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
breakpoint_here (CORE_ADDR addr)
|
||||||
|
{
|
||||||
|
struct process_info *proc = current_process ();
|
||||||
|
struct breakpoint *bp;
|
||||||
|
|
||||||
|
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
|
||||||
|
if (bp->pc == addr)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
breakpoint_inserted_here (CORE_ADDR addr)
|
||||||
|
{
|
||||||
|
struct process_info *proc = current_process ();
|
||||||
|
struct breakpoint *bp;
|
||||||
|
|
||||||
|
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
|
||||||
|
if (bp->pc == addr && bp->inserted)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
|
check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
|
||||||
{
|
{
|
||||||
|
@ -288,7 +399,7 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
|
||||||
buf_offset = start - mem_addr;
|
buf_offset = start - mem_addr;
|
||||||
|
|
||||||
memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
|
memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
|
||||||
if (bp->reinserting == 0)
|
if (bp->inserted)
|
||||||
memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
|
memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,19 @@
|
||||||
|
|
||||||
/* Breakpoints are opaque. */
|
/* Breakpoints are opaque. */
|
||||||
|
|
||||||
|
/* Returns TRUE if breakpoints are supported on this target. */
|
||||||
|
|
||||||
|
int breakpoints_supported (void);
|
||||||
|
|
||||||
|
/* Returns TRUE if there's any breakpoint at ADDR in our tables,
|
||||||
|
inserted, or not. */
|
||||||
|
|
||||||
|
int breakpoint_here (CORE_ADDR addr);
|
||||||
|
|
||||||
|
/* Returns TRUE if there's any inserted breakpoint set at ADDR. */
|
||||||
|
|
||||||
|
int breakpoint_inserted_here (CORE_ADDR addr);
|
||||||
|
|
||||||
/* Create a new breakpoint at WHERE, and call HANDLER when
|
/* Create a new breakpoint at WHERE, and call HANDLER when
|
||||||
it is hit. HANDLER should return 1 if the breakpoint
|
it is hit. HANDLER should return 1 if the breakpoint
|
||||||
should be deleted, 0 otherwise. */
|
should be deleted, 0 otherwise. */
|
||||||
|
@ -36,24 +49,28 @@ void set_breakpoint_at (CORE_ADDR where,
|
||||||
|
|
||||||
void delete_breakpoint_at (CORE_ADDR addr);
|
void delete_breakpoint_at (CORE_ADDR addr);
|
||||||
|
|
||||||
/* Create a reinsertion breakpoint at STOP_AT for the breakpoint
|
/* Set a reinsert breakpoint at STOP_AT. */
|
||||||
currently at STOP_PC (and temporarily remove the breakpoint at
|
|
||||||
STOP_PC). */
|
|
||||||
|
|
||||||
void reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at);
|
void set_reinsert_breakpoint (CORE_ADDR stop_at);
|
||||||
|
|
||||||
/* Change the status of the breakpoint at WHERE to inserted. */
|
/* Delete all reinsert breakpoints. */
|
||||||
|
|
||||||
void reinsert_breakpoint (CORE_ADDR where);
|
void delete_reinsert_breakpoints (void);
|
||||||
|
|
||||||
/* Change the status of the breakpoint at WHERE to uninserted. */
|
/* Reinsert breakpoints at WHERE (and change their status to
|
||||||
|
inserted). */
|
||||||
|
|
||||||
void uninsert_breakpoint (CORE_ADDR where);
|
void reinsert_breakpoints_at (CORE_ADDR where);
|
||||||
|
|
||||||
|
/* Uninsert breakpoints at WHERE (and change their status to
|
||||||
|
uninserted). This still leaves the breakpoints in the table. */
|
||||||
|
|
||||||
|
void uninsert_breakpoints_at (CORE_ADDR where);
|
||||||
|
|
||||||
/* See if any breakpoint claims ownership of STOP_PC. Call the handler for
|
/* See if any breakpoint claims ownership of STOP_PC. Call the handler for
|
||||||
the breakpoint, if found. */
|
the breakpoint, if found. */
|
||||||
|
|
||||||
int check_breakpoints (CORE_ADDR stop_pc);
|
void check_breakpoints (CORE_ADDR stop_pc);
|
||||||
|
|
||||||
/* See if any breakpoints shadow the target memory area from MEM_ADDR
|
/* See if any breakpoints shadow the target memory area from MEM_ADDR
|
||||||
to MEM_ADDR + MEM_LEN. Update the data already read from the target
|
to MEM_ADDR + MEM_LEN. Update the data already read from the target
|
||||||
|
|
|
@ -162,8 +162,25 @@ struct inferior_list_entry
|
||||||
struct inferior_list_entry *next;
|
struct inferior_list_entry *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Opaque type for user-visible threads. */
|
|
||||||
struct thread_info;
|
struct thread_info;
|
||||||
|
struct process_info;
|
||||||
|
struct regcache;
|
||||||
|
|
||||||
|
#include "regcache.h"
|
||||||
|
#include "gdb/signals.h"
|
||||||
|
#include "gdb_signals.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "mem-break.h"
|
||||||
|
|
||||||
|
struct thread_info
|
||||||
|
{
|
||||||
|
struct inferior_list_entry entry;
|
||||||
|
void *target_data;
|
||||||
|
void *regcache_data;
|
||||||
|
|
||||||
|
/* The last wait status reported for this thread. */
|
||||||
|
struct target_waitstatus last_status;
|
||||||
|
};
|
||||||
|
|
||||||
struct dll_info
|
struct dll_info
|
||||||
{
|
{
|
||||||
|
@ -203,12 +220,6 @@ struct process_info
|
||||||
struct process_info *current_process (void);
|
struct process_info *current_process (void);
|
||||||
struct process_info *get_thread_process (struct thread_info *);
|
struct process_info *get_thread_process (struct thread_info *);
|
||||||
|
|
||||||
#include "regcache.h"
|
|
||||||
#include "gdb/signals.h"
|
|
||||||
#include "gdb_signals.h"
|
|
||||||
#include "target.h"
|
|
||||||
#include "mem-break.h"
|
|
||||||
|
|
||||||
/* Target-specific functions */
|
/* Target-specific functions */
|
||||||
|
|
||||||
void initialize_low ();
|
void initialize_low ();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue