Index: gdb/gdb/breakpoint.c =================================================================== --- gdb.orig/gdb/breakpoint.c 2009-12-23 17:07:34.000000000 -0200 +++ gdb/gdb/breakpoint.c 2009-12-23 17:14:52.000000000 -0200 @@ -1059,6 +1059,8 @@ update_watchpoint (struct breakpoint *b, 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,6 +1068,18 @@ update_watchpoint (struct breakpoint *b, if (!watchpoint_in_thread_scope (b)) return; + /* 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 array and update_global_locations will eventually delete them and remove breakpoints if needed. */ @@ -1262,6 +1276,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)); @@ -1492,7 +1513,12 @@ Note: automatically using hardware break watchpoints. It's not clear that it's necessary... */ && bpt->owner->disposition != disp_del_at_next_stop) { - if (bpt->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL) + 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, @@ -2126,7 +2152,11 @@ remove_breakpoint_1 (struct bp_location struct value *n; b->inserted = (is == mark_inserted); - if (b->owner->hw_point_flag == HW_POINT_COND_HW_ACCEL) + 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); @@ -2918,13 +2948,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; @@ -2936,10 +2972,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; @@ -2953,24 +2997,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 = "); + } + } + 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); } - watchpoint_value_print (b->val, stb->stream); - ui_out_field_stream (uiout, "new", stb); + ui_out_text (uiout, "\n"); result = PRINT_UNKNOWN; break; @@ -3179,15 +3238,30 @@ watchpoints_triggered (struct target_wai 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; @@ -3290,6 +3364,11 @@ 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 know 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. */ @@ -5821,10 +5900,15 @@ hw_watchpoint_used_count (enum bptype ty 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; } } @@ -6041,6 +6125,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); @@ -6049,6 +6137,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); @@ -6057,6 +6149,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); @@ -7121,74 +7217,143 @@ watch_command_1 (char *arg, int accessfl 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. */ + + /* 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--; + + /* 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--; + + end_tok = 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; - /* 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; - - /* 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; - - /* 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; - - 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; - - 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; @@ -7240,6 +7405,11 @@ watch_command_1 (char *arg, int accessfl 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, @@ -7254,7 +7424,14 @@ watch_command_1 (char *arg, int accessfl /* 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); @@ -7302,6 +7479,12 @@ watch_command_1 (char *arg, int accessfl 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 @@ -7387,21 +7570,25 @@ can_use_hardware_watchpoint (struct valu /* 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; } } } @@ -7452,6 +7639,101 @@ 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", pulongest (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. Either the target watchpoint resources\n\ +don't support it, or hardware watchpoints are disabled in GDB\n\ +(see \"set can-use-hw-watchpoints\").")); + + 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 hardware resources for specified watchpoint.")); + + 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); +} + /* Helper routines for the until_command routine in infcmd.c. Here @@ -10852,7 +11134,40 @@ inferior in all-stop mode, gdb behaves a &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); + automatic_hardware_breakpoints = 1; observer_attach_about_to_proceed (breakpoint_about_to_proceed); Index: gdb/gdb/breakpoint.h =================================================================== --- gdb.orig/gdb/breakpoint.h 2009-12-23 17:04:23.000000000 -0200 +++ gdb/gdb/breakpoint.h 2009-12-23 17:14:52.000000000 -0200 @@ -262,6 +262,14 @@ struct bp_location 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. */ @@ -392,6 +400,8 @@ 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_MASKED_WATCH, /* Hardware masked watchpoint. */ HW_POINT_COND_HW_ACCEL, /* Hardware watchpoint with condition hardware-accelerated. */ }; Index: gdb/gdb/findcmd.c =================================================================== --- gdb.orig/gdb/findcmd.c 2009-12-23 17:04:23.000000000 -0200 +++ gdb/gdb/findcmd.c 2009-12-23 17:09:38.000000000 -0200 @@ -45,6 +45,75 @@ put_bits (bfd_uint64_t data, char *buf, } } +/* 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 *m } /* 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. */ Index: gdb/gdb/i386-nat.c =================================================================== --- gdb.orig/gdb/i386-nat.c 2009-12-23 17:04:23.000000000 -0200 +++ gdb/gdb/i386-nat.c 2009-12-23 17:09:38.000000000 -0200 @@ -530,8 +530,8 @@ i386_remove_watchpoint (CORE_ADDR addr, /* Return non-zero if we can watch a memory region that starts at address ADDR and whose length is LEN bytes. */ -static int -i386_region_ok_for_watchpoint (CORE_ADDR addr, int len) +int +i386_region_ok_for_watchpoint (CORE_ADDR addr, int len, int is_big_blob) { int nregs; Index: gdb/gdb/ppc-linux-nat.c =================================================================== --- gdb.orig/gdb/ppc-linux-nat.c 2009-12-23 17:04:23.000000000 -0200 +++ gdb/gdb/ppc-linux-nat.c 2009-12-23 17:14:52.000000000 -0200 @@ -1461,6 +1461,10 @@ ppc_linux_can_use_special_hw_point_p (en switch (flag) { + case HW_POINT_RANGED_WATCH: + return features & PPC_DEBUG_FEATURE_DATA_BP_RANGE; + case HW_POINT_MASKED_WATCH: + return features & PPC_DEBUG_FEATURE_DATA_BP_MASK; case HW_POINT_COND_HW_ACCEL: return booke_debug_info.num_condition_regs > 0; /* We also accept non-special *points. */ @@ -1472,7 +1476,7 @@ ppc_linux_can_use_special_hw_point_p (en } static int -ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob) { /* Handle sub-8-byte quantities. */ if (len <= 0) @@ -1483,9 +1487,14 @@ ppc_linux_region_ok_for_hw_watchpoint (C to determine the hardcoded watchable region for watchpoints. */ if (have_ptrace_new_debug_booke) { - if (booke_debug_info.data_bp_alignment - && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1)) - + booke_debug_info.data_bp_alignment)) + /* DAC-based processors (i.e., embedded processors), like the PowerPC 440 + have ranged watchpoints and can watch arbitrary lengths. This takes + two hardware watchpoints though. */ + if (ppc_linux_can_use_special_hw_point_p (HW_POINT_RANGED_WATCH)) + return is_big_blob ? 2 : 1; + else if (booke_debug_info.data_bp_alignment + && (addr + len > (addr & ~(booke_debug_info.data_bp_alignment - 1)) + + booke_debug_info.data_bp_alignment)) return 0; } /* addr+len must fall in the 8 byte watchable region for DABR-based @@ -1677,6 +1686,65 @@ ppc_linux_remove_hw_breakpoint (struct g t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE; static int +ppc_linux_insert_mask_watchpoint (CORE_ADDR addr, int len, int rw, + CORE_ADDR mask) +{ + struct ppc_hw_breakpoint p; + uint32_t trigger; + unsigned long a = (unsigned long) addr, + m = (unsigned long) mask; + struct lwp_info *lp; + ptid_t ptid; + + if (!have_ptrace_new_debug_booke) + return -1; + + HW_WATCH_RW_TRIGGER (trigger, rw); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = trigger; + p.addr_mode = PPC_BREAKPOINT_MODE_MASK; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) a; + p.addr2 = (uint64_t) m; + p.condition_value = 0; + + ALL_LWPS (lp, ptid) + booke_insert_point (&p, TIDGET (ptid)); + + return 0; +} + +static int +ppc_linux_remove_mask_watchpoint (CORE_ADDR addr, int len, int rw, + CORE_ADDR mask) +{ + struct ppc_hw_breakpoint p; + uint32_t trigger; + unsigned long a = (unsigned long) addr, + m = (unsigned long) mask; + struct lwp_info *lp; + ptid_t ptid; + + if (!have_ptrace_new_debug_booke) + return -1; + + HW_WATCH_RW_TRIGGER (trigger, rw); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = trigger; + p.addr_mode = PPC_BREAKPOINT_MODE_MASK; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) a; + p.addr2 = (uint64_t) m; + p.condition_value = 0; + + ALL_LWPS (lp, ptid) + booke_remove_point (&p, TIDGET (ptid)); + + return 0; +} +static int ppc_linux_insert_cond_accel_watchpoint (CORE_ADDR addr, int len, int rw, CORE_ADDR cond) { @@ -1755,12 +1823,12 @@ ppc_linux_insert_watchpoint (CORE_ADDR a if (have_ptrace_new_debug_booke) { + struct ppc_hw_breakpoint p; + uint32_t trigger; + if (len <= 4) ALL_LWPS (lp, ptid) { - struct ppc_hw_breakpoint p; - uint32_t trigger; - HW_WATCH_RW_TRIGGER (trigger, rw); p.version = PPC_DEBUG_CURRENT_VERSION; @@ -1773,6 +1841,21 @@ ppc_linux_insert_watchpoint (CORE_ADDR a booke_insert_point (&p, TIDGET (ptid)); } + else + ALL_LWPS (lp, ptid) + { + HW_WATCH_RW_TRIGGER (trigger, rw); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = trigger; + p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) addr; + p.addr2 = (uint64_t) addr + len; + p.condition_value = 0; + + booke_insert_point (&p, TIDGET (ptid)); + } ret = 0; } @@ -1834,12 +1917,12 @@ ppc_linux_remove_watchpoint (CORE_ADDR a if (have_ptrace_new_debug_booke) { + struct ppc_hw_breakpoint p; + uint32_t trigger; + if (len <= 4) ALL_LWPS (lp, ptid) { - struct ppc_hw_breakpoint p; - uint32_t trigger; - HW_WATCH_RW_TRIGGER (trigger, rw); p.version = PPC_DEBUG_CURRENT_VERSION; @@ -1852,6 +1935,21 @@ ppc_linux_remove_watchpoint (CORE_ADDR a booke_remove_point (&p, TIDGET (ptid)); } + else + ALL_LWPS (lp, ptid) + { + HW_WATCH_RW_TRIGGER (trigger, rw); + + p.version = PPC_DEBUG_CURRENT_VERSION; + p.trigger_type = trigger; + p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) addr; + p.addr2 = (uint64_t) addr + len; + p.condition_value = 0; + + booke_remove_point (&p, TIDGET (ptid)); + } ret = 0; } @@ -2008,6 +2106,30 @@ ppc_linux_can_use_watchpoint_cond_accel_ return ppc_linux_get_watchpoint_cond_accel_addr (b, &tmp_value); } +static int +ppc_linux_hw_point_extra_slot_count (enum hw_point_flag flag) +{ + /* If this *point is a: + + - Masked hardware watchpoint, + - Ranged hardware watchpoint + + then it uses 1 extra slot. */ + switch (flag) + { + case HW_POINT_MASKED_WATCH: + case HW_POINT_RANGED_WATCH: + return 1; + default: + return 0; + } + + /* Otherwise, it is a normal *point and does not use + extra slots. */ + return 0; +} + + static void ppc_linux_store_inferior_registers (struct target_ops *ops, struct regcache *regcache, int regno) @@ -2240,11 +2362,14 @@ _initialize_ppc_linux_nat (void) ppc_linux_can_use_watchpoint_cond_accel_p; t->to_insert_watchpoint = ppc_linux_insert_watchpoint; t->to_remove_watchpoint = ppc_linux_remove_watchpoint; + t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint; + t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint; t->to_insert_cond_accel_watchpoint = ppc_linux_insert_cond_accel_watchpoint; t->to_remove_cond_accel_watchpoint = ppc_linux_remove_cond_accel_watchpoint; t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint; t->to_stopped_data_address = ppc_linux_stopped_data_address; t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range; + t->to_hw_point_extra_slot_count = ppc_linux_hw_point_extra_slot_count; t->to_read_description = ppc_linux_read_description; t->to_auxv_parse = ppc_linux_auxv_parse; Index: gdb/gdb/target.c =================================================================== --- gdb.orig/gdb/target.c 2009-12-23 17:04:23.000000000 -0200 +++ gdb/gdb/target.c 2009-12-23 17:09:38.000000000 -0200 @@ -53,7 +53,7 @@ static void default_terminal_info (char static int default_watchpoint_addr_within_range (struct target_ops *, CORE_ADDR, CORE_ADDR, int); -static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int); +static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int, int); static int nosymbol (char *, CORE_ADDR *); @@ -131,7 +131,7 @@ static int debug_to_stopped_data_address static int debug_to_watchpoint_addr_within_range (struct target_ops *, CORE_ADDR, CORE_ADDR, int); -static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int); +static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int, int); static void debug_to_terminal_init (void); @@ -626,6 +626,8 @@ update_current_target (void) INHERIT (to_remove_hw_breakpoint, t); INHERIT (to_insert_watchpoint, t); INHERIT (to_remove_watchpoint, t); + INHERIT (to_insert_mask_watchpoint, t); + INHERIT (to_remove_mask_watchpoint, t); INHERIT (to_insert_cond_accel_watchpoint, t); INHERIT (to_remove_cond_accel_watchpoint, t); INHERIT (to_get_watchpoint_cond_accel_addr, t); @@ -635,6 +637,7 @@ update_current_target (void) INHERIT (to_stopped_by_watchpoint, t); INHERIT (to_watchpoint_addr_within_range, t); INHERIT (to_region_ok_for_hw_watchpoint, t); + INHERIT (to_hw_point_extra_slot_count, t); INHERIT (to_terminal_init, t); INHERIT (to_terminal_inferior, t); INHERIT (to_terminal_ours_for_output, t); @@ -748,6 +751,12 @@ update_current_target (void) de_fault (to_remove_watchpoint, (int (*) (CORE_ADDR, int, int)) return_minus_one); + de_fault (to_insert_mask_watchpoint, + (int (*) (CORE_ADDR, int, int, CORE_ADDR)) + return_minus_one); + de_fault (to_remove_mask_watchpoint, + (int (*) (CORE_ADDR, int, int, CORE_ADDR)) + return_minus_one); de_fault (to_insert_cond_accel_watchpoint, (int (*) (CORE_ADDR, int, int, CORE_ADDR)) return_minus_one); @@ -764,6 +773,9 @@ update_current_target (void) default_watchpoint_addr_within_range); de_fault (to_region_ok_for_hw_watchpoint, default_region_ok_for_hw_watchpoint); + de_fault (to_hw_point_extra_slot_count, + (int (*) (enum hw_point_flag)) + return_zero); de_fault (to_get_watchpoint_cond_accel_addr, (int (*) (struct bp_location *, CORE_ADDR *)) return_zero); @@ -2618,7 +2630,7 @@ Can't determine the current address spac } static int -default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob) { return (len <= gdbarch_ptr_bit (target_gdbarch) / TARGET_CHAR_BIT); } @@ -3148,11 +3160,11 @@ debug_to_can_use_hw_breakpoint (int type } static int -debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob) { CORE_ADDR retval; - retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len); + retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len, is_big_blob); fprintf_unfiltered (gdb_stdlog, "target_region_ok_for_hw_watchpoint (%ld, %ld) = 0x%lx\n", Index: gdb/gdb/target.h =================================================================== --- gdb.orig/gdb/target.h 2009-12-23 17:06:07.000000000 -0200 +++ gdb/gdb/target.h 2009-12-23 17:09:38.000000000 -0200 @@ -411,6 +411,8 @@ struct target_ops int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *); int (*to_remove_watchpoint) (CORE_ADDR, int, int); int (*to_insert_watchpoint) (CORE_ADDR, int, int); + int (*to_insert_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR); + int (*to_remove_mask_watchpoint) (CORE_ADDR, int, int, CORE_ADDR); int (*to_insert_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR); int (*to_remove_cond_accel_watchpoint) (CORE_ADDR, int, int, CORE_ADDR); int (*to_stopped_by_watchpoint) (void); @@ -421,7 +423,8 @@ struct target_ops CORE_ADDR, CORE_ADDR, int); int (*to_get_watchpoint_cond_accel_addr) (struct bp_location *, CORE_ADDR *); - int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int); + int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int, int); + int (*to_hw_point_extra_slot_count) (enum hw_point_flag); void (*to_terminal_init) (void); void (*to_terminal_inferior) (void); void (*to_terminal_ours_for_output) (void); @@ -1196,8 +1199,8 @@ extern char *normal_pid_to_str (ptid_t p (*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE); #ifndef target_region_ok_for_hw_watchpoint -#define target_region_ok_for_hw_watchpoint(addr, len) \ - (*current_target.to_region_ok_for_hw_watchpoint) (addr, len) +#define target_region_ok_for_hw_watchpoint(addr, len, is_big_blob) \ + (*current_target.to_region_ok_for_hw_watchpoint) (addr, len, is_big_blob) #endif /* Returns non-zero if the target supports the special type of hardware @@ -1229,6 +1232,17 @@ extern char *normal_pid_to_str (ptid_t p #define target_remove_watchpoint(addr, len, type) \ (*current_target.to_remove_watchpoint) (addr, len, type) +/* Hardware watchpoints with a mask associated. */ +#ifndef target_insert_mask_watchpoint +#define target_insert_mask_watchpoint(addr, len, type, mask) \ + (*current_target.to_insert_mask_watchpoint) (addr, len, type, mask) +#endif + +#ifndef target_remove_mask_watchpoint +#define target_remove_mask_watchpoint(addr, len, type, mask) \ + (*current_target.to_remove_mask_watchpoint) (addr, len, type, mask) +#endif + /* Hardware watchpoint with a condition associated (to be hardware-accelerated). */ #ifndef target_insert_cond_accel_watchpoint @@ -1256,6 +1270,11 @@ extern char *normal_pid_to_str (ptid_t p #define target_watchpoint_addr_within_range(target, addr, start, length) \ (*target.to_watchpoint_addr_within_range) (target, addr, start, length) +#ifndef target_hw_point_extra_slot_count +#define target_hw_point_extra_slot_count(flag) \ + (*current_target.to_hw_point_extra_slot_count) (flag) +#endif + /* Target can execute in reverse? */ #define target_can_execute_reverse \ (current_target.to_can_execute_reverse ? \ Index: gdb/gdb/value.h =================================================================== --- gdb.orig/gdb/value.h 2009-12-23 17:04:23.000000000 -0200 +++ gdb/gdb/value.h 2009-12-23 17:09:38.000000000 -0200 @@ -521,6 +521,9 @@ extern CORE_ADDR parse_and_eval_address_ 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); Index: gdb/gdb/spu-multiarch.c =================================================================== --- gdb.orig/gdb/spu-multiarch.c 2009-12-23 17:04:23.000000000 -0200 +++ gdb/gdb/spu-multiarch.c 2009-12-23 17:09:38.000000000 -0200 @@ -121,7 +121,7 @@ spu_thread_architecture (struct target_o /* Override the to_region_ok_for_hw_watchpoint routine. */ static int -spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) +spu_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len, int is_big_blob) { struct target_ops *ops_beneath = find_target_beneath (&spu_ops); while (ops_beneath && !ops_beneath->to_region_ok_for_hw_watchpoint) @@ -132,7 +132,8 @@ spu_region_ok_for_hw_watchpoint (CORE_AD return 0; if (ops_beneath) - return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len); + return ops_beneath->to_region_ok_for_hw_watchpoint (addr, len, + is_big_blob); return 0; }