From e09342b536073e978e30460267e144063843cd17 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Tue, 11 Jan 2011 19:23:03 +0000 Subject: 2011-01-11 Sergio Durigan Junior Thiago Jung Bauermann Implement support for PowerPC BookE ranged watchpoints. gdb/ * breakpoint.h (struct breakpoint_ops) : New method. Initialize to NULL in all existing breakpoint_ops instances. (struct breakpoint) : New field. (target_exact_watchpoints): Declare external global. * breakpoint.c (target_exact_watchpoints): New global flag. (update_watchpoint): Set b->type to bp_hardware_watchpoint and b->enable_state to bp_enabled before calling hw_watchpoint_used_count. (hw_watchpoint_used_count): Iterate over all bp_locations in a watchpoint. Call breakpoint's breakpoint_ops.resources_needed if available. (insert_watchpoint, remove_watchpoint): Use fixed length of 1 byte if the watchpoint is exact. (resources_needed_watchpoint): New function. (watchpoint_breakpoint_ops): Add resources_needed_watchpoint. (watch_command_1): Set b->exact if the user asked for an exact watchpoint and one can be set. (can_use_hardware_watchpoint): Add exact_watchpoints argument. Pass fixed length of 1 to target_region_ok_for_hw_watchpoint if the user asks for an exact watchpoint and one can be set. Return number of needed debug registers to watch the expression. * gdbtypes.c (is_scalar_type): New function, based on valprint.c:scalar_type_p. (is_scalar_type_recursive): New function. * gdbtypes.h (is_scalar_type_recursive): Declare. * ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint): Always handle regions when ranged watchpoints are available. (create_watchpoint_request): New function. (ppc_linux_insert_watchpoint, ppc_linux_remove_watchpoint): Use create_watchpoint_request. * rs6000-tdep.c (show_powerpc_exact_watchpoints): New function. (_initialize_rs6000_tdep): Add `exact-watchpoints' boolean to the `set powerpc' and `show powerpc' commands. * target.h (struct target_ops) : Mention documentation comment in the target macro. (target_region_ok_for_hw_watchpoint): Document return value. gdb/doc/ * gdb.texinfo (PowerPC Embedded): Document ranged watchpoints and the "set powerpc exact-watchpoints" flag. --- gdb/ChangeLog | 42 ++++++++++++++++ gdb/ada-lang.c | 3 ++ gdb/breakpoint.c | 135 +++++++++++++++++++++++++++++++++++++--------------- gdb/breakpoint.h | 17 ++++++- gdb/doc/ChangeLog | 9 +++- gdb/doc/gdb.texinfo | 28 +++++++++-- gdb/gdbtypes.c | 62 ++++++++++++++++++++++++ gdb/gdbtypes.h | 2 + gdb/ppc-linux-nat.c | 96 +++++++++++++++++++++++-------------- gdb/rs6000-tdep.c | 23 +++++++++ gdb/target.h | 7 +++ 11 files changed, 346 insertions(+), 78 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index cc610a2..41a190b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,45 @@ +2011-01-11 Sergio Durigan Junior + Thiago Jung Bauermann + + Implement support for PowerPC BookE ranged watchpoints. + * breakpoint.h + (struct breakpoint_ops) : New method. + Initialize to NULL in all existing breakpoint_ops instances. + (struct breakpoint) : New field. + (target_exact_watchpoints): Declare external global. + * breakpoint.c (target_exact_watchpoints): New global flag. + (update_watchpoint): Set b->type to bp_hardware_watchpoint and + b->enable_state to bp_enabled before calling + hw_watchpoint_used_count. + (hw_watchpoint_used_count): Iterate over all bp_locations in a + watchpoint. Call breakpoint's breakpoint_ops.resources_needed + if available. + (insert_watchpoint, remove_watchpoint): Use fixed length of 1 byte + if the watchpoint is exact. + (resources_needed_watchpoint): New function. + (watchpoint_breakpoint_ops): Add resources_needed_watchpoint. + (watch_command_1): Set b->exact if the user asked for an exact + watchpoint and one can be set. + (can_use_hardware_watchpoint): Add exact_watchpoints argument. + Pass fixed length of 1 to target_region_ok_for_hw_watchpoint if + the user asks for an exact watchpoint and one can be set. Return + number of needed debug registers to watch the expression. + * gdbtypes.c (is_scalar_type): New function, based on + valprint.c:scalar_type_p. + (is_scalar_type_recursive): New function. + * gdbtypes.h (is_scalar_type_recursive): Declare. + * ppc-linux-nat.c (ppc_linux_region_ok_for_hw_watchpoint): Always + handle regions when ranged watchpoints are available. + (create_watchpoint_request): New function. + (ppc_linux_insert_watchpoint, ppc_linux_remove_watchpoint): Use + create_watchpoint_request. + * rs6000-tdep.c (show_powerpc_exact_watchpoints): New function. + (_initialize_rs6000_tdep): Add `exact-watchpoints' boolean to the + `set powerpc' and `show powerpc' commands. + * target.h (struct target_ops) : + Mention documentation comment in the target macro. + (target_region_ok_for_hw_watchpoint): Document return value. + 2011-01-11 Thiago Jung Bauermann * breakpoint.c (update_watchpoint): Decide on using a software or diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 4f96e4a..73de1a0 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -10901,6 +10901,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops = NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ + NULL, /* resources_needed */ print_it_catch_exception, print_one_catch_exception, print_mention_catch_exception, @@ -10939,6 +10940,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = { NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ + NULL, /* resources_needed */ print_it_catch_exception_unhandled, print_one_catch_exception_unhandled, print_mention_catch_exception_unhandled, @@ -10975,6 +10977,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = { NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ + NULL, /* resources_needed */ print_it_catch_assert, print_one_catch_assert, print_mention_catch_assert, diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 8c1a4e0..3db9401 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -98,7 +98,7 @@ static void clear_command (char *, int); static void catch_command (char *, int); -static int can_use_hardware_watchpoint (struct value *); +static int can_use_hardware_watchpoint (struct value *, int); static void break_command_1 (char *, int, int); @@ -351,6 +351,9 @@ static int executing_breakpoint_commands; /* Are overlay event breakpoints enabled? */ static int overlay_events_enabled; +/* See description in breakpoint.h. */ +int target_exact_watchpoints = 0; + /* Walk the following statement or block through all breakpoints. ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current breakpoint. */ @@ -1481,29 +1484,41 @@ update_watchpoint (struct breakpoint *b, int reparse) if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint) && reparse) { - int mem_cnt; + int reg_cnt; enum bp_loc_type loc_type; struct bp_location *bl; - mem_cnt = can_use_hardware_watchpoint (val_chain); - if (mem_cnt) + reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact); + + if (reg_cnt) { int i, target_resources_ok, other_type_used; + enum enable_state orig_enable_state; /* We need to determine how many resources are already - used for all other hardware watchpoints to see if we - still have enough resources to also fit this watchpoint - in as well. To avoid the hw_watchpoint_used_count call - below from counting this watchpoint, make sure that it - is marked as a software watchpoint. */ - b->type = bp_watchpoint; + used for all other hardware watchpoints plus this one + to see if we still have enough resources to also fit + this watchpoint in as well. To guarantee the + hw_watchpoint_used_count call below counts this + watchpoint, make sure that it is marked as a hardware + watchpoint. */ + b->type = bp_hardware_watchpoint; + + /* hw_watchpoint_used_count ignores disabled watchpoints, + and b might be disabled if we're being called from + do_enable_breakpoint. */ + orig_enable_state = b->enable_state; + b->enable_state = bp_enabled; + i = hw_watchpoint_used_count (bp_hardware_watchpoint, &other_type_used); - target_resources_ok = target_can_use_hardware_watchpoint - (bp_hardware_watchpoint, i + mem_cnt, other_type_used); - if (target_resources_ok > 0) - b->type = bp_hardware_watchpoint; + b->enable_state = orig_enable_state; + + target_resources_ok = target_can_use_hardware_watchpoint + (bp_hardware_watchpoint, i, other_type_used); + if (target_resources_ok <= 0) + b->type = bp_watchpoint; } else b->type = bp_watchpoint; @@ -6094,6 +6109,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops = insert_catch_fork, remove_catch_fork, breakpoint_hit_catch_fork, + NULL, /* resources_needed */ print_it_catch_fork, print_one_catch_fork, print_mention_catch_fork, @@ -6189,6 +6205,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops = insert_catch_vfork, remove_catch_vfork, breakpoint_hit_catch_vfork, + NULL, /* resources_needed */ print_it_catch_vfork, print_one_catch_vfork, print_mention_catch_vfork, @@ -6472,6 +6489,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops = insert_catch_syscall, remove_catch_syscall, breakpoint_hit_catch_syscall, + NULL, /* resources_needed */ print_it_catch_syscall, print_one_catch_syscall, print_mention_catch_syscall, @@ -6625,6 +6643,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops = insert_catch_exec, remove_catch_exec, breakpoint_hit_catch_exec, + NULL, /* resources_needed */ print_it_catch_exec, print_one_catch_exec, print_mention_catch_exec, @@ -6665,20 +6684,30 @@ hw_breakpoint_used_count (void) static int hw_watchpoint_used_count (enum bptype type, int *other_type_used) { - struct breakpoint *b; int i = 0; + struct breakpoint *b; + struct bp_location *bl; *other_type_used = 0; ALL_BREAKPOINTS (b) - { - if (breakpoint_enabled (b)) - { + { + if (!breakpoint_enabled (b)) + continue; + if (b->type == type) - i++; + for (bl = b->loc; bl; bl = bl->next) + { + /* Special types of hardware watchpoints may use more than + one register. */ + if (b->ops && b->ops->resources_needed) + i += b->ops->resources_needed (bl); + else + i++; + } else if (is_hardware_watchpoint (b)) *other_type_used = 1; - } - } + } + return i; } @@ -8226,8 +8255,10 @@ watchpoint_exp_is_const (const struct expression *exp) static int insert_watchpoint (struct bp_location *bl) { - return target_insert_watchpoint (bl->address, bl->length, - bl->watchpoint_type, bl->owner->cond_exp); + int length = bl->owner->exact? 1 : bl->length; + + return target_insert_watchpoint (bl->address, length, bl->watchpoint_type, + bl->owner->cond_exp); } /* Implement the "remove" breakpoint_ops method for hardware watchpoints. */ @@ -8235,8 +8266,21 @@ insert_watchpoint (struct bp_location *bl) static int remove_watchpoint (struct bp_location *bl) { - return target_remove_watchpoint (bl->address, bl->length, - bl->watchpoint_type, bl->owner->cond_exp); + int length = bl->owner->exact? 1 : bl->length; + + return target_remove_watchpoint (bl->address, length, bl->watchpoint_type, + bl->owner->cond_exp); +} + +/* Implement the "resources_needed" breakpoint_ops method for + hardware watchpoints. */ + +static int +resources_needed_watchpoint (const struct bp_location *bl) +{ + int length = bl->owner->exact? 1 : bl->length; + + return target_region_ok_for_hw_watchpoint (bl->address, length); } /* The breakpoint_ops structure to be used in hardware watchpoints. */ @@ -8246,6 +8290,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops = insert_watchpoint, remove_watchpoint, NULL, /* breakpoint_hit */ + resources_needed_watchpoint, NULL, /* print_it */ NULL, /* print_one */ NULL, /* print_mention */ @@ -8272,7 +8317,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty, char *cond_end = NULL; int i, other_type_used, target_resources_ok = 0; enum bptype bp_type; - int mem_cnt = 0; + int reg_cnt = 0; int thread = -1; int pc = 0; @@ -8407,14 +8452,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty, else bp_type = bp_hardware_watchpoint; - mem_cnt = can_use_hardware_watchpoint (val); - if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint) + reg_cnt = can_use_hardware_watchpoint (val, target_exact_watchpoints); + if (reg_cnt == 0 && bp_type != bp_hardware_watchpoint) error (_("Expression cannot be implemented with read/access watchpoint.")); - if (mem_cnt != 0) + if (reg_cnt != 0) { i = hw_watchpoint_used_count (bp_type, &other_type_used); target_resources_ok = - target_can_use_hardware_watchpoint (bp_type, i + mem_cnt, + target_can_use_hardware_watchpoint (bp_type, i + reg_cnt, other_type_used); if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint) error (_("Target does not support this type of hardware watchpoint.")); @@ -8426,7 +8471,7 @@ 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) + if (!reg_cnt || target_resources_ok <= 0) bp_type = bp_watchpoint; frame = block_innermost_frame (exp_valid_block); @@ -8497,6 +8542,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty, b->val_valid = 1; b->ops = &watchpoint_breakpoint_ops; + /* Use an exact watchpoint when there's only one memory region to be + watched, and only one debug register is needed to watch it. */ + b->exact = target_exact_watchpoints && reg_cnt == 1; + if (cond_start) b->cond_string = savestring (cond_start, cond_end - cond_start); else @@ -8536,12 +8585,15 @@ watch_command_1 (char *arg, int accessflag, int from_tty, update_global_location_list (1); } -/* Return count of locations need to be watched and can be handled in - hardware. If the watchpoint can not be handled in hardware return - zero. */ +/* Return count of debug registers needed to watch the given expression. + If EXACT_WATCHPOINTS is 1, then consider that only the address of + the start of the watched region will be monitored (i.e., all accesses + will be aligned). This uses less debug registers on some targets. + + If the watchpoint cannot be handled in hardware return zero. */ static int -can_use_hardware_watchpoint (struct value *v) +can_use_hardware_watchpoint (struct value *v, int exact_watchpoints) { int found_memory_cnt = 0; struct value *head = v; @@ -8594,12 +8646,18 @@ can_use_hardware_watchpoint (struct value *v) && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) { CORE_ADDR vaddr = value_address (v); - int len = TYPE_LENGTH (value_type (v)); + int len; + int num_regs; + + len = (exact_watchpoints + && is_scalar_type_recursive (vtype))? + 1 : TYPE_LENGTH (value_type (v)); - if (!target_region_ok_for_hw_watchpoint (vaddr, len)) + num_regs = target_region_ok_for_hw_watchpoint (vaddr, len); + if (!num_regs) return 0; else - found_memory_cnt++; + found_memory_cnt += num_regs; } } } @@ -9025,6 +9083,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = { NULL, /* insert */ NULL, /* remove */ NULL, /* breakpoint_hit */ + NULL, /* resources_needed */ print_exception_catchpoint, print_one_exception_catchpoint, print_mention_exception_catchpoint, diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index cd9b6b8..69598a7 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -385,6 +385,11 @@ struct breakpoint_ops breakpoint was hit. */ int (*breakpoint_hit) (struct breakpoint *); + /* Tell how many hardware resources (debug registers) are needed + for this breakpoint. If this function is not provided, then + the breakpoint or watchpoint needs one debug register. */ + int (*resources_needed) (const struct bp_location *); + /* The normal print routine for this breakpoint, called when we hit it. */ enum print_stop_action (*print_it) (struct breakpoint *); @@ -425,6 +430,13 @@ DEF_VEC_P(bp_location_p); detail to the breakpoints module. */ struct counted_command_line; +/* Some targets (e.g., embedded PowerPC) need two debug registers to set + a watchpoint over a memory region. If this flag is true, GDB will use + only one register per watchpoint, thus assuming that all acesses that + modify a memory location happen at its starting address. */ + +extern int target_exact_watchpoints; + /* 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 @@ -595,7 +607,10 @@ struct breakpoint can sometimes be NULL for enabled GDBs as not all breakpoint types are tracked by the Python scripting API. */ struct breakpoint_object *py_bp_object; -}; + + /* Whether this watchpoint is exact (see target_exact_watchpoints). */ + int exact; + }; typedef struct breakpoint *breakpoint_p; DEF_VEC_P(breakpoint_p); diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index d5f89b2..a64db4c 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2011-01-11 Sergio Durigan Junior + Thiago Jung Bauermann + + Implement support for PowerPC BookE ranged watchpoints. + * gdb.texinfo (PowerPC Embedded): Document ranged watchpoints and + the "set powerpc exact-watchpoints" flag. + 2011-01-07 Tom Tromey * gdb.texinfo (Python API): Add descriptions to @menu items. @@ -8,7 +15,7 @@ 2010-01-06 Paul Pluzhnikov - * gdb.texinfo (Debugging Output): Document "set debug jit". + * gdb.texinfo (Debugging Output): Document "set debug jit". 2011-01-06 Tom Tromey diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 7f8c785..8e42913 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18721,9 +18721,25 @@ implement in hardware simple hardware watchpoint conditions of the form: if @var{ADDRESS|VARIABLE} == @var{CONSTANT EXPRESSION} @end smallexample -The DVC register will be automatically used whenever @value{GDBN} detects -such pattern in a condition expression. This feature is available in native -@value{GDBN} running on a Linux kernel version 2.6.34 or newer. +The DVC register will be automatically used when @value{GDBN} detects +such pattern in a condition expression, and the created watchpoint uses one +debug register (either the @code{exact-watchpoints} option is on and the +variable is scalar, or the variable has a length of one byte). This feature +is available in native @value{GDBN} running on a Linux kernel version 2.6.34 +or newer. + +When running on PowerPC embedded processors, @value{GDBN} automatically uses +ranged hardware watchpoints, unless the @code{exact-watchpoints} option is on, +in which case watchpoints using only one debug register are created when +watching variables of scalar types. + +You can create an artificial array to watch an arbitrary memory +region using one of the following commands (@pxref{Expressions}): + +@smallexample +(@value{GDBP}) watch *((char *) @var{address})@@@var{length} +(@value{GDBP}) watch @{char[@var{length}]@} @var{address} +@end smallexample @value{GDBN} provides the following PowerPC-specific commands: @@ -18744,6 +18760,12 @@ arguments and return values. The valid options are @samp{auto}; registers. By default, @value{GDBN} selects the calling convention based on the selected architecture and the provided executable file. +@item set powerpc exact-watchpoints +@itemx show powerpc exact-watchpoints +Allow @value{GDBN} to use only one debug register when watching a variable +of scalar type, thus assuming that the variable is accessed through the +address of its first byte. + @kindex target dink32 @item target dink32 @var{dev} DINK32 ROM monitor. diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 94ae179..a01f326 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1955,6 +1955,68 @@ is_integral_type (struct type *t) || (TYPE_CODE (t) == TYPE_CODE_BOOL))); } +/* Return true if TYPE is scalar. */ + +static int +is_scalar_type (struct type *type) +{ + CHECK_TYPEDEF (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_SET: + case TYPE_CODE_STRING: + case TYPE_CODE_BITSTRING: + return 0; + default: + return 1; + } +} + +/* Return true if T is scalar, or a composite type which in practice has + the memory layout of a scalar type. E.g., an array or struct with only one + scalar element inside it, or a union with only scalar elements. */ + +int +is_scalar_type_recursive (struct type *t) +{ + CHECK_TYPEDEF (t); + + if (is_scalar_type (t)) + return 1; + /* Are we dealing with an array or string of known dimensions? */ + else if ((TYPE_CODE (t) == TYPE_CODE_ARRAY + || TYPE_CODE (t) == TYPE_CODE_STRING) && TYPE_NFIELDS (t) == 1 + && TYPE_CODE (TYPE_INDEX_TYPE (t)) == TYPE_CODE_RANGE) + { + LONGEST low_bound, high_bound; + struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (t)); + + get_discrete_bounds (TYPE_INDEX_TYPE (t), &low_bound, &high_bound); + + return high_bound == low_bound && is_scalar_type_recursive (elt_type); + } + /* Are we dealing with a struct with one element? */ + else if (TYPE_CODE (t) == TYPE_CODE_STRUCT && TYPE_NFIELDS (t) == 1) + return is_scalar_type_recursive (TYPE_FIELD_TYPE (t, 0)); + else if (TYPE_CODE (t) == TYPE_CODE_UNION) + { + int i, n = TYPE_NFIELDS (t); + + /* If all elements of the union are scalar, then the union is scalar. */ + for (i = 0; i < n; i++) + if (!is_scalar_type_recursive (TYPE_FIELD_TYPE (t, i))) + return 0; + + return 1; + } + + return 0; +} + /* A helper function which returns true if types A and B represent the "same" class type. This is true if the types have the same main type, or the same name. */ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 108206b..debb41c 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -1476,6 +1476,8 @@ extern int can_dereference (struct type *); extern int is_integral_type (struct type *); +extern int is_scalar_type_recursive (struct type *); + extern void maintenance_print_type (char *, int); extern htab_t create_copied_types_hash (struct objfile *objfile); diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index c0f0708..a86f9b6 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -1497,9 +1497,16 @@ ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) to determine the hardcoded watchable region for watchpoints. */ if (have_ptrace_booke_interface ()) { - 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 any access within an arbitrary + memory region. This is useful to watch arrays and structs, for + instance. It takes two hardware watchpoints though. */ + if (len > 1 + && booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) + return 2; + 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 @@ -1889,6 +1896,55 @@ ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw, && check_condition (addr, cond, &data_value)); } +/* Set up P with the parameters necessary to request a watchpoint covering + LEN bytes starting at ADDR and if possible with condition expression COND + evaluated by hardware. INSERT tells if we are creating a request for + inserting or removing the watchpoint. */ + +static void +create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr, + int len, int rw, struct expression *cond, + int insert) +{ + if (len == 1) + { + int use_condition; + CORE_ADDR data_value; + + use_condition = (insert? can_use_watchpoint_cond_accel () + : booke_debug_info.num_condition_regs > 0); + if (cond && use_condition && check_condition (addr, cond, &data_value)) + calculate_dvc (addr, len, data_value, &p->condition_mode, + &p->condition_value); + else + { + p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p->condition_value = 0; + } + + p->addr_mode = PPC_BREAKPOINT_MODE_EXACT; + p->addr2 = 0; + } + else + { + p->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; + p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p->condition_value = 0; + + /* The watchpoint will trigger if the address of the memory access is + within the defined range, as follows: p->addr <= address < p->addr2. + + Note that the above sentence just documents how ptrace interprets + its arguments; the watchpoint is set to watch the range defined by + the user _inclusively_, as specified by the user interface. */ + p->addr2 = (uint64_t) addr + len; + } + + p->version = PPC_DEBUG_CURRENT_VERSION; + p->trigger_type = get_trigger_type (rw); + p->addr = (uint64_t) addr; +} + static int ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw, struct expression *cond) @@ -1900,23 +1956,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw, if (have_ptrace_booke_interface ()) { struct ppc_hw_breakpoint p; - CORE_ADDR data_value; - - if (cond && can_use_watchpoint_cond_accel () - && check_condition (addr, cond, &data_value)) - calculate_dvc (addr, len, data_value, &p.condition_mode, - &p.condition_value); - else - { - p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; - p.condition_value = 0; - } - p.version = PPC_DEBUG_CURRENT_VERSION; - p.trigger_type = get_trigger_type (rw); - p.addr_mode = PPC_BREAKPOINT_MODE_EXACT; - p.addr = (uint64_t) addr; - p.addr2 = 0; + create_watchpoint_request (&p, addr, len, rw, cond, 1); ALL_LWPS (lp, ptid) booke_insert_point (&p, TIDGET (ptid)); @@ -1984,23 +2025,8 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw, if (have_ptrace_booke_interface ()) { struct ppc_hw_breakpoint p; - CORE_ADDR data_value; - - if (cond && booke_debug_info.num_condition_regs > 0 - && check_condition (addr, cond, &data_value)) - calculate_dvc (addr, len, data_value, &p.condition_mode, - &p.condition_value); - else - { - p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; - p.condition_value = 0; - } - p.version = PPC_DEBUG_CURRENT_VERSION; - p.trigger_type = get_trigger_type (rw); - p.addr_mode = PPC_BREAKPOINT_MODE_EXACT; - p.addr = (uint64_t) addr; - p.addr2 = 0; + create_watchpoint_request (&p, addr, len, rw, cond, 0); ALL_LWPS (lp, ptid) booke_remove_point (&p, TIDGET (ptid)); diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index cd5135e..c16e933 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -4183,6 +4183,16 @@ powerpc_set_vector_abi (char *args, int from_tty, internal_error (__FILE__, __LINE__, _("could not update architecture")); } +/* Show the current setting of the exact watchpoints flag. */ + +static void +show_powerpc_exact_watchpoints (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value); +} + /* Initialization code. */ /* -Wmissing-prototypes */ @@ -4240,4 +4250,17 @@ _initialize_rs6000_tdep (void) _("Show the vector ABI."), NULL, powerpc_set_vector_abi, NULL, &setpowerpccmdlist, &showpowerpccmdlist); + + add_setshow_boolean_cmd ("exact-watchpoints", class_support, + &target_exact_watchpoints, + _("\ +Set whether to use just one debug register for watchpoints on scalars."), + _("\ +Show whether to use just one debug register for watchpoints on scalars."), + _("\ +If true, GDB will use only one debug register when watching a variable of\n\ +scalar type, thus assuming that the variable is accessed through the address\n\ +of its first byte."), + NULL, show_powerpc_exact_watchpoints, + &setpowerpccmdlist, &showpowerpccmdlist); } diff --git a/gdb/target.h b/gdb/target.h index 72fd211..d76c490 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -453,7 +453,11 @@ struct target_ops int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *); int (*to_watchpoint_addr_within_range) (struct target_ops *, CORE_ADDR, CORE_ADDR, int); + + /* Documentation of this routine is provided with the corresponding + target_* macro. */ int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int); + int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int, struct expression *); void (*to_terminal_init) (void); @@ -1308,6 +1312,9 @@ extern char *normal_pid_to_str (ptid_t ptid); #define target_can_use_hardware_watchpoint(TYPE,CNT,OTHERTYPE) \ (*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE); +/* Returns the number of debug registers needed to watch the given + memory region, or zero if not supported. */ + #define target_region_ok_for_hw_watchpoint(addr, len) \ (*current_target.to_region_ok_for_hw_watchpoint) (addr, len) -- cgit v1.1