From: Luis Gustavo <luis_gustavo@mentor.com>
To: gdb-patches@sourceware.org
Subject: [rfc target-side break conditions 5/5 v2] GDBServer-side changes
Date: Fri, 27 Jan 2012 20:34:00 -0000 [thread overview]
Message-ID: <4F230A29.3060404@mentor.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 236 bytes --]
This updated patch addresses all the comments made before and also
handles the updated Z packet format with the "conditions" marker.
I've added a function that parses (a generic set of) options passed
through the Z packets.
Luis
[-- Attachment #2: 0004-break_condition_gdbserver.diff --]
[-- Type: text/x-patch, Size: 10888 bytes --]
2012-01-26 Luis Machado <lgustavo@codesourcery>
gdbserver/
* 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.
Index: gdb/gdb/gdbserver/server.c
===================================================================
--- gdb.orig/gdb/gdbserver/server.c 2012-01-27 15:36:31.897821938 -0200
+++ gdb/gdb/gdbserver/server.c 2012-01-27 15:36:44.613821938 -0200
@@ -1621,6 +1621,9 @@ handle_query (char *own_buf, int packet_
strcat (own_buf, ";tracenz+");
}
+ /* Support target-side breakpoint conditions. */
+ strcat (own_buf, ";ConditionalBreakpoints+");
+
return;
}
@@ -2825,6 +2828,36 @@ 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;
+
+ while (dataptr[0] == ',')
+ {
+ dataptr++;
+
+ if (!strncmp (dataptr, "conditions=", strlen ("conditions=")))
+ {
+ /* We have conditions to parse. */
+ dataptr += strlen ("conditions");
+
+ /* Insert conditions. */
+ do
+ {
+ dataptr++;
+ add_breakpoint_condition (point_addr, &dataptr);
+ } while (*dataptr == ';');
+ }
+ }
+
+ *packet = dataptr;
+}
+
/* Event loop callback that handles a serial event. The first byte in
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
@@ -3147,7 +3180,22 @@ process_serial_event (void)
case '4': /* access watchpoint */
require_running (own_buf);
if (insert && the_target->insert_point != NULL)
- res = (*the_target->insert_point) (type, addr, len);
+ {
+ /* Insert the breakpoint. If it is already inserted, nothing
+ will take place. */
+ 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)
res = (*the_target->remove_point) (type, addr, len);
break;
Index: gdb/gdb/gdbserver/mem-break.c
===================================================================
--- gdb.orig/gdb/gdbserver/mem-break.c 2012-01-27 15:36:31.885821938 -0200
+++ gdb/gdb/gdbserver/mem-break.c 2012-01-27 15:36:44.613821938 -0200
@@ -20,6 +20,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "server.h"
+#include "regcache.h"
+#include "ax.h"
const unsigned char *breakpoint_data;
int breakpoint_len;
@@ -85,6 +87,16 @@ enum bkpt_type
other_breakpoint,
};
+typedef struct point_cond_list_t
+{
+ /* Pointer to the agent expression that is the breakpoint's
+ conditional. */
+ struct agent_expr *cond;
+
+ /* Pointer to the next condition. */
+ struct point_cond_list_t *next;
+} point_cond_list_t;
+
/* A high level (in gdbserver's perspective) breakpoint. */
struct breakpoint
{
@@ -93,6 +105,12 @@ struct breakpoint
/* The breakpoint's 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_t *cond_list;
+
/* Link to this breakpoint's raw breakpoint. This is always
non-NULL. */
struct raw_breakpoint *raw;
@@ -632,7 +650,7 @@ delete_breakpoint (struct breakpoint *to
return delete_breakpoint_1 (proc, todel);
}
-static struct breakpoint *
+struct breakpoint *
find_gdb_breakpoint_at (CORE_ADDR where)
{
struct process_info *proc = current_process ();
@@ -692,6 +710,9 @@ delete_gdb_breakpoint_at (CORE_ADDR addr
if (bp == NULL)
return -1;
+ /* Before deleting the breakpoint, make sure to free
+ its condition list. */
+ clear_gdb_breakpoint_conditions (addr);
err = delete_breakpoint (bp);
if (err)
return -1;
@@ -699,12 +720,119 @@ delete_gdb_breakpoint_at (CORE_ADDR addr
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_t *cond, **cond_p;
+
+ if (!bp || (bp && !bp->cond_list))
+ 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)
+{
+ point_cond_list_t *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
-gdb_breakpoint_here (CORE_ADDR where)
+add_breakpoint_condition (CORE_ADDR addr, char **condition)
+{
+ struct breakpoint *bp = find_gdb_breakpoint_at (addr);
+ char *actparm = (char *) *condition;
+ struct agent_expr *cond;
+
+ if (!bp)
+ return 1;
+
+ if (condition == NULL)
+ return 1;
+
+ cond = gdb_parse_agent_expr (&actparm);
+
+ if (!cond)
+ {
+ 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_t *cl;
- return (bp != NULL);
+ struct regcache *regcache = get_thread_regcache (current_inferior, 1);
+
+ if (!bp)
+ return 0;
+
+ /* Check if the breakpoint is unconditional. If it is,
+ the condition always evaluates to TRUE. */
+ if (!bp->cond_list)
+ return 1;
+
+ /* Evaluate each condition in the breakpoint's list of conditions.
+ Return true if any of the conditions evaluate to TRUE. */
+ for (cl = bp->cond_list; cl != NULL && !value; cl = cl->next)
+ {
+ /* Evaluate the condition. */
+ gdb_eval_agent_expr (regcache, NULL, cl->cond, &value);
+ value = value? 1 : 0;
+ }
+
+ return (value != 0);
+}
+
+/* Return 1 if there is a breakpoint inserted in address WHERE
+ and if its condition, if it exists, is true. */
+
+int
+gdb_breakpoint_here (CORE_ADDR where)
+{
+ return (find_gdb_breakpoint_at (where) != NULL);
}
void
Index: gdb/gdb/gdbserver/mem-break.h
===================================================================
--- gdb.orig/gdb/gdbserver/mem-break.h 2012-01-27 15:36:31.909821938 -0200
+++ gdb/gdb/gdbserver/mem-break.h 2012-01-27 15:36:44.665821938 -0200
@@ -25,6 +25,11 @@
struct breakpoint;
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
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);
+/* 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. */
int gdb_breakpoint_here (CORE_ADDR where);
Index: gdb/gdb/gdbserver/linux-low.c
===================================================================
--- gdb.orig/gdb/gdbserver/linux-low.c 2012-01-27 15:36:31.925821938 -0200
+++ gdb/gdb/gdbserver/linux-low.c 2012-01-27 15:36:44.669821938 -0200
@@ -2390,7 +2390,8 @@ Check if we're already there.\n",
|| event_child->stopped_by_watchpoint
|| (!step_over_finished
&& !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
of our own breakpoints, or finished an internal step GDB
@@ -3253,8 +3254,10 @@ need_step_over_p (struct inferior_list_e
if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc))
{
/* Don't step over a breakpoint that GDB expects to hit
- though. */
- if (gdb_breakpoint_here (pc))
+ though. If the condition is being evaluated on the target's side
+ 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)
fprintf (stderr,
next reply other threads:[~2012-01-27 20:34 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-27 20:34 Luis Gustavo [this message]
2012-02-07 22:14 ` Stan Shebs
2012-02-08 23:14 ` Luis Gustavo
2012-02-09 12:33 ` Pedro Alves
2012-02-22 15:25 ` Luis Gustavo
2012-02-23 17:25 ` Pedro Alves
2012-02-24 12:19 ` Luis Gustavo
2012-02-24 12:52 ` Pedro Alves
2012-02-24 12:59 ` Luis Gustavo
2012-02-24 13:01 ` Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4F230A29.3060404@mentor.com \
--to=luis_gustavo@mentor.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox