From ddcbc3975fffffdb5bb3bfb05b1f0ef3d67be3ee Mon Sep 17 00:00:00 2001 From: Don Breazeal Date: Tue, 12 May 2015 09:52:42 -0700 Subject: [PATCH] Clone remote breakpoints This patch implements gdbserver routines to clone the breakpoint lists of a process, duplicating them for another process. In gdbserver, each process maintains its own independent breakpoint list. When a fork call creates a child, all of the breakpoints currently inserted in the parent process are also inserted in the child process, but there is nothing to describe them in the data structures related to the child. The child must have a breakpoint list describing them so that they can be removed (if detaching) or recognized (if following). Implementation is a mechanical process of just cloning the lists in several new functions in gdbserver/mem-break.c. Tested by building, since none of the new functions are called yet. This was tested with another patch in the series that implements follow-fork. gdb/gdbserver/ChangeLog: * mem-break.c (APPEND_TO_LIST): Define macro. (clone_agent_expr): New function. (clone_one_breakpoint): New function. (clone_all_breakpoints): New function. * mem-break.h: Declare new functions. --- gdb/gdbserver/ChangeLog | 8 +++ gdb/gdbserver/mem-break.c | 105 ++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/mem-break.h | 6 +++ 3 files changed, 119 insertions(+) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index a37051d5c6..73788ece87 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,11 @@ +2015-05-12 Don Breazeal + + * mem-break.c (APPEND_TO_LIST): Define macro. + (clone_agent_expr): New function. + (clone_one_breakpoint): New function. + (clone_all_breakpoints): New function. + * mem-break.h: Declare new functions. + 2015-05-12 Don Breazeal * linux-low.c (linux_supports_fork_events): New function. diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c index 70fab2e3a7..d1b66bf1ee 100644 --- a/gdb/gdbserver/mem-break.c +++ b/gdb/gdbserver/mem-break.c @@ -28,6 +28,24 @@ int breakpoint_len; #define MAX_BREAKPOINT_LEN 8 +/* Helper macro used in loops that append multiple items to a singly-linked + list instead of inserting items at the head of the list, as, say, in the + breakpoint lists. LISTPP is a pointer to the pointer that is the head of + the new list. ITEMP is a pointer to the item to be added to the list. + TAILP must be defined to be the same type as ITEMP, and initialized to + NULL. */ + +#define APPEND_TO_LIST(listpp, itemp, tailp) \ + do \ + { \ + if ((tailp) == NULL) \ + *(listpp) = (itemp); \ + else \ + (tailp)->next = (itemp); \ + (tailp) = (itemp); \ + } \ + while (0) + /* GDB will never try to install multiple breakpoints at the same address. However, we can see GDB requesting to insert a breakpoint at an address is had already inserted one previously in a few @@ -1913,3 +1931,90 @@ free_all_breakpoints (struct process_info *proc) while (proc->breakpoints) delete_breakpoint_1 (proc, proc->breakpoints); } + +/* Clone an agent expression. */ + +static struct agent_expr * +clone_agent_expr (const struct agent_expr *src_ax) +{ + struct agent_expr *ax; + + ax = xcalloc (1, sizeof (*ax)); + ax->length = src_ax->length; + ax->bytes = xcalloc (ax->length, 1); + memcpy (ax->bytes, src_ax->bytes, ax->length); + return ax; +} + +/* Deep-copy the contents of one breakpoint to another. */ + +static struct breakpoint * +clone_one_breakpoint (const struct breakpoint *src) +{ + struct breakpoint *dest; + struct raw_breakpoint *dest_raw; + struct point_cond_list *current_cond; + struct point_cond_list *new_cond; + struct point_cond_list *cond_tail = NULL; + struct point_command_list *current_cmd; + struct point_command_list *new_cmd; + struct point_command_list *cmd_tail = NULL; + + /* Clone the raw breakpoint. */ + dest_raw = xcalloc (1, sizeof (*dest_raw)); + dest_raw->raw_type = src->raw->raw_type; + dest_raw->refcount = src->raw->refcount; + dest_raw->pc = src->raw->pc; + dest_raw->size = src->raw->size; + memcpy (dest_raw->old_data, src->raw->old_data, MAX_BREAKPOINT_LEN); + dest_raw->inserted = src->raw->inserted; + + /* Clone the high-level breakpoint. */ + dest = xcalloc (1, sizeof (*dest)); + dest->type = src->type; + dest->raw = dest_raw; + dest->handler = src->handler; + + /* Clone the condition list. */ + for (current_cond = src->cond_list; current_cond != NULL; + current_cond = current_cond->next) + { + new_cond = xcalloc (1, sizeof (*new_cond)); + new_cond->cond = clone_agent_expr (current_cond->cond); + APPEND_TO_LIST (&dest->cond_list, new_cond, cond_tail); + } + + /* Clone the command list. */ + for (current_cmd = src->command_list; current_cmd != NULL; + current_cmd = current_cmd->next) + { + new_cmd = xcalloc (1, sizeof (*new_cmd)); + new_cmd->cmd = clone_agent_expr (current_cmd->cmd); + new_cmd->persistence = current_cmd->persistence; + APPEND_TO_LIST (&dest->command_list, new_cmd, cmd_tail); + } + + return dest; +} + +/* Create a new breakpoint list NEW_LIST that is a copy of the + list starting at SRC_LIST. Create the corresponding new + raw_breakpoint list NEW_RAW_LIST as well. */ + +void +clone_all_breakpoints (struct breakpoint **new_list, + struct raw_breakpoint **new_raw_list, + const struct breakpoint *src_list) +{ + const struct breakpoint *bp; + struct breakpoint *new_bkpt; + struct breakpoint *bkpt_tail = NULL; + struct raw_breakpoint *raw_bkpt_tail = NULL; + + for (bp = src_list; bp != NULL; bp = bp->next) + { + new_bkpt = clone_one_breakpoint (bp); + APPEND_TO_LIST (new_list, new_bkpt, bkpt_tail); + APPEND_TO_LIST (new_raw_list, new_bkpt->raw, raw_bkpt_tail); + } +} diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h index 8b010c14df..b5a3208bf8 100644 --- a/gdb/gdbserver/mem-break.h +++ b/gdb/gdbserver/mem-break.h @@ -253,4 +253,10 @@ int insert_memory_breakpoint (struct raw_breakpoint *bp); int remove_memory_breakpoint (struct raw_breakpoint *bp); +/* Create a new breakpoint list NEW_BKPT_LIST that is a copy of SRC. */ + +void clone_all_breakpoints (struct breakpoint **new_bkpt_list, + struct raw_breakpoint **new_raw_bkpt_list, + const struct breakpoint *src); + #endif /* MEM_BREAK_H */ -- 2.34.1