diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 5394ae4..42f04a3 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -127,6 +127,12 @@ static int breakpoint_address_match (struct address_space *aspace1, struct address_space *aspace2, CORE_ADDR addr2); +static int breakpoint_address_match_range (struct address_space *aspace1, + CORE_ADDR addr1, + CORE_ADDR len1, + struct address_space *aspace2, + CORE_ADDR addr2); + static void breakpoints_info (char *, int); static void breakpoint_1 (int, int); @@ -1059,6 +1065,8 @@ update_watchpoint (struct breakpoint *b, int reparse) struct bp_location *loc; int frame_saved; bpstat bs; + CORE_ADDR mask = 0; + ULONGEST range = 0; /* If this is a local watchpoint, we only want to check if the watchpoint frame is in scope if the current thread is the thread @@ -1066,7 +1074,19 @@ update_watchpoint (struct breakpoint *b, int reparse) if (!watchpoint_in_thread_scope (b)) return; - /* We don't free locations. They are stored in bp_location array and + /* We've got to save some special fields before updating + this watchpoint. */ + switch (b->hw_point_flag) + { + case HW_POINT_MASKED_WATCH: + mask = b->loc->hw_wp_mask; + break; + case HW_POINT_RANGED_WATCH: + range = b->loc->ranged_hw_bp_length; + break; + } + + /* We don't free locations. They are stored in bp_location_chain and update_global_locations will eventually delete them and remove breakpoints if needed. */ b->loc = NULL; @@ -1100,6 +1120,7 @@ update_watchpoint (struct breakpoint *b, int reparse) if (within_current_scope && reparse) { char *s; + if (b->exp) { xfree (b->exp); @@ -1151,6 +1172,13 @@ update_watchpoint (struct breakpoint *b, int reparse) && reparse) { int i, mem_cnt, other_type_used; + enum enable_state e; + + /* We have to temporary disable this watchpoint, otherwise + we will count it twice (once as being inserted, and once + as a watchpoint that we want to insert). */ + e = b->enable_state; + b->enable_state = bp_disabled; i = hw_watchpoint_used_count (bp_hardware_watchpoint, &other_type_used); @@ -1167,6 +1195,8 @@ update_watchpoint (struct breakpoint *b, int reparse) else b->type = bp_hardware_watchpoint; } + /* Restoring the original state. */ + b->enable_state = e; } frame_pspace = get_frame_program_space (get_selected_frame (NULL)); @@ -1229,6 +1259,17 @@ update_watchpoint (struct breakpoint *b, int reparse) { char *s = b->cond_string; b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0); + + if (b->type == bp_hardware_watchpoint + && TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_COND_HW_ACCEL) + && TARGET_CAN_USE_WATCHPOINT_COND_ACCEL_P (b->loc)) + { + TARGET_GET_WATCHPOINT_COND_ACCEL_ADDR (b->loc, + &b->loc->cond_hw_addr); + b->hw_point_flag = HW_POINT_COND_HW_ACCEL; + } + else + b->hw_point_flag = HW_POINT_NONE; } } else if (!within_current_scope) @@ -1242,6 +1283,13 @@ in which its expression is valid.\n"), b->disposition = disp_del_at_next_stop; } + /* Restoring some special fields. */ + if (b->loc) + { + b->loc->hw_wp_mask = mask; + b->loc->ranged_hw_bp_length = range; + } + /* Restore the selected frame. */ if (frame_saved) select_frame (frame_find_by_id (saved_frame_id)); @@ -1302,6 +1350,7 @@ insert_bp_location (struct bp_location *bpt, memset (&bpt->target_info, 0, sizeof (bpt->target_info)); bpt->target_info.placed_address = bpt->address; bpt->target_info.placed_address_space = bpt->pspace->aspace; + bpt->target_info.length = bpt->ranged_hw_bp_length; if (bpt->loc_type == bp_loc_software_breakpoint || bpt->loc_type == bp_loc_hardware_breakpoint) @@ -1472,9 +1521,20 @@ Note: automatically using hardware breakpoints for read-only addresses.\n")); watchpoints. It's not clear that it's necessary... */ && bpt->owner->disposition != disp_del_at_next_stop) { - val = target_insert_watchpoint (bpt->address, - bpt->length, - bpt->watchpoint_type); + if (bpt->owner->hw_point_flag == HW_POINT_MASKED_WATCH) + val = target_insert_mask_watchpoint (bpt->address, + bpt->length, + bpt->watchpoint_type, + bpt->hw_wp_mask); + else if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL) + val = target_insert_cond_accel_watchpoint (bpt->address, + bpt->length, + bpt->watchpoint_type, + bpt->cond_hw_addr); + else + val = target_insert_watchpoint (bpt->address, + bpt->length, + bpt->watchpoint_type); bpt->inserted = (val != -1); } @@ -1613,6 +1673,7 @@ insert_breakpoint_locations (void) val = insert_bp_location (b, tmp_error_stream, &disabled_breaks, &hw_breakpoint_error); + if (val) error = val; } @@ -2100,8 +2161,17 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is) struct value *n; b->inserted = (is == mark_inserted); - val = target_remove_watchpoint (b->address, b->length, - b->watchpoint_type); + if (b->owner->hw_point_flag == HW_POINT_MASKED_WATCH) + val = target_remove_mask_watchpoint (b->address, b->length, + b->watchpoint_type, + b->hw_wp_mask); + else if (b->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL) + val = target_remove_cond_accel_watchpoint (b->address, b->length, + b->watchpoint_type, + b->cond_hw_addr); + else + val = target_remove_watchpoint (b->address, b->length, + b->watchpoint_type); /* Failure to remove any of the hardware watchpoints comes here. */ if ((is == mark_uninserted) && (b->inserted)) @@ -2267,8 +2337,15 @@ breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc) if ((breakpoint_enabled (bpt->owner) || bpt->owner->enable_state == bp_permanent) - && breakpoint_address_match (bpt->pspace->aspace, bpt->address, - aspace, pc)) + && ((breakpoint_address_match (bpt->pspace->aspace, bpt->address, + aspace, pc) && ((bpt->address == pc))) + || (bpt->owner->hw_point_flag == HW_POINT_RANGED_BREAK + && breakpoint_address_match_range (bpt->pspace->aspace, + bpt->address, + bpt->ranged_hw_bp_length, + aspace, pc) + && pc >= bpt->address + && pc < (bpt->address + bpt->ranged_hw_bp_length)))) { if (overlay_debugging && section_is_overlay (bpt->section) @@ -2839,6 +2916,11 @@ print_it_typical (bpstat bs) annotate_breakpoint (b->number); if (bp_temp) ui_out_text (uiout, "\nTemporary breakpoint "); + else if (bl && bl->owner + && bl->owner->hw_point_flag == HW_POINT_RANGED_BREAK) + ui_out_text (uiout, "\nRange hardware assisted breakpoint "); + else if (b->type == bp_hardware_breakpoint) + ui_out_text (uiout, "\nHardware assisted breakpoint "); else ui_out_text (uiout, "\nBreakpoint "); if (ui_out_is_mi_like_p (uiout)) @@ -2887,13 +2969,19 @@ print_it_typical (bpstat bs) (uiout, "reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER)); mention (b); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nOld value = "); - watchpoint_value_print (bs->old_val, stb->stream); - ui_out_field_stream (uiout, "old", stb); - ui_out_text (uiout, "\nNew value = "); - watchpoint_value_print (b->val, stb->stream); - ui_out_field_stream (uiout, "new", stb); + if (b->hw_point_flag == HW_POINT_MASKED_WATCH) + ui_out_text (uiout, "\nCheck the underlying instruction \ +at PC for address and value related to this watchpoint trigger.\n"); + else + { + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nOld value = "); + watchpoint_value_print (bs->old_val, stb->stream); + ui_out_field_stream (uiout, "old", stb); + ui_out_text (uiout, "\nNew value = "); + watchpoint_value_print (b->val, stb->stream); + ui_out_field_stream (uiout, "new", stb); + } ui_out_text (uiout, "\n"); /* More than one watchpoint may have been triggered. */ result = PRINT_UNKNOWN; @@ -2905,10 +2993,18 @@ print_it_typical (bpstat bs) (uiout, "reason", async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER)); mention (b); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nValue = "); - watchpoint_value_print (b->val, stb->stream); - ui_out_field_stream (uiout, "value", stb); + + if (b->hw_point_flag == HW_POINT_MASKED_WATCH) + ui_out_text (uiout, "\nCheck the underlying instruction\ + at PC for address and value related to this watchpoint trigger.\n"); + else + { + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nValue = "); + watchpoint_value_print (b->val, stb->stream); + ui_out_field_stream (uiout, "value", stb); + } + ui_out_text (uiout, "\n"); result = PRINT_UNKNOWN; break; @@ -2922,24 +3018,39 @@ print_it_typical (bpstat bs) (uiout, "reason", async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); mention (b); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nOld value = "); - watchpoint_value_print (bs->old_val, stb->stream); - ui_out_field_stream (uiout, "old", stb); - ui_out_text (uiout, "\nNew value = "); + + if (b->hw_point_flag != HW_POINT_MASKED_WATCH) + { + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nOld value = "); + watchpoint_value_print (bs->old_val, stb->stream); + ui_out_field_stream (uiout, "old", stb); + ui_out_text (uiout, "\nNew value = "); + } } else { mention (b); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); - make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nValue = "); + + if (b->hw_point_flag != HW_POINT_MASKED_WATCH) + { + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER)); + make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nValue = "); + } } - watchpoint_value_print (b->val, stb->stream); - ui_out_field_stream (uiout, "new", stb); + if (b->hw_point_flag == HW_POINT_MASKED_WATCH) + ui_out_text (uiout, "\nCheck the underlying instruction\ + at PC for address and value related to this watchpoint trigger.\n"); + else + { + watchpoint_value_print (b->val, stb->stream); + ui_out_field_stream (uiout, "new", stb); + } + ui_out_text (uiout, "\n"); result = PRINT_UNKNOWN; break; @@ -3148,15 +3259,30 @@ watchpoints_triggered (struct target_waitstatus *ws) b->watchpoint_triggered = watch_triggered_no; for (loc = b->loc; loc; loc = loc->next) - /* Exact match not required. Within range is - sufficient. */ - if (target_watchpoint_addr_within_range (¤t_target, - addr, loc->address, - loc->length)) - { - b->watchpoint_triggered = watch_triggered_yes; - break; - } + { + CORE_ADDR newaddr, start; + + if (loc->owner->hw_point_flag == HW_POINT_MASKED_WATCH) + { + newaddr = addr & loc->hw_wp_mask; + start = loc->address & loc->hw_wp_mask; + } + else + { + newaddr = addr; + start = loc->address; + } + + /* Exact match not required. Within range is + sufficient. */ + if (target_watchpoint_addr_within_range (¤t_target, + newaddr, start, + loc->length)) + { + b->watchpoint_triggered = watch_triggered_yes; + break; + } + } } return 1; @@ -3174,7 +3300,23 @@ watchpoints_triggered (struct target_waitstatus *ws) #define BP_TEMPFLAG 1 #define BP_HARDWAREFLAG 2 -/* Check watchpoint condition. */ +/* Check watchpoint condition. We can't use value_equal because it coerces + an array to a pointer, thus comparing just the address of the array instead + of its contents. This is not what we want. */ + +static int +value_equal_watchpoint (struct value *arg1, struct value *arg2) +{ + struct type *type1, *type2; + + type1 = check_typedef (value_type (arg1)); + type2 = check_typedef (value_type (arg2)); + + return TYPE_CODE (type1) == TYPE_CODE (type2) + && TYPE_LENGTH (type1) == TYPE_LENGTH (type2) + && memcmp (value_contents (arg1), value_contents (arg2), + TYPE_LENGTH (type1)) == 0; +} static int watchpoint_check (void *p) @@ -3246,7 +3388,7 @@ watchpoint_check (void *p) fetch_watchpoint_value (b->exp, &new_val, NULL, NULL); if ((b->val != NULL) != (new_val != NULL) - || (b->val != NULL && !value_equal (b->val, new_val))) + || (b->val != NULL && !value_equal_watchpoint (b->val, new_val))) { if (new_val != NULL) { @@ -3259,6 +3401,10 @@ watchpoint_check (void *p) /* We will stop here */ return WP_VALUE_CHANGED; } + else if (b->hw_point_flag == HW_POINT_MASKED_WATCH) + /* Since we don't the exact trigger address (from stopped_data_address) + Just tell the user we've triggered a mask watchpoint. */ + return WP_VALUE_CHANGED; else { /* Nothing changed, don't do anything. */ @@ -3337,7 +3483,10 @@ bpstat_check_location (const struct bp_location *bl, if (b->type == bp_hardware_breakpoint) { - if (bl->address != bp_addr) + if ((b->hw_point_flag == HW_POINT_NONE && bl->address != bp_addr) + || (b->hw_point_flag == HW_POINT_RANGED_BREAK + && (bp_addr < bl->address + || (bp_addr >= bl->address + bl->ranged_hw_bp_length)))) return 0; if (overlay_debugging /* unmapped overlay section */ && section_is_overlay (bl->section) @@ -3465,6 +3614,11 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) if (frame_id_p (b->frame_id) && !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ()))) bs->stop = 0; + else if (b->hw_point_flag == HW_POINT_COND_HW_ACCEL) + /* The condition is going to be hardware-accelerated, which means + that we don't have to evaluate it because the hardware already + did this. Just return. */ + return; else if (bs->stop) { int value_is_zero = 0; @@ -4097,7 +4251,13 @@ print_one_breakpoint_location (struct breakpoint *b, if (opts.addressprint) { if (print_address_bits <= 32) - strcat (wrap_indent, " "); + { + if (loc && loc->owner + && loc->owner->hw_point_flag == HW_POINT_RANGED_BREAK) + strcat (wrap_indent, " "); + else + strcat (wrap_indent, " "); + } else strcat (wrap_indent, " "); } @@ -4155,8 +4315,14 @@ print_one_breakpoint_location (struct breakpoint *b, else if (b->loc == NULL || loc->shlib_disabled) ui_out_field_string (uiout, "addr", ""); else - ui_out_field_core_addr (uiout, "addr", - loc->gdbarch, loc->address); + if (loc && loc->owner + && loc->owner->hw_point_flag == HW_POINT_RANGED_BREAK) + ui_out_field_range_core_addr (uiout, "addr", loc->gdbarch, + loc->address, + loc->address + loc->ranged_hw_bp_length); + else + ui_out_field_core_addr (uiout, "addr", + loc->gdbarch, loc->address); } annotate_field (5); if (!header_of_multiple) @@ -4492,7 +4658,10 @@ breakpoint_1 (int bnum, int allflag) if (nr_printable_breakpoints > 0) annotate_field (4); if (print_address_bits <= 32) - ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */ + if (b && b->hw_point_flag == HW_POINT_RANGED_BREAK) + ui_out_table_header (uiout, 18, ui_left, "addr", "Address"); + else + ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */ else ui_out_table_header (uiout, 18, ui_left, "addr", "Address");/* 5 */ } @@ -4681,6 +4850,23 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1, && addr1 == addr2); } +/* Returns true if {ASPACE1,ADDR1} and {ASPACE2,ADDR2} represent the + same breakpoint location, but (ADDR1 <= ADDR2 <= ADDR1 + LEN1). + In most targets, this can only be true if ASPACE1 matches ASPACE2. + On targets that have global breakpoints, the address space + doesn't really matter. */ + +static int +breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1, + CORE_ADDR len1, + struct address_space *aspace2, CORE_ADDR addr2) +{ + return ((gdbarch_has_global_breakpoints (target_gdbarch) + || aspace1 == aspace2) + && addr2 >= addr1 + && addr2 <= addr1 + len1); +} + /* Assuming LOC1 and LOC2's types' have meaningful target addresses (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2 represent the same location. */ @@ -4850,6 +5036,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch, b->syscalls_to_be_caught = NULL; b->ops = NULL; b->condition_not_parsed = 0; + b->hw_point_flag = HW_POINT_NONE; /* Add this breakpoint to the end of the chain so that a list of breakpoints will come out in order @@ -4941,6 +5128,7 @@ set_raw_breakpoint (struct gdbarch *gdbarch, /* Store the program space that was used to set the breakpoint, for breakpoint resetting. */ b->pspace = sal.pspace; + b->loc->ranged_hw_bp_length = 0; if (sal.symtab == NULL) b->source_file = NULL; @@ -5771,7 +5959,12 @@ hw_breakpoint_used_count (void) ALL_BREAKPOINTS (b) { if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b)) - i++; + { + i++; + /* Special types of hardware breakpoints can use more than + one slot. */ + i += target_hw_point_extra_slot_count (b->hw_point_flag); + } } return i; @@ -5789,10 +5982,15 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used) if (breakpoint_enabled (b)) { if (b->type == type) - i++; - else if ((b->type == bp_hardware_watchpoint - || b->type == bp_read_watchpoint - || b->type == bp_access_watchpoint)) + { + i++; + /* Special types of hardware watchpoints can use more + than one slot. */ + i += target_hw_point_extra_slot_count (b->hw_point_flag); + } + else if ((b->type == bp_hardware_watchpoint || + b->type == bp_read_watchpoint || + b->type == bp_access_watchpoint)) *other_type_used = 1; } } @@ -6009,6 +6207,10 @@ mention (struct breakpoint *b) do_cleanups (ui_out_chain); break; case bp_hardware_watchpoint: + if (b->hw_point_flag == HW_POINT_MASKED_WATCH) + ui_out_text (uiout, "Mask "); + else if (b->hw_point_flag == HW_POINT_RANGED_WATCH) + ui_out_text (uiout, "Range "); ui_out_text (uiout, "Hardware watchpoint "); ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt"); ui_out_field_int (uiout, "number", b->number); @@ -6017,6 +6219,10 @@ mention (struct breakpoint *b) do_cleanups (ui_out_chain); break; case bp_read_watchpoint: + if (b->hw_point_flag == HW_POINT_MASKED_WATCH) + ui_out_text (uiout, "Mask "); + else if (b->hw_point_flag == HW_POINT_RANGED_WATCH) + ui_out_text (uiout, "Range "); ui_out_text (uiout, "Hardware read watchpoint "); ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt"); ui_out_field_int (uiout, "number", b->number); @@ -6025,6 +6231,10 @@ mention (struct breakpoint *b) do_cleanups (ui_out_chain); break; case bp_access_watchpoint: + if (b->hw_point_flag == HW_POINT_MASKED_WATCH) + ui_out_text (uiout, "Mask "); + else if (b->hw_point_flag == HW_POINT_RANGED_WATCH) + ui_out_text (uiout, "Range "); ui_out_text (uiout, "Hardware access (read/write) watchpoint "); ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt"); ui_out_field_int (uiout, "number", b->number); @@ -6051,6 +6261,9 @@ mention (struct breakpoint *b) say_where = 0; break; } + + if (b->hw_point_flag == HW_POINT_RANGED_BREAK) + printf_filtered (_("Range ")); printf_filtered (_("Hardware assisted breakpoint %d"), b->number); say_where = 1; break; @@ -7089,74 +7302,143 @@ watch_command_1 (char *arg, int accessflag, int from_tty) char *exp_start = NULL; char *exp_end = NULL; char *tok, *id_tok_start, *end_tok; - int toklen; + int toklen = -1; char *cond_start = NULL; char *cond_end = NULL; int i, other_type_used, target_resources_ok = 0; enum bptype bp_type; int mem_cnt = 0; int thread = -1; + /* Flag to indicate whether we are going to use masks for + the hardware watchpoint. */ + int use_mask = 0; + CORE_ADDR hw_wp_mask = 0; + + do { + /* Make sure that we actually have parameters to parse. */ + if (arg != NULL && arg[0] != '\0') + { + toklen = strlen (arg); /* Size of argument list. */ - /* Make sure that we actually have parameters to parse. */ - if (arg != NULL && arg[0] != '\0') - { - toklen = strlen (arg); /* Size of argument list. */ - - /* Points tok to the end of the argument list. */ - tok = arg + toklen - 1; + /* Points tok to the end of the argument list. */ + tok = arg + toklen - 1; - /* Go backwards in the parameters list. Skip the last parameter. - If we're expecting a 'thread ' parameter, this should - be the thread identifier. */ - while (tok > arg && (*tok == ' ' || *tok == '\t')) - tok--; - while (tok > arg && (*tok != ' ' && *tok != '\t')) - tok--; + /* Go backwards in the parameters list. Skip the last parameter. + If we're expecting a 'thread ' parameter, this should + be the thread identifier. */ + while (tok > arg && (*tok == ' ' || *tok == '\t')) + tok--; + while (tok > arg && (*tok != ' ' && *tok != '\t')) + tok--; - /* Points end_tok to the beginning of the last token. */ - id_tok_start = tok + 1; + /* Points end_tok to the beginning of the last token. */ + id_tok_start = tok + 1; - /* Go backwards in the parameters list. Skip one more parameter. - If we're expecting a 'thread ' parameter, we should - reach a "thread" token. */ - while (tok > arg && (*tok == ' ' || *tok == '\t')) - tok--; + /* Go backwards in the parameters list. Skip one more parameter. + If we're expecting a 'thread ' parameter, we should + reach a "thread" token. */ + while (tok > arg && (*tok == ' ' || *tok == '\t')) + tok--; - end_tok = tok; + end_tok = tok; - while (tok > arg && (*tok != ' ' && *tok != '\t')) - tok--; + while (tok > arg && (*tok != ' ' && *tok != '\t')) + tok--; - /* Move the pointer forward to skip the whitespace and - calculate the length of the token. */ - tok++; - toklen = end_tok - tok; + /* Move the pointer forward to skip the whitespace and + calculate the length of the token. */ + tok++; + toklen = end_tok - tok; - if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0) - { - /* At this point we've found a "thread" token, which means - the user is trying to set a watchpoint that triggers - only in a specific thread. */ - char *endp; - - /* Extract the thread ID from the next token. */ - thread = strtol (id_tok_start, &endp, 0); - - /* Check if the user provided a valid numeric value for the - thread ID. */ - if (*endp != ' ' && *endp != '\t' && *endp != '\0') - error (_("Invalid thread ID specification %s."), id_tok_start); - - /* Check if the thread actually exists. */ - if (!valid_thread_id (thread)) - error (_("Unknown thread %d."), thread); - - /* Truncate the string and get rid of the thread - parameter before the parameter list is parsed by the - evaluate_expression() function. */ - *tok = '\0'; - } - } + if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0) + { + /* At this point we've found a "thread" token, which means + the user is trying to set a watchpoint that triggers + only in a specific thread. */ + char *endp; + + /* Extract the thread ID from the next token. */ + thread = strtol (id_tok_start, &endp, 0); + + /* Check if the user provided a valid numeric value for the + thread ID. */ + if (*endp != ' ' && *endp != '\t' && *endp != '\0') + error (_("Invalid thread ID specification %s."), + id_tok_start); + + /* Check if the thread actually exists. */ + if (!valid_thread_id (thread)) + error (_("Unknown thread %d."), thread); + + /* Truncate the string and get rid of the thread + parameter before the parameter list is parsed by the + evaluate_expression() function. */ + *tok = '\0'; + } + else if (toklen >= 1 && strncmp (tok, "mask", toklen) == 0) + { + /* We've found a "mask" token, which means the user wants to + create a hardware watchpoint that is going to have the mask + facility. */ + char *tokp = tok; + char *addr_p; + char *endp; + char *mask_addr; + int len_addr; + struct value *mask_value; + struct cleanup *clean_mask_addr; + + /* Does the target support masked watchpoints? */ + if (!TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_MASKED_WATCH)) + error (_("This target does not support the usage of masks \ +with hardware watchpoints.")); + + use_mask = 1; + + /* Skipping the token "mask", and possible spaces. */ + while (!isspace (*tokp) && *tokp != '\0') + tokp++; + while (isspace (*tokp)) + tokp++; + + if (*tokp == '\0') + error (_("You must supply the address that is going to be\n\ +used in the mask.")); + addr_p = tokp; + + while (!isspace (*addr_p) && *addr_p != '\0') + addr_p++; + + len_addr = addr_p - tokp; + + strtol (tokp, &endp, 16); + /* Check if the user provided a valid numeric value for the + mask address. */ + if (*endp != ' ' && *endp != '\t' && *endp != '\0') + error (_("Invalid mask address specification `%s'."), + tokp); + + if (len_addr <= 0) + error (_("The mask address is invalid.")); + + mask_addr = xstrndup (tokp, len_addr); + clean_mask_addr = make_cleanup (xfree, mask_addr); + + mask_value = parse_to_comma_and_eval (&mask_addr); + hw_wp_mask = value_as_address (mask_value); + + /* Truncate the string and get rid of the "mask
" + parameter before the parameter list is parsed by the + evaluate_expression() function. */ + *tok = '\0'; + do_cleanups (clean_mask_addr); + } + else if (toklen >= 1) + /* There is a token, but it is not recognized. We should + stop here. */ + break; + } + } while (toklen >= 1); /* Parse the rest of the arguments. */ innermost_block = NULL; @@ -7208,6 +7490,11 @@ watch_command_1 (char *arg, int accessflag, int from_tty) error (_("Expression cannot be implemented with read/access watchpoint.")); if (mem_cnt != 0) { + /* If we are going to use masks, then we may need more + slots in order to use the hardware watchpoint. */ + if (use_mask) + mem_cnt += target_hw_point_extra_slot_count (HW_POINT_MASKED_WATCH); + i = hw_watchpoint_used_count (bp_type, &other_type_used); target_resources_ok = target_can_use_hardware_watchpoint (bp_type, i + mem_cnt, @@ -7222,7 +7509,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty) /* Change the type of breakpoint to an ordinary watchpoint if a hardware watchpoint could not be set. */ if (!mem_cnt || target_resources_ok <= 0) - bp_type = bp_watchpoint; + { + if (use_mask) + /* No way to implement a watchpoint that uses mask without + hardware support. */ + error (_("Cannot use masks without hardware watchpoints.")); + else + bp_type = bp_watchpoint; + } frame = block_innermost_frame (exp_valid_block); @@ -7270,6 +7564,12 @@ watch_command_1 (char *arg, int accessflag, int from_tty) b->exp_string = savestring (exp_start, exp_end - exp_start); b->val = val; b->val_valid = 1; + if (use_mask) + { + b->loc->hw_wp_mask = hw_wp_mask; + b->hw_point_flag = HW_POINT_MASKED_WATCH; + } + if (cond_start) b->cond_string = savestring (cond_start, cond_end - cond_start); else @@ -7300,6 +7600,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty) that should be inserted. */ update_watchpoint (b, 1); + if (b->hw_point_flag == HW_POINT_COND_HW_ACCEL) + printf_filtered (_("This watchpoint will have its condition evaluation \ +assisted by hardware.\n")); + mention (b); update_global_location_list (1); } @@ -7351,21 +7655,25 @@ can_use_hardware_watchpoint (struct value *v) /* Ahh, memory we actually used! Check if we can cover it with hardware watchpoints. */ struct type *vtype = check_typedef (value_type (v)); + /* Is the value a struct or array? */ + int is_big_blob = TYPE_CODE (vtype) == TYPE_CODE_STRUCT + || TYPE_CODE (vtype) == TYPE_CODE_ARRAY; /* We only watch structs and arrays if user asked for it explicitly, never if they just happen to appear in a middle of some value chain. */ - if (v == head - || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT - && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) + if (v == head || !is_big_blob) { CORE_ADDR vaddr = value_address (v); int len = TYPE_LENGTH (value_type (v)); + int ret; - if (!target_region_ok_for_hw_watchpoint (vaddr, len)) + ret = TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len, + is_big_blob); + if (!ret) return 0; else - found_memory_cnt++; + found_memory_cnt += ret; } } } @@ -7416,6 +7724,230 @@ awatch_command (char *arg, int from_tty) { watch_command_1 (arg, hw_access, from_tty); } + +static void +watch_range_command_1 (char *arg, int accessflag, int from_tty) +{ + char *exp_string, *string_p; + struct gdbarch *gdbarch = get_current_arch (); + int wp_count, other_type_used, can_use_wp, ret, err, mem_cnt; + CORE_ADDR start_addr; + ULONGEST length; + struct breakpoint *b; + struct expression *exp; + struct symtab_and_line sal; + struct value *val; + struct cleanup *cleanups; + enum bptype type; + + /* Do we support ranged hardware watchpoints? */ + if (!TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_RANGED_WATCH)) + error (_("This target does not support ranged hardware watchpoints.")); + + parse_addr_range (&arg, &start_addr, &length); + + exp_string = string_p = xstrprintf ("{char[%s]} %s", + phex (length, sizeof (length)), + paddress (gdbarch, start_addr)); + exp = parse_exp_1 (&string_p, 0, 0); + fetch_watchpoint_value (exp, &val, NULL, NULL); + if (val != NULL) + release_value (val); + cleanups = make_cleanup (xfree, exp_string); + + mem_cnt = can_use_hardware_watchpoint (val); + if (mem_cnt < 0) + error (_("Provided range can't be watched.")); + + if (accessflag == hw_read) + type = bp_read_watchpoint; + else if (accessflag == hw_access) + type = bp_access_watchpoint; + else + type = bp_hardware_watchpoint; + + wp_count = hw_watchpoint_used_count (type, + &other_type_used); + can_use_wp = target_can_use_hardware_watchpoint (type, + wp_count + mem_cnt, + other_type_used); + if (can_use_wp < 0) + error (_("Not enough available hardware watchpoints.")); + + init_sal (&sal); /* initialize to zeroes */ + sal.pspace = current_program_space; + + /* Now set up the breakpoint. */ + b = set_raw_breakpoint (gdbarch, sal, accessflag); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->thread = -1; + b->disposition = disp_donttouch; + b->exp = exp; + b->exp_string = exp_string; + b->hw_point_flag = HW_POINT_RANGED_WATCH; + if (val) + { + b->val = val; + b->val_valid = 1; + } + b->watchpoint_frame = null_frame_id; + + mention (b); + update_global_location_list (1); + + discard_cleanups (cleanups); +} + +static void +watch_range_command (char *arg, int from_tty) +{ + watch_range_command_1 (arg, bp_hardware_watchpoint, from_tty); +} + +static void +awatch_range_command (char *arg, int from_tty) +{ + watch_range_command_1 (arg, bp_access_watchpoint, from_tty); +} + +static void +rwatch_range_command (char *arg, int from_tty) +{ + watch_range_command_1 (arg, bp_read_watchpoint, from_tty); +} + +static void +hbreak_range_command (char *arg, int from_tty) +{ + int bp_count, can_use_bp, ret, err; + int parse_line = 0; + CORE_ADDR start_addr; + ULONGEST length; + struct breakpoint *b; + struct symtab_and_line sal; + struct gdbarch *gdbarch = get_current_arch (); + + /* Do we support ranged hardware breakpoints? */ + if (!TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_RANGED_BREAK)) + error (_("This target does not support ranged hardware breakpoints.")); + + if (arg != NULL && *arg != '\0') + { + while (isspace (*arg)) + arg++; + + /* Is this an address (of the form `0x...'), or a line? */ + if (arg[0] == '0' && arg[1] == 'x') + parse_line = 0; + else + parse_line = 1; + } + + if (parse_line) + { + char *l1 = arg, *l2; + char *line1, *line2; + int size; + struct symtabs_and_lines sals1, sals2; + struct symtab_and_line sal1, sal2; + + l2 = arg; + while (*l2 != ',') + l2++; + + size = l2 - l1; + + *l2 = '\0'; + l2++; + while (isspace (*l2)) + l2++; + + line1 = l1; + line2 = l2; + + /* Parsing first line. */ + sals1 = decode_line_1 (&line1, 1, NULL, 0, NULL, NULL); + + if (sals1.nelts != 1) + error (_("Could not get information on specified line `%s'."), + line1); + sal1 = sals1.sals[0]; + xfree (sals1.sals); + + if (*line1) + error (_("Junk at end of arguments.")); + + resolve_sal_pc (&sal1); + + /* Parsing second line. */ + sals2 = decode_line_1 (&line2, 1, NULL, 0, NULL, NULL); + + if (sals2.nelts != 1) + error (_("Could not get information on specified line `%s'."), + line2); + sal2 = sals2.sals[0]; + xfree (sals2.sals); + + if (*line2) + error (_("Junk at end of arguments.")); + + resolve_sal_pc (&sal2); + + /* Verifying if the lines make sense. We need to check if + the first address in the range is smaller than the second, + and also compute the length. */ + if (sal1.pc > sal2.pc) + error (_("Invalid search space, end preceeds start.")); + + start_addr = sal1.pc; + length = sal2.pc - sal1.pc; + + if (length == 0) + { + /* This range is simple enough to be treated by + the `hbreak' command. */ + printf_unfiltered (_("Range is too small, using `hbreak' \ +instead.\n")); + hbreak_command (l1, 1); + return; + } + } + else + parse_addr_range (&arg, &start_addr, &length); + + bp_count = hw_breakpoint_used_count (); + /* For ranged hardware breakpoints, we may have to use 2 slots + instead of 1. */ + bp_count += target_hw_point_extra_slot_count (HW_POINT_RANGED_BREAK); + can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint, + bp_count + 1, + 0); + if (can_use_bp < 0) + error (_("Not enough available hardware breakpoints.")); + + sal = find_pc_line (start_addr, 0); + sal.pc = start_addr; + sal.section = find_pc_overlay (start_addr); + sal.explicit_pc = 1; + sal.pspace = current_program_space; + + /* Now set up the breakpoint. */ + b = set_raw_breakpoint (gdbarch, sal, bp_hardware_breakpoint); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->thread = -1; + b->disposition = disp_donttouch; + b->exp = NULL; + b->exp_string = NULL; + b->val = NULL; + b->val_valid = 0; + b->hw_point_flag = HW_POINT_RANGED_BREAK; + b->loc->ranged_hw_bp_length = length; + + mention (b); + update_global_location_list (1); +} /* Helper routines for the until_command routine in infcmd.c. Here @@ -8854,6 +9386,18 @@ update_breakpoint_locations (struct breakpoint *b, b->number, e.message); new_loc->enabled = 0; } + + if (b->type == bp_hardware_watchpoint + && new_loc->cond + && TARGET_CAN_USE_SPECIAL_HW_POINT_P (HW_POINT_COND_HW_ACCEL) + && TARGET_CAN_USE_WATCHPOINT_COND_ACCEL_P (new_loc)) + { + TARGET_GET_WATCHPOINT_COND_ACCEL_ADDR (new_loc, + &new_loc->cond_hw_addr); + new_loc->owner->hw_point_flag = HW_POINT_COND_HW_ACCEL; + } + else + new_loc->owner->hw_point_flag = HW_POINT_NONE; } if (b->source_file != NULL) @@ -10019,6 +10563,230 @@ tracepoint_save_command (char *args, int from_tty) return; } +/* This function checks if the expression associated + with the breakpoint `b' is of the form "*
". + It returns 1 if it is, 0 otherwise. */ +static int +exp_is_address_p (struct breakpoint *b) +{ + /* Check that the associated tree corresponds to that expression, + that is 5 elements, first a UNOP_IND, and then an OP_LONG. */ + if (b->exp->nelts != 5 + || b->exp->elts[0].opcode != UNOP_IND + || b->exp->elts[1].opcode != OP_LONG) + return 0; + return 1; +} + +/* This function checks if the expression associated + with the breakpoint `b' is of the form "". + It returns 1 if it is, 0 otherwise. */ +static int +exp_is_var_p (struct breakpoint *b) +{ + /* Check that the associated tree corresponds to that expression, + that is 4 elements, first a OP_VAR_VALUE. */ + if (b->exp->nelts != 4 + || b->exp->elts[0].opcode != OP_VAR_VALUE) + return 0; + return 1; +} + +/* This function checks if the condition associated + with the bp_location `b' is of the form "*
== LITERAL". + It returns 1 if it is, 0 otherwise. */ +static int +cond_is_address_equal_literal_p (struct bp_location *b) +{ + /* Check the watchpoint condition expression. It should be + of the form "*
EQUAL ", where EQUAL is the + equality binary operator. The associated tree should have + exactly 10 elements in it, all in a very specific order. */ + if (b->cond->nelts != 10 + || b->cond->elts[0].opcode != BINOP_EQUAL + || b->cond->elts[1].opcode != UNOP_IND + || b->cond->elts[2].opcode != OP_LONG + || b->cond->elts[6].opcode != OP_LONG) + return 0; + return 1; +} + +/* This function checks if the condition associated + with the bp_location `b' is of the form " == LITERAL". + It returns 1 if it is, 0 otherwise. */ +static int +cond_is_var_equal_literal_p (struct bp_location *b) +{ + /* Check the watchpoint condition expression. It should be + of the form " EQUAL ", where EQUAL is the + equality binary operator. The associated tree should have + exactly 9 elements in it, all in a very specific order. */ + if (b->cond->nelts != 9 + || b->cond->elts[0].opcode != BINOP_EQUAL + || b->cond->elts[1].opcode != OP_VAR_VALUE + || b->cond->elts[5].opcode != OP_LONG) + return 0; + return 1; +} + +/* This function returns the address of a variable VAR which + resides on the block B. */ +static CORE_ADDR +get_var_address (struct symbol *var, struct block *b) +{ + struct value *v = address_of_variable (var, b); + return value_as_address (v); +} + +/* This function is used to determine whether the condition associated + with bp_location B is of the form: + + watch *
if == + + If it is, then it sets DATA_VALUE to LITERAL and returns 1. + Otherwise, it returns 0. */ +int +default_watch_address_if_var_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value) +{ + CORE_ADDR exp_address, + cond_address; + struct breakpoint *bp = b->owner; + + if (!exp_is_address_p (bp) + || !cond_is_var_equal_literal_p (b)) + return 0; + + exp_address = bp->exp->elts[3].longconst; + cond_address = get_var_address (b->cond->elts[3].symbol, + b->cond->elts[2].block); + + /* Make sure that the two addresses are the same. */ + if (exp_address != cond_address) + { + printf_filtered ("Addresses in location and condition are different.\n"); + return 0; + } + + /* At this point, all verifications were positive, so we can use + hardware-assisted data-matching. Set the data value, and return + non-zero. */ + *data_value = b->cond->elts[7].longconst; + + return 1; +} + +/* This function is used to determine whether the condition associated + with bp_location B is of the form: + + watch if *
== + + If it is, then it sets DATA_VALUE to LITERAL and returns 1. + Otherwise, it returns 0. */ +int +default_watch_var_if_address_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value) +{ + CORE_ADDR exp_address, + cond_address; + struct breakpoint *bp = b->owner; + + if (!exp_is_var_p (bp) + || !cond_is_address_equal_literal_p (b)) + return 0; + + exp_address = get_var_address (bp->exp->elts[2].symbol, + bp->exp->elts[1].block); + cond_address = b->cond->elts[4].longconst; + + /* Make sure that the two addresses are the same. */ + if (exp_address != cond_address) + { + printf_filtered ("Addresses in location and condition are different.\n"); + return 0; + } + + /* At this point, all verifications were positive, so we can use + hardware-assisted data-matching. Set the data value, and return + non-zero. */ + *data_value = b->cond->elts[8].longconst; + + return 1; +} + +/* This function is used to determine whether the condition associated + with bp_location B is of the form: + + watch if == + + If it is, then it sets DATA_VALUE to LITERAL and returns 1. + Otherwise, it returns 0. */ +int +default_watch_var_if_var_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value) +{ + char *name_exp, *name_cond; + struct breakpoint *bp = b->owner; + + if (!exp_is_var_p (bp) + || !cond_is_var_equal_literal_p (b)) + return 0; + + name_exp = bp->exp->elts[2].symbol->ginfo.name; + name_cond = b->cond->elts[3].symbol->ginfo.name; + + /* Make sure that the two variables' names are the same. */ + if (strcmp (name_cond, name_exp) != 0) + { + printf_filtered ("Addresses in location and condition are different.\n"); + return 0; + } + + /* At this point, all verifications were positive, so we can use + hardware-assisted data-matching. Set the data value, and return + non-zero. */ + *data_value = b->cond->elts[7].longconst; + + return 1; +} + +/* This function is used to determine whether the condition associated + with bp_location B is of the form: + + watch *
if *
== + + If it is, then it sets DATA_VALUE to LITERAL and returns 1. + Otherwise, it returns 0. */ +int +default_watch_address_if_address_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value) +{ + CORE_ADDR exp_address, + cond_address; + struct breakpoint *bp = b->owner; + + if (!exp_is_address_p (bp) + || !cond_is_address_equal_literal_p (b)) + return 0; + + exp_address = bp->exp->elts[3].longconst; + cond_address = b->cond->elts[4].longconst; + + /* Make sure that the two addresses are the same. */ + if (exp_address != cond_address) + { + printf_filtered ("Addresses in location and condition are different.\n"); + return 0; + } + + /* At this point, all verifications were positive, so we can use + hardware-assisted data-matching. Set the data value, and return + non-zero. */ + *data_value = b->cond->elts[8].longconst; + + return 1; +} + /* Create a vector of all tracepoints. */ VEC(breakpoint_p) * @@ -10568,7 +11336,51 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."), &show_always_inserted_mode, &breakpoint_set_cmdlist, &breakpoint_show_cmdlist); - + + c = add_com ("watch-range", class_breakpoint, watch_range_command, _("\ +Set a WRITE hardware watchpoint for an address range.\n\ +The address range should be specified in one of the following formats:\n\ +\n\ + start-address, end-address\n\ + start-address, +length\n\ +\n\ +The watchpoint will stop execution of your program whenever the inferior\n\ +writes to any address within that range.")); + set_cmd_completer (c, expression_completer); + + c = add_com ("awatch-range", class_breakpoint, awatch_range_command, _("\ +Set an ACCESS hardware watchpoint for an address range.\n\ +The address range should be specified in one of the following formats:\n\ +\n\ + start-address, end-address\n\ + start-address, +length\n\ +\n\ +The watchpoint will stop execution of your program whenever the inferior\n\ +accesses (reads from or writes to) any address within that range.")); + set_cmd_completer (c, expression_completer); + + c = add_com ("rwatch-range", class_breakpoint, rwatch_range_command, _("\ +Set a READ hardware watchpoint for an address range.\n\ +The address range should be specified in one of the following formats:\n\ +\n\ + start-address, end-address\n\ + start-address, +length\n\ +\n\ +The watchpoint will stop execution of your program whenever the inferior\n\ +reads any address within that range.")); + set_cmd_completer (c, expression_completer); + + add_com ("hbreak-range", class_breakpoint, hbreak_range_command, _("\ +Set a hardware assisted breakpoint for an address range.\n\ +The address range should be specified in one of the following formats:\n\ +\n\ + start-address, end-address\n\ + start-address, +length\n\ + start-line, end-line\n\ +\n\ +The breakpoint will stop execution of your program whenever the inferior\n\ +executes any address within that range.")); + automatic_hardware_breakpoints = 1; observer_attach_about_to_proceed (breakpoint_about_to_proceed); diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 5ebd36c..4e49473 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -186,6 +186,11 @@ struct bp_target_info is used to determine the type of breakpoint to insert. */ CORE_ADDR placed_address; + /* If this is a ranged hardware breakpoint, then we can use this + field in order to store the length of the range that will be + watched for execution. */ + ULONGEST length; + /* If the breakpoint lives in memory and reading that memory would give back the breakpoint, instead of the original contents, then the original contents are cached here. Only SHADOW_LEN bytes of @@ -246,6 +251,25 @@ struct bp_location different locations. */ struct expression *cond; + /* Flag to indicate if the condition is going to be accelerated + by hardware. If its value is non-zero, then GDB checks the + condition using hardware acceleration; otherwise it uses the + regular software-based checking. */ + int cond_hw_accel : 1; + + /* If the condition can be hardware-accelerated, then we must + get the condition's variable address so that GDB can + properly set the evaluation via hardware. */ + CORE_ADDR cond_hw_addr; + + /* If we are inserting a ranged hardware breakpoint, then we must + set its length here. */ + ULONGEST ranged_hw_bp_length; + + /* The mask address for this hardware watchpoint. It is valid only + if `hw_wp_use_mask' is 1. */ + CORE_ADDR hw_wp_mask; + /* This location's address is in an unloaded solib, and so this location should not be inserted. It will be automatically enabled when that solib is loaded. */ @@ -373,6 +397,16 @@ DEF_VEC_I(int); typedef struct bp_location *bp_location_p; DEF_VEC_P(bp_location_p); +/* Special flags for hardware breakpoints/watchpoints. */ +enum hw_point_flag { + HW_POINT_NONE = 0, + HW_POINT_RANGED_WATCH, /* Hardware ranged watchpoint. */ + HW_POINT_RANGED_BREAK, /* Hardware ranged breakpoint. */ + HW_POINT_MASKED_WATCH, /* Hardware masked watchpoint. */ + HW_POINT_COND_HW_ACCEL, /* Hardware watchpoint with condition + hardware-accelerated. */ +}; + /* Note that the ->silent field is not currently used by any commands (though the code is in there if it was to be, and set_raw_breakpoint does set it to 0). I implemented it because I thought it would be @@ -512,6 +546,9 @@ struct breakpoint /* Chain of action lines to execute when this tracepoint is hit. */ struct action_line *actions; + + /* Special flags. */ + enum hw_point_flag hw_point_flag; }; typedef struct breakpoint *breakpoint_p; @@ -992,4 +1029,20 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p, is newly allocated; the caller should free when done with it. */ extern VEC(breakpoint_p) *all_tracepoints (void); +/* Return greater than zero if the condition associated with + the watchpoint `b' can be treated by the hardware; zero otherwise. + + Also stores the data value in `data_value'. */ +extern int default_watch_address_if_address_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value); + +extern int default_watch_var_if_var_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value); + +extern int default_watch_address_if_var_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value); + +extern int default_watch_var_if_address_equal_literal_p (struct bp_location *b, + CORE_ADDR *data_value); + #endif /* !defined (BREAKPOINT_H) */ diff --git a/gdb/findcmd.c b/gdb/findcmd.c index 1d28914..85f229c 100644 --- a/gdb/findcmd.c +++ b/gdb/findcmd.c @@ -45,6 +45,75 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p) } } +/* Reads an address range, in one of the following formats: + + start-address, end-address + start-address, +length + + ARGS will be set to the first character after the end-address or length, + or if that character is a comma, the character following it. If a parser + error occurs, an exception is thrown and none of the arguments is + touched. */ + +void +parse_addr_range (char **args, CORE_ADDR *start_addrp, + ULONGEST *search_space_lenp) +{ + char *s = *args; + CORE_ADDR start_addr; + ULONGEST search_space_len; + struct value *v; + + v = parse_to_comma_and_eval (&s); + start_addr = value_as_address (v); + + if (*s == ',') + ++s; + while (isspace (*s)) + ++s; + + if (*s == '+') + { + LONGEST len; + ++s; + v = parse_to_comma_and_eval (&s); + len = value_as_long (v); + + if (len == 0) + error (_("Empty search range.")); + else if (len < 0) + error (_("Invalid length.")); + /* Watch for overflows. */ + else if (len > CORE_ADDR_MAX + || (start_addr + len - 1) < start_addr) + error (_("Search space too large.")); + + search_space_len = len; + } + else + { + CORE_ADDR end_addr; + + v = parse_to_comma_and_eval (&s); + end_addr = value_as_address (v); + if (start_addr > end_addr) + error (_("Invalid search space, end preceeds start.")); + search_space_len = end_addr - start_addr + 1; + /* We don't support searching all of memory + (i.e. start=0, end = 0xff..ff). + Bail to avoid overflows later on. */ + if (search_space_len == 0) + error (_("Overflow in address range computation, choose smaller range.")); + } + + if (*s == ',') + ++s; + + *args = s; + *start_addrp = start_addr; + *search_space_lenp = search_space_len; +} + /* Subroutine of find_command to simplify it. Parse the arguments of the "find" command. */ @@ -114,51 +183,7 @@ parse_find_args (char *args, ULONGEST *max_countp, } /* Get the search range. */ - - v = parse_to_comma_and_eval (&s); - start_addr = value_as_address (v); - - if (*s == ',') - ++s; - while (isspace (*s)) - ++s; - - if (*s == '+') - { - LONGEST len; - ++s; - v = parse_to_comma_and_eval (&s); - len = value_as_long (v); - if (len == 0) - { - printf_filtered (_("Empty search range.\n")); - return; - } - if (len < 0) - error (_("Invalid length.")); - /* Watch for overflows. */ - if (len > CORE_ADDR_MAX - || (start_addr + len - 1) < start_addr) - error (_("Search space too large.")); - search_space_len = len; - } - else - { - CORE_ADDR end_addr; - v = parse_to_comma_and_eval (&s); - end_addr = value_as_address (v); - if (start_addr > end_addr) - error (_("Invalid search space, end preceeds start.")); - search_space_len = end_addr - start_addr + 1; - /* We don't support searching all of memory - (i.e. start=0, end = 0xff..ff). - Bail to avoid overflows later on. */ - if (search_space_len == 0) - error (_("Overflow in address range computation, choose smaller range.")); - } - - if (*s == ',') - ++s; + parse_addr_range (&s, &start_addr, &search_space_len); /* Fetch the search string. */ diff --git a/gdb/testsuite/gdb.base/watchpoint.c b/gdb/testsuite/gdb.base/watchpoint.c index bba97fa..1e95400 100644 --- a/gdb/testsuite/gdb.base/watchpoint.c +++ b/gdb/testsuite/gdb.base/watchpoint.c @@ -30,7 +30,7 @@ int ival2 = -1; int ival3 = -1; int ival4 = -1; int ival5 = -1; -char buf[10]; +char buf[30]; struct foo { int val; @@ -95,6 +95,7 @@ func3 () x = 1; /* second x assignment */ y = 1; y = 2; + buf[26] = 3; } int diff --git a/gdb/testsuite/gdb.base/watchpoint.exp b/gdb/testsuite/gdb.base/watchpoint.exp index 9fee73b..ee55e76 100644 --- a/gdb/testsuite/gdb.base/watchpoint.exp +++ b/gdb/testsuite/gdb.base/watchpoint.exp @@ -678,6 +678,24 @@ proc test_inaccessible_watchpoint {} { } } +proc test_watchpoint_in_big_blob {} { + global gdb_prompt + + gdb_test "watch buf" ".*atchpoint \[0-9\]+: buf" + send_gdb "cont\n" + gdb_expect { + -re "Continuing.*\[Ww\]atchpoint.*buf.*Old value = .*$gdb_prompt $" { + pass "watchpoint on buf hit" + } + -re "Continuing.*$gdb_prompt $" { + fail "watchpoint on buf hit" + } + -re ".*$gdb_prompt $" { fail "watchpoint on buf hit" ; return } + timeout { fail "watchpoint on buf hit (timeout)" ; return } + eof { fail "watchpoint on buf hit (eof)" ; return } + } +} + # Start with a fresh gdb. gdb_exit @@ -842,6 +860,8 @@ if [initialize] then { } test_watchpoint_and_breakpoint + + test_watchpoint_in_big_blob } # Restore old timeout diff --git a/gdb/ui-out.c b/gdb/ui-out.c index 19a4644..86e7c82 100644 --- a/gdb/ui-out.c +++ b/gdb/ui-out.c @@ -486,6 +486,45 @@ ui_out_field_fmt_int (struct ui_out *uiout, } void +ui_out_field_range_core_addr (struct ui_out *uiout, + const char *fldname, + struct gdbarch *gdbarch, + CORE_ADDR address_start, + CORE_ADDR address_end) +{ + char addstr[40]; + int addr_bit = gdbarch_addr_bit (gdbarch); + + if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT)) + { + address_start &= ((CORE_ADDR) 1 << addr_bit) - 1; + address_end &= ((CORE_ADDR) 1 << addr_bit) - 1; + } + + /* FIXME: cagney/2002-05-03: Need local_address_string() function + that returns the language localized string formatted to a width + based on gdbarch_addr_bit. */ + if (addr_bit <= 32) + { + strcpy (addstr, "["); + strcat (addstr, hex_string_custom (address_start, 8)); + strcat (addstr, ","); + strcat (addstr, hex_string_custom (address_end, 8)); + strcat (addstr, "]"); + } + else + { + strcpy (addstr, "["); + strcat (addstr, hex_string_custom (address_start, 16)); + strcat (addstr, ","); + strcat (addstr, hex_string_custom (address_end, 16)); + strcat (addstr, "]"); + } + + ui_out_field_string (uiout, fldname, addstr); +} + +void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname, struct gdbarch *gdbarch, diff --git a/gdb/ui-out.h b/gdb/ui-out.h index 4f3b7a4..43336c4 100644 --- a/gdb/ui-out.h +++ b/gdb/ui-out.h @@ -114,6 +114,11 @@ extern void ui_out_field_fmt_int (struct ui_out *uiout, int width, enum ui_align align, const char *fldname, int value); +extern void ui_out_field_range_core_addr (struct ui_out *uiout, const char *fldname, + struct gdbarch *gdbarch, + CORE_ADDR address_start, + CORE_ADDR address_end); + extern void ui_out_field_core_addr (struct ui_out *uiout, const char *fldname, struct gdbarch *gdbarch, CORE_ADDR address); diff --git a/gdb/value.h b/gdb/value.h index 993f05b..d9cf12d 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -521,6 +521,9 @@ extern CORE_ADDR parse_and_eval_address_1 (char **expptr); extern LONGEST parse_and_eval_long (char *exp); +void parse_addr_range (char **args, CORE_ADDR *start_addrp, + ULONGEST *search_space_lenp); + extern void unop_promote (const struct language_defn *language, struct gdbarch *gdbarch, struct value **arg1);