X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fmem-break.c;h=5c73326ebb547a5c93bbae09ca4011c1a0ecd182;hb=bae62ee2087bb54fd06746c99de9b734cc58a721;hp=2ce3ab2f9b6153b30845640dbf2b0a06e4c8e6c4;hpb=ef7cab6ba16d76c3470fb27a0c8966513f7cb34a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c index 2ce3ab2f9b..5c73326ebb 100644 --- a/gdb/gdbserver/mem-break.c +++ b/gdb/gdbserver/mem-break.c @@ -1,5 +1,5 @@ /* Memory breakpoint operations for the remote server for GDB. - Copyright (C) 2002-2014 Free Software Foundation, Inc. + Copyright (C) 2002-2016 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -21,13 +21,27 @@ #include "server.h" #include "regcache.h" #include "ax.h" -#include - -const unsigned char *breakpoint_data; -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 @@ -84,8 +98,13 @@ struct raw_breakpoint breakpoint for a given PC. */ CORE_ADDR pc; - /* The breakpoint's size. */ - int size; + /* The breakpoint's kind. This is target specific. Most + architectures only use one specific instruction for breakpoints, while + others may use more than one. E.g., on ARM, we need to use different + breakpoint instructions on Thumb, Thumb-2, and ARM code. Likewise for + hardware breakpoints -- some architectures (including ARM) need to + setup debug registers differently depending on mode. */ + int kind; /* The breakpoint's shadow memory. */ unsigned char old_data[MAX_BREAKPOINT_LEN]; @@ -173,6 +192,27 @@ struct breakpoint int (*handler) (CORE_ADDR); }; +/* Return the breakpoint size from its kind. */ + +static int +bp_size (struct raw_breakpoint *bp) +{ + int size = 0; + + the_target->sw_breakpoint_from_kind (bp->kind, &size); + return size; +} + +/* Return the breakpoint opcode from its kind. */ + +static const gdb_byte * +bp_opcode (struct raw_breakpoint *bp) +{ + int size = 0; + + return the_target->sw_breakpoint_from_kind (bp->kind, &size); +} + /* See mem-break.h. */ enum target_hw_bp_type @@ -189,7 +229,8 @@ raw_bkpt_type_to_target_hw_bp_type (enum raw_bkpt_type raw_type) case raw_bkpt_type_access_wp: return hw_access; default: - fatal ("bad raw breakpoing type %d", (int) raw_type); + internal_error (__FILE__, __LINE__, + "bad raw breakpoint type %d", (int) raw_type); } } @@ -200,7 +241,7 @@ Z_packet_to_bkpt_type (char z_type) { gdb_assert ('0' <= z_type && z_type <= '4'); - return gdb_breakpoint_Z0 + (z_type - '0'); + return (enum bkpt_type) (gdb_breakpoint_Z0 + (z_type - '0')); } /* See mem-break.h. */ @@ -226,7 +267,7 @@ Z_packet_to_raw_bkpt_type (char z_type) } int -any_persistent_commands () +any_persistent_commands (void) { struct process_info *proc = current_process (); struct breakpoint *bp; @@ -264,13 +305,13 @@ find_enabled_raw_code_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type) NULL if not found. */ static struct raw_breakpoint * -find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int size) +find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int kind) { struct process_info *proc = current_process (); struct raw_breakpoint *bp; for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->pc == addr && bp->raw_type == type && bp->size == size) + if (bp->pc == addr && bp->raw_type == type && bp->kind == kind) return bp; return NULL; @@ -284,24 +325,10 @@ insert_memory_breakpoint (struct raw_breakpoint *bp) unsigned char buf[MAX_BREAKPOINT_LEN]; int err; - if (breakpoint_data == NULL) - return 1; - - /* If the architecture treats the size field of Z packets as a - 'kind' field, then we'll need to be able to know which is the - breakpoint instruction too. */ - if (bp->size != breakpoint_len) - { - if (debug_threads) - debug_printf ("Don't know how to insert breakpoints of size %d.\n", - bp->size); - return -1; - } - /* Note that there can be fast tracepoint jumps installed in the same memory range, so to get at the original memory, we need to use read_inferior_memory, which masks those out. */ - err = read_inferior_memory (bp->pc, buf, breakpoint_len); + err = read_inferior_memory (bp->pc, buf, bp_size (bp)); if (err != 0) { if (debug_threads) @@ -311,10 +338,10 @@ insert_memory_breakpoint (struct raw_breakpoint *bp) } else { - memcpy (bp->old_data, buf, breakpoint_len); + memcpy (bp->old_data, buf, bp_size (bp)); - err = (*the_target->write_memory) (bp->pc, breakpoint_data, - breakpoint_len); + err = (*the_target->write_memory) (bp->pc, bp_opcode (bp), + bp_size (bp)); if (err != 0) { if (debug_threads) @@ -341,8 +368,8 @@ remove_memory_breakpoint (struct raw_breakpoint *bp) note that we need to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ - memcpy (buf, bp->old_data, breakpoint_len); - err = write_inferior_memory (bp->pc, buf, breakpoint_len); + memcpy (buf, bp->old_data, bp_size (bp)); + err = write_inferior_memory (bp->pc, buf, bp_size (bp)); if (err != 0) { if (debug_threads) @@ -353,60 +380,68 @@ remove_memory_breakpoint (struct raw_breakpoint *bp) return err != 0 ? -1 : 0; } -/* Set a RAW breakpoint of type TYPE and size SIZE at WHERE. On +/* Set a RAW breakpoint of type TYPE and kind KIND at WHERE. On success, a pointer to the new breakpoint is returned. On failure, returns NULL and writes the error code to *ERR. */ static struct raw_breakpoint * -set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int size, +set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int kind, int *err) { struct process_info *proc = current_process (); struct raw_breakpoint *bp; + struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); if (type == raw_bkpt_type_sw || type == raw_bkpt_type_hw) { bp = find_enabled_raw_code_breakpoint_at (where, type); - if (bp != NULL && bp->size != size) + if (bp != NULL && bp->kind != kind) { - /* A different size than previously seen. The previous + /* A different kind than previously seen. The previous breakpoint must be gone then. */ if (debug_threads) - debug_printf ("Inconsistent breakpoint size? Was %d, now %d.\n", - bp->size, size); + debug_printf ("Inconsistent breakpoint kind? Was %d, now %d.\n", + bp->kind, kind); bp->inserted = -1; bp = NULL; } } else - bp = find_raw_breakpoint_at (where, type, size); + bp = find_raw_breakpoint_at (where, type, kind); - if (bp != NULL) + if (bp == NULL) { - bp->refcount++; - return bp; + bp = XCNEW (struct raw_breakpoint); + bp->pc = where; + bp->kind = kind; + bp->raw_type = type; + make_cleanup (xfree, bp); } - bp = xcalloc (1, sizeof (*bp)); - bp->pc = where; - bp->size = size; - bp->refcount = 1; - bp->raw_type = type; - - *err = the_target->insert_point (bp->raw_type, bp->pc, bp->size, bp); - if (*err != 0) + if (!bp->inserted) { - if (debug_threads) - debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n", - paddress (where), *err); - free (bp); - return NULL; + *err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); + if (*err != 0) + { + if (debug_threads) + debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n", + paddress (where), *err); + + do_cleanups (old_chain); + return NULL; + } + + bp->inserted = 1; } - bp->inserted = 1; - /* Link the breakpoint in. */ - bp->next = proc->raw_breakpoints; - proc->raw_breakpoints = bp; + discard_cleanups (old_chain); + + /* Link the breakpoint in, if this is the first reference. */ + if (++bp->refcount == 1) + { + bp->next = proc->raw_breakpoints; + proc->raw_breakpoints = bp; + } return bp; } @@ -510,7 +545,7 @@ delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel) pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ - buf = alloca (bp->length); + buf = (unsigned char *) alloca (bp->length); memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length); ret = write_inferior_memory (bp->pc, buf, bp->length); if (ret != 0) @@ -568,12 +603,12 @@ set_fast_tracepoint_jump (CORE_ADDR where, /* We don't, so create a new object. Double the length, because the flexible array member holds both the jump insn, and the shadow. */ - jp = xcalloc (1, sizeof (*jp) + (length * 2)); + jp = (struct fast_tracepoint_jump *) xcalloc (1, sizeof (*jp) + (length * 2)); jp->pc = where; jp->length = length; memcpy (fast_tracepoint_jump_insn (jp), insn, length); jp->refcount = 1; - buf = alloca (length); + buf = (unsigned char *) alloca (length); /* Note that there can be trap breakpoints inserted in the same address range. To access the original memory contents, we use @@ -653,7 +688,7 @@ uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc) pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ - buf = alloca (jp->length); + buf = (unsigned char *) alloca (jp->length); memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); err = write_inferior_memory (jp->pc, buf, jp->length); if (err != 0) @@ -700,7 +735,7 @@ reinsert_fast_tracepoint_jumps_at (CORE_ADDR where) to pass the current shadow contents, because write_inferior_memory updates any shadow memory with what we pass here, and we want that to be a nop. */ - buf = alloca (jp->length); + buf = (unsigned char *) alloca (jp->length); memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); err = write_inferior_memory (where, buf, jp->length); if (err != 0) @@ -715,7 +750,7 @@ reinsert_fast_tracepoint_jumps_at (CORE_ADDR where) } /* Set a high-level breakpoint of type TYPE, with low level type - RAW_TYPE and size SIZE, at WHERE. On success, a pointer to the new + RAW_TYPE and kind KIND, at WHERE. On success, a pointer to the new breakpoint is returned. On failure, returns NULL and writes the error code to *ERR. HANDLER is called when the breakpoint is hit. HANDLER should return 1 if the breakpoint should be deleted, 0 @@ -723,14 +758,14 @@ reinsert_fast_tracepoint_jumps_at (CORE_ADDR where) static struct breakpoint * set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type, - CORE_ADDR where, int size, + CORE_ADDR where, int kind, int (*handler) (CORE_ADDR), int *err) { struct process_info *proc = current_process (); struct breakpoint *bp; struct raw_breakpoint *raw; - raw = set_raw_breakpoint_at (raw_type, where, size, err); + raw = set_raw_breakpoint_at (raw_type, where, kind, err); if (raw == NULL) { @@ -738,7 +773,7 @@ set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type, return NULL; } - bp = xcalloc (1, sizeof (struct breakpoint)); + bp = XCNEW (struct breakpoint); bp->type = type; bp->raw = raw; @@ -756,9 +791,11 @@ struct breakpoint * set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) { int err_ignored; + CORE_ADDR placed_address = where; + int breakpoint_kind = target_breakpoint_kind_from_pc (&placed_address); return set_breakpoint (other_breakpoint, raw_bkpt_type_sw, - where, breakpoint_len, handler, + placed_address, breakpoint_kind, handler, &err_ignored); } @@ -782,7 +819,7 @@ delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) *bp_link = bp->next; - ret = the_target->remove_point (bp->raw_type, bp->pc, bp->size, + ret = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, bp); if (ret != 0) { @@ -874,12 +911,12 @@ delete_breakpoint (struct breakpoint *todel) return delete_breakpoint_1 (proc, todel); } -/* Locate a GDB breakpoint of type Z_TYPE and size SIZE placed at - address ADDR and return a pointer to its structure. If SIZE is -1, - the breakpoints' sizes are ignored. */ +/* Locate a GDB breakpoint of type Z_TYPE and kind KIND placed at + address ADDR and return a pointer to its structure. If KIND is -1, + the breakpoint's kind is ignored. */ static struct breakpoint * -find_gdb_breakpoint (char z_type, CORE_ADDR addr, int size) +find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) { struct process_info *proc = current_process (); struct breakpoint *bp; @@ -887,7 +924,7 @@ find_gdb_breakpoint (char z_type, CORE_ADDR addr, int size) for (bp = proc->breakpoints; bp != NULL; bp = bp->next) if (bp->type == type && bp->raw->pc == addr - && (size == -1 || bp->raw->size == size)) + && (kind == -1 || bp->raw->kind == kind)) return bp; return NULL; @@ -901,13 +938,13 @@ z_type_supported (char z_type) && the_target->supports_z_point_type (z_type)); } -/* Create a new GDB breakpoint of type Z_TYPE at ADDR with size SIZE. +/* Create a new GDB breakpoint of type Z_TYPE at ADDR with kind KIND. Returns a pointer to the newly created breakpoint on success. On failure returns NULL and sets *ERR to either -1 for error, or 1 if Z_TYPE breakpoints are not supported on this target. */ static struct breakpoint * -set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err) +set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err) { struct breakpoint *bp; enum bkpt_type type; @@ -935,9 +972,9 @@ set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err) if (bp != NULL) { - if (bp->raw->size != size) + if (bp->raw->kind != kind) { - /* A different size than previously seen. The previous + /* A different kind than previously seen. The previous breakpoint must be gone then. */ bp->raw->inserted = -1; delete_breakpoint (bp); @@ -958,10 +995,10 @@ set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err) } else { - /* Data breakpoints for the same address but different size are + /* Data breakpoints for the same address but different kind are expected. GDB doesn't merge these. The backend gets to do that if it wants/can. */ - bp = find_gdb_breakpoint (z_type, addr, size); + bp = find_gdb_breakpoint (z_type, addr, kind); } if (bp != NULL) @@ -976,7 +1013,7 @@ set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err) raw_type = Z_packet_to_raw_bkpt_type (z_type); type = Z_packet_to_bkpt_type (z_type); - return set_breakpoint (type, raw_type, addr, size, NULL, err); + return set_breakpoint (type, raw_type, addr, kind, NULL, err); } static int @@ -994,20 +1031,15 @@ check_gdb_bp_preconditions (char z_type, int *err) *err = 1; return 0; } - else if (current_inferior == NULL) - { - *err = -1; - return 0; - } - else - return 1; + + return 1; } /* See mem-break.h. This is a wrapper for set_gdb_breakpoint_1 that knows to prepare to access memory for Z0 breakpoints. */ struct breakpoint * -set_gdb_breakpoint (char z_type, CORE_ADDR addr, int size, int *err) +set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err) { struct breakpoint *bp; @@ -1018,12 +1050,14 @@ set_gdb_breakpoint (char z_type, CORE_ADDR addr, int size, int *err) access memory. */ if (z_type == Z_PACKET_SW_BP) { - *err = prepare_to_access_memory (); - if (*err != 0) - return NULL; + if (prepare_to_access_memory () != 0) + { + *err = -1; + return NULL; + } } - bp = set_gdb_breakpoint_1 (z_type, addr, size, err); + bp = set_gdb_breakpoint_1 (z_type, addr, kind, err); if (z_type == Z_PACKET_SW_BP) done_accessing_memory (); @@ -1031,18 +1065,18 @@ set_gdb_breakpoint (char z_type, CORE_ADDR addr, int size, int *err) return bp; } -/* Delete a GDB breakpoint of type Z_TYPE and size SIZE previously +/* Delete a GDB breakpoint of type Z_TYPE and kind KIND previously inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success, -1 on error, and 1 if Z_TYPE breakpoints are not supported on this target. */ static int -delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size) +delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind) { struct breakpoint *bp; int err; - bp = find_gdb_breakpoint (z_type, addr, size); + bp = find_gdb_breakpoint (z_type, addr, kind); if (bp == NULL) return -1; @@ -1060,7 +1094,7 @@ delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size) knows to prepare to access memory for Z0 breakpoints. */ int -delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int size) +delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) { int ret; @@ -1078,7 +1112,7 @@ delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int size) return -1; } - ret = delete_gdb_breakpoint_1 (z_type, addr, size); + ret = delete_gdb_breakpoint_1 (z_type, addr, kind); if (z_type == Z_PACKET_SW_BP) done_accessing_memory (); @@ -1152,7 +1186,7 @@ add_condition_to_breakpoint (struct breakpoint *bp, struct point_cond_list *new_cond; /* Create new condition. */ - new_cond = xcalloc (1, sizeof (*new_cond)); + new_cond = XCNEW (struct point_cond_list); new_cond->cond = condition; /* Add condition to the list. */ @@ -1211,7 +1245,7 @@ gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr) if (bp->cond_list == NULL) return 1; - ctx.regcache = get_thread_regcache (current_inferior, 1); + ctx.regcache = get_thread_regcache (current_thread, 1); ctx.tframe = NULL; ctx.tpoint = NULL; @@ -1243,14 +1277,14 @@ gdb_condition_true_at_breakpoint (CORE_ADDR where) /* Add commands COMMANDS to GDBserver's breakpoint BP. */ -void +static void add_commands_to_breakpoint (struct breakpoint *bp, struct agent_expr *commands, int persist) { struct point_command_list *new_cmd; /* Create new command. */ - new_cmd = xcalloc (1, sizeof (*new_cmd)); + new_cmd = XCNEW (struct point_command_list); new_cmd->cmd = commands; new_cmd->persistence = persist; @@ -1335,7 +1369,7 @@ run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr) if (bp == NULL) return 1; - ctx.regcache = get_thread_regcache (current_inferior, 1); + ctx.regcache = get_thread_regcache (current_thread, 1); ctx.tframe = NULL; ctx.tpoint = NULL; @@ -1421,7 +1455,7 @@ uninsert_raw_breakpoint (struct raw_breakpoint *bp) bp->inserted = 0; - err = the_target->remove_point (bp->raw_type, bp->pc, bp->size, bp); + err = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, bp); if (err != 0) { bp->inserted = 1; @@ -1475,15 +1509,35 @@ uninsert_all_breakpoints (void) uninsert_raw_breakpoint (bp); } +void +uninsert_reinsert_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + if (bp->type == reinsert_breakpoint) + { + gdb_assert (bp->raw->inserted > 0); + + /* Only uninsert the raw breakpoint if it only belongs to a + reinsert breakpoint. */ + if (bp->raw->refcount == 1) + uninsert_raw_breakpoint (bp->raw); + } + } +} + static void reinsert_raw_breakpoint (struct raw_breakpoint *bp) { int err; if (bp->inserted) - error ("Breakpoint already inserted at reinsert time."); + return; - err = the_target->insert_point (bp->raw_type, bp->pc, bp->size, bp); + err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); if (err == 0) bp->inserted = 1; else if (debug_threads) @@ -1519,6 +1573,28 @@ reinsert_breakpoints_at (CORE_ADDR pc) } } +int +has_reinsert_breakpoints (struct process_info *proc) +{ + struct breakpoint *bp, **bp_link; + + bp = proc->breakpoints; + bp_link = &proc->breakpoints; + + while (bp) + { + if (bp->type == reinsert_breakpoint) + return 1; + else + { + bp_link = &bp->next; + bp = *bp_link; + } + } + + return 0; +} + void reinsert_all_breakpoints (void) { @@ -1532,6 +1608,24 @@ reinsert_all_breakpoints (void) reinsert_raw_breakpoint (bp); } +void +reinsert_reinsert_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + if (bp->type == reinsert_breakpoint) + { + gdb_assert (bp->raw->inserted > 0); + + if (bp->raw->refcount == 1) + reinsert_raw_breakpoint (bp->raw); + } + } +} + void check_breakpoints (CORE_ADDR stop_pc) { @@ -1571,13 +1665,6 @@ check_breakpoints (CORE_ADDR stop_pc) } } -void -set_breakpoint_data (const unsigned char *bp_data, int bp_len) -{ - breakpoint_data = bp_data; - breakpoint_len = bp_len; -} - int breakpoint_here (CORE_ADDR addr) { @@ -1609,6 +1696,57 @@ breakpoint_inserted_here (CORE_ADDR addr) return 0; } +/* See mem-break.h. */ + +int +software_breakpoint_inserted_here (CORE_ADDR addr) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if (bp->raw_type == raw_bkpt_type_sw + && bp->pc == addr + && bp->inserted) + return 1; + + return 0; +} + +/* See mem-break.h. */ + +int +hardware_breakpoint_inserted_here (CORE_ADDR addr) +{ + struct process_info *proc = current_process (); + struct raw_breakpoint *bp; + + for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) + if (bp->raw_type == raw_bkpt_type_hw + && bp->pc == addr + && bp->inserted) + return 1; + + return 0; +} + +/* See mem-break.h. */ + +int +reinsert_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->type == reinsert_breakpoint + && bp->raw->pc == addr + && bp->raw->inserted) + return 1; + + return 0; +} + static int validate_inserted_breakpoint (struct raw_breakpoint *bp) { @@ -1618,9 +1756,9 @@ validate_inserted_breakpoint (struct raw_breakpoint *bp) gdb_assert (bp->inserted); gdb_assert (bp->raw_type == raw_bkpt_type_sw); - buf = alloca (breakpoint_len); - err = (*the_target->read_memory) (bp->pc, buf, breakpoint_len); - if (err || memcmp (buf, breakpoint_data, breakpoint_len) != 0) + buf = (unsigned char *) alloca (bp_size (bp)); + err = (*the_target->read_memory) (bp->pc, buf, bp_size (bp)); + if (err || memcmp (buf, bp_opcode (bp), bp_size (bp)) != 0) { /* Tag it as gone. */ bp->inserted = -1; @@ -1640,7 +1778,12 @@ delete_disabled_breakpoints (void) { next = bp->next; if (bp->raw->inserted < 0) - delete_breakpoint_1 (proc, bp); + { + /* If reinsert_breakpoints become disabled, that means the + manipulations (insertion and removal) of them are wrong. */ + gdb_assert (bp->type != reinsert_breakpoint); + delete_breakpoint_1 (proc, bp); + } } } @@ -1711,7 +1854,7 @@ check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) for (; bp != NULL; bp = bp->next) { - CORE_ADDR bp_end = bp->pc + breakpoint_len; + CORE_ADDR bp_end = bp->pc + bp_size (bp); CORE_ADDR start, end; int copy_offset, copy_len, buf_offset; @@ -1800,7 +1943,7 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, for (; bp != NULL; bp = bp->next) { - CORE_ADDR bp_end = bp->pc + breakpoint_len; + CORE_ADDR bp_end = bp->pc + bp_size (bp); CORE_ADDR start, end; int copy_offset, copy_len, buf_offset; @@ -1831,7 +1974,7 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, if (bp->inserted > 0) { if (validate_inserted_breakpoint (bp)) - memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len); + memcpy (buf + buf_offset, bp_opcode (bp) + copy_offset, copy_len); else disabled_one = 1; } @@ -1878,3 +2021,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 = XCNEW (struct agent_expr); + ax->length = src_ax->length; + ax->bytes = (unsigned char *) 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 = XCNEW (struct raw_breakpoint); + dest_raw->raw_type = src->raw->raw_type; + dest_raw->refcount = src->raw->refcount; + dest_raw->pc = src->raw->pc; + dest_raw->kind = src->raw->kind; + memcpy (dest_raw->old_data, src->raw->old_data, MAX_BREAKPOINT_LEN); + dest_raw->inserted = src->raw->inserted; + + /* Clone the high-level breakpoint. */ + dest = XCNEW (struct breakpoint); + 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 = XCNEW (struct point_cond_list); + 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 = XCNEW (struct point_command_list); + 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); + } +}