2012-02-24 Luis Machado <lgustavo@codesourcery>
* server.c (handle_query): Advertise support for target-side breakpoint condition evaluation. (process_point_options): New function. (process_serial_event): When inserting a breakpoint, check for a target-side condition that should be evaluated. * mem-break.c: Include regcache.h and ax.h. (point_cond_list_t): New data structure. (breakpoint) <cond_list>: New field. (find_gdb_breakpoint_at): Make non-static. (delete_gdb_breakpoint_at): Clear any target-side conditions. (clear_gdb_breakpoint_conditions): New function. (add_condition_to_breakpoint): Likewise. (add_breakpoint_condition): Likewise. (gdb_condition_true_at_breakpoint): Likewise. (gdb_breakpoint_here): Return result directly instead of going through a local variable. * mem-break.h (find_gdb_breakpoint_at): New prototype. (clear_gdb_breakpoint_conditions): Likewise. (add_breakpoint_condition): Likewise. (gdb_condition_true_at_breakpoint): Likewise. * linux-low.c (linux_wait_1): Evaluate target-side breakpoint condition. (need_step_over_p): Take target-side breakpoint condition into consideration.
This commit is contained in:
parent
9f14eebc6a
commit
9f3a5c850e
5 changed files with 249 additions and 8 deletions
|
@ -1,3 +1,33 @@
|
||||||
|
2012-02-24 Luis Machado <lgustavo@codesourcery>
|
||||||
|
|
||||||
|
* server.c (handle_query): Advertise support for target-side
|
||||||
|
breakpoint condition evaluation.
|
||||||
|
(process_point_options): New function.
|
||||||
|
(process_serial_event): When inserting a breakpoint, check for
|
||||||
|
a target-side condition that should be evaluated.
|
||||||
|
|
||||||
|
* mem-break.c: Include regcache.h and ax.h.
|
||||||
|
(point_cond_list_t): New data structure.
|
||||||
|
(breakpoint) <cond_list>: New field.
|
||||||
|
(find_gdb_breakpoint_at): Make non-static.
|
||||||
|
(delete_gdb_breakpoint_at): Clear any target-side
|
||||||
|
conditions.
|
||||||
|
(clear_gdb_breakpoint_conditions): New function.
|
||||||
|
(add_condition_to_breakpoint): Likewise.
|
||||||
|
(add_breakpoint_condition): Likewise.
|
||||||
|
(gdb_condition_true_at_breakpoint): Likewise.
|
||||||
|
(gdb_breakpoint_here): Return result directly instead
|
||||||
|
of going through a local variable.
|
||||||
|
|
||||||
|
* mem-break.h (find_gdb_breakpoint_at): New prototype.
|
||||||
|
(clear_gdb_breakpoint_conditions): Likewise.
|
||||||
|
(add_breakpoint_condition): Likewise.
|
||||||
|
(gdb_condition_true_at_breakpoint): Likewise.
|
||||||
|
|
||||||
|
* linux-low.c (linux_wait_1): Evaluate target-side breakpoint condition.
|
||||||
|
(need_step_over_p): Take target-side breakpoint condition into
|
||||||
|
consideration.
|
||||||
|
|
||||||
2012-02-24 Luis Machado <lgustavo@codesourcery>
|
2012-02-24 Luis Machado <lgustavo@codesourcery>
|
||||||
|
|
||||||
* server.h: Include tracepoint.h.
|
* server.h: Include tracepoint.h.
|
||||||
|
|
|
@ -2398,7 +2398,8 @@ Check if we're already there.\n",
|
||||||
|| event_child->stopped_by_watchpoint
|
|| event_child->stopped_by_watchpoint
|
||||||
|| (!step_over_finished
|
|| (!step_over_finished
|
||||||
&& !bp_explains_trap && !trace_event)
|
&& !bp_explains_trap && !trace_event)
|
||||||
|| gdb_breakpoint_here (event_child->stop_pc));
|
|| (gdb_breakpoint_here (event_child->stop_pc)
|
||||||
|
&& gdb_condition_true_at_breakpoint (event_child->stop_pc)));
|
||||||
|
|
||||||
/* We found no reason GDB would want us to stop. We either hit one
|
/* We found no reason GDB would want us to stop. We either hit one
|
||||||
of our own breakpoints, or finished an internal step GDB
|
of our own breakpoints, or finished an internal step GDB
|
||||||
|
@ -3261,8 +3262,10 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy)
|
||||||
if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc))
|
if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc))
|
||||||
{
|
{
|
||||||
/* Don't step over a breakpoint that GDB expects to hit
|
/* Don't step over a breakpoint that GDB expects to hit
|
||||||
though. */
|
though. If the condition is being evaluated on the target's side
|
||||||
if (gdb_breakpoint_here (pc))
|
and it evaluate to false, step over this breakpoint as well. */
|
||||||
|
if (gdb_breakpoint_here (pc)
|
||||||
|
&& gdb_condition_true_at_breakpoint (pc))
|
||||||
{
|
{
|
||||||
if (debug_threads)
|
if (debug_threads)
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#include "regcache.h"
|
||||||
|
#include "ax.h"
|
||||||
|
|
||||||
const unsigned char *breakpoint_data;
|
const unsigned char *breakpoint_data;
|
||||||
int breakpoint_len;
|
int breakpoint_len;
|
||||||
|
@ -85,6 +87,16 @@ enum bkpt_type
|
||||||
other_breakpoint,
|
other_breakpoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct point_cond_list
|
||||||
|
{
|
||||||
|
/* Pointer to the agent expression that is the breakpoint's
|
||||||
|
conditional. */
|
||||||
|
struct agent_expr *cond;
|
||||||
|
|
||||||
|
/* Pointer to the next condition. */
|
||||||
|
struct point_cond_list *next;
|
||||||
|
};
|
||||||
|
|
||||||
/* A high level (in gdbserver's perspective) breakpoint. */
|
/* A high level (in gdbserver's perspective) breakpoint. */
|
||||||
struct breakpoint
|
struct breakpoint
|
||||||
{
|
{
|
||||||
|
@ -93,6 +105,12 @@ struct breakpoint
|
||||||
/* The breakpoint's type. */
|
/* The breakpoint's type. */
|
||||||
enum bkpt_type type;
|
enum bkpt_type type;
|
||||||
|
|
||||||
|
/* Pointer to the condition list that should be evaluated on
|
||||||
|
the target or NULL if the breakpoint is unconditional or
|
||||||
|
if GDB doesn't want us to evaluate the conditionals on the
|
||||||
|
target's side. */
|
||||||
|
struct point_cond_list *cond_list;
|
||||||
|
|
||||||
/* Link to this breakpoint's raw breakpoint. This is always
|
/* Link to this breakpoint's raw breakpoint. This is always
|
||||||
non-NULL. */
|
non-NULL. */
|
||||||
struct raw_breakpoint *raw;
|
struct raw_breakpoint *raw;
|
||||||
|
@ -632,7 +650,7 @@ delete_breakpoint (struct breakpoint *todel)
|
||||||
return delete_breakpoint_1 (proc, todel);
|
return delete_breakpoint_1 (proc, todel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct breakpoint *
|
struct breakpoint *
|
||||||
find_gdb_breakpoint_at (CORE_ADDR where)
|
find_gdb_breakpoint_at (CORE_ADDR where)
|
||||||
{
|
{
|
||||||
struct process_info *proc = current_process ();
|
struct process_info *proc = current_process ();
|
||||||
|
@ -692,6 +710,9 @@ delete_gdb_breakpoint_at (CORE_ADDR addr)
|
||||||
if (bp == NULL)
|
if (bp == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* Before deleting the breakpoint, make sure to free
|
||||||
|
its condition list. */
|
||||||
|
clear_gdb_breakpoint_conditions (addr);
|
||||||
err = delete_breakpoint (bp);
|
err = delete_breakpoint (bp);
|
||||||
if (err)
|
if (err)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -699,12 +720,126 @@ delete_gdb_breakpoint_at (CORE_ADDR addr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear all conditions associated with this breakpoint address. */
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_gdb_breakpoint_conditions (CORE_ADDR addr)
|
||||||
|
{
|
||||||
|
struct breakpoint *bp = find_gdb_breakpoint_at (addr);
|
||||||
|
struct point_cond_list *cond, **cond_p;
|
||||||
|
|
||||||
|
if (bp == NULL || bp->cond_list == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cond = bp->cond_list;
|
||||||
|
cond_p = &bp->cond_list->next;
|
||||||
|
|
||||||
|
while (cond != NULL)
|
||||||
|
{
|
||||||
|
free (cond->cond);
|
||||||
|
free (cond);
|
||||||
|
cond = *cond_p;
|
||||||
|
cond_p = &cond->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
bp->cond_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add condition CONDITION to GDBserver's breakpoint BP. */
|
||||||
|
|
||||||
|
void
|
||||||
|
add_condition_to_breakpoint (struct breakpoint *bp,
|
||||||
|
struct agent_expr *condition)
|
||||||
|
{
|
||||||
|
struct point_cond_list *new_cond;
|
||||||
|
|
||||||
|
/* Create new condition. */
|
||||||
|
new_cond = xcalloc (1, sizeof (*new_cond));
|
||||||
|
new_cond->cond = condition;
|
||||||
|
|
||||||
|
/* Add condition to the list. */
|
||||||
|
new_cond->next = bp->cond_list;
|
||||||
|
bp->cond_list = new_cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a target-side condition CONDITION to the breakpoint at ADDR. */
|
||||||
|
|
||||||
|
int
|
||||||
|
add_breakpoint_condition (CORE_ADDR addr, char **condition)
|
||||||
|
{
|
||||||
|
struct breakpoint *bp = find_gdb_breakpoint_at (addr);
|
||||||
|
char *actparm = *condition;
|
||||||
|
struct agent_expr *cond;
|
||||||
|
|
||||||
|
if (bp == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (condition == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
cond = gdb_parse_agent_expr (&actparm);
|
||||||
|
|
||||||
|
if (cond == NULL)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Condition evaluation failed. "
|
||||||
|
"Assuming unconditional.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_condition_to_breakpoint (bp, cond);
|
||||||
|
|
||||||
|
*condition = actparm;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate condition (if any) at breakpoint BP. Return 1 if
|
||||||
|
true and 0 otherwise. */
|
||||||
|
|
||||||
|
int
|
||||||
|
gdb_condition_true_at_breakpoint (CORE_ADDR where)
|
||||||
|
{
|
||||||
|
/* Fetch registers for the current inferior. */
|
||||||
|
struct breakpoint *bp = find_gdb_breakpoint_at (where);
|
||||||
|
ULONGEST value = 0;
|
||||||
|
struct point_cond_list *cl;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
struct regcache *regcache = get_thread_regcache (current_inferior, 1);
|
||||||
|
|
||||||
|
if (bp == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check if the breakpoint is unconditional. If it is,
|
||||||
|
the condition always evaluates to TRUE. */
|
||||||
|
if (bp->cond_list == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Evaluate each condition in the breakpoint's list of conditions.
|
||||||
|
Return true if any of the conditions evaluates to TRUE.
|
||||||
|
|
||||||
|
If we failed to evaluate the expression, TRUE is returned. This
|
||||||
|
forces GDB to reevaluate the conditions. */
|
||||||
|
for (cl = bp->cond_list;
|
||||||
|
cl && !value && !err; cl = cl->next)
|
||||||
|
{
|
||||||
|
/* Evaluate the condition. */
|
||||||
|
err = gdb_eval_agent_expr (regcache, NULL, cl->cond, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return (value != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return 1 if there is a breakpoint inserted in address WHERE
|
||||||
|
and if its condition, if it exists, is true. */
|
||||||
|
|
||||||
int
|
int
|
||||||
gdb_breakpoint_here (CORE_ADDR where)
|
gdb_breakpoint_here (CORE_ADDR where)
|
||||||
{
|
{
|
||||||
struct breakpoint *bp = find_gdb_breakpoint_at (where);
|
return (find_gdb_breakpoint_at (where) != NULL);
|
||||||
|
|
||||||
return (bp != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
struct breakpoint;
|
struct breakpoint;
|
||||||
struct fast_tracepoint_jump;
|
struct fast_tracepoint_jump;
|
||||||
|
|
||||||
|
/* Locate a breakpoint placed at address WHERE and return a pointer
|
||||||
|
to its structure. */
|
||||||
|
|
||||||
|
struct breakpoint *find_gdb_breakpoint_at (CORE_ADDR where);
|
||||||
|
|
||||||
/* Create a new GDB breakpoint at WHERE. Returns -1 if breakpoints
|
/* Create a new GDB breakpoint at WHERE. Returns -1 if breakpoints
|
||||||
are not supported on this target, 0 otherwise. */
|
are not supported on this target, 0 otherwise. */
|
||||||
|
|
||||||
|
@ -39,6 +44,19 @@ int breakpoint_here (CORE_ADDR addr);
|
||||||
|
|
||||||
int breakpoint_inserted_here (CORE_ADDR addr);
|
int breakpoint_inserted_here (CORE_ADDR addr);
|
||||||
|
|
||||||
|
/* Clear all breakpoint conditions associated with this address. */
|
||||||
|
|
||||||
|
void clear_gdb_breakpoint_conditions (CORE_ADDR addr);
|
||||||
|
|
||||||
|
/* Set target-side condition CONDITION to the breakpoint at ADDR. */
|
||||||
|
|
||||||
|
int add_breakpoint_condition (CORE_ADDR addr, char **condition);
|
||||||
|
|
||||||
|
/* Evaluation condition (if any) at breakpoint BP. Return 1 if
|
||||||
|
true and 0 otherwise. */
|
||||||
|
|
||||||
|
int gdb_condition_true_at_breakpoint (CORE_ADDR where);
|
||||||
|
|
||||||
/* Returns TRUE if there's a GDB breakpoint set at ADDR. */
|
/* Returns TRUE if there's a GDB breakpoint set at ADDR. */
|
||||||
|
|
||||||
int gdb_breakpoint_here (CORE_ADDR where);
|
int gdb_breakpoint_here (CORE_ADDR where);
|
||||||
|
|
|
@ -1621,6 +1621,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||||
strcat (own_buf, ";tracenz+");
|
strcat (own_buf, ";tracenz+");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Support target-side breakpoint conditions. */
|
||||||
|
strcat (own_buf, ";ConditionalBreakpoints+");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2825,6 +2828,43 @@ main (int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Process options coming from Z packets for *point at address
|
||||||
|
POINT_ADDR. PACKET is the packet buffer. *PACKET is updated
|
||||||
|
to point to the first char after the last processed option. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_point_options (CORE_ADDR point_addr, char **packet)
|
||||||
|
{
|
||||||
|
char *dataptr = *packet;
|
||||||
|
|
||||||
|
/* Check if data has the correct format. */
|
||||||
|
if (*dataptr != ';')
|
||||||
|
return;
|
||||||
|
|
||||||
|
dataptr++;
|
||||||
|
|
||||||
|
while (*dataptr)
|
||||||
|
{
|
||||||
|
switch (*dataptr)
|
||||||
|
{
|
||||||
|
case 'X':
|
||||||
|
/* Conditional expression. */
|
||||||
|
fprintf (stderr, "Found breakpoint condition.\n");
|
||||||
|
add_breakpoint_condition (point_addr, &dataptr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Unrecognized token, just skip it. */
|
||||||
|
fprintf (stderr, "Unknown token %c, ignoring.\n",
|
||||||
|
*dataptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip tokens until we find one that we recognize. */
|
||||||
|
while (*dataptr && *dataptr != 'X' && *dataptr != ';')
|
||||||
|
dataptr++;
|
||||||
|
}
|
||||||
|
*packet = dataptr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Event loop callback that handles a serial event. The first byte in
|
/* Event loop callback that handles a serial event. The first byte in
|
||||||
the serial buffer gets us here. We expect characters to arrive at
|
the serial buffer gets us here. We expect characters to arrive at
|
||||||
a brisk pace, so we read the rest of the packet with a blocking
|
a brisk pace, so we read the rest of the packet with a blocking
|
||||||
|
@ -3147,7 +3187,22 @@ process_serial_event (void)
|
||||||
case '4': /* access watchpoint */
|
case '4': /* access watchpoint */
|
||||||
require_running (own_buf);
|
require_running (own_buf);
|
||||||
if (insert && the_target->insert_point != NULL)
|
if (insert && the_target->insert_point != NULL)
|
||||||
|
{
|
||||||
|
/* Insert the breakpoint. If it is already inserted, nothing
|
||||||
|
will take place. */
|
||||||
res = (*the_target->insert_point) (type, addr, len);
|
res = (*the_target->insert_point) (type, addr, len);
|
||||||
|
|
||||||
|
/* GDB may have sent us a list of *point parameters to be
|
||||||
|
evaluated on the target's side. Read such list here. If we
|
||||||
|
already have a list of parameters, GDB is telling us to drop
|
||||||
|
that list and use this one instead. */
|
||||||
|
if (!res && (type == '0' || type == '1'))
|
||||||
|
{
|
||||||
|
/* Remove previous conditions. */
|
||||||
|
clear_gdb_breakpoint_conditions (addr);
|
||||||
|
process_point_options (addr, &dataptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (!insert && the_target->remove_point != NULL)
|
else if (!insert && the_target->remove_point != NULL)
|
||||||
res = (*the_target->remove_point) (type, addr, len);
|
res = (*the_target->remove_point) (type, addr, len);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue