This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch 2/3] Implement support for PowerPC BookE ranged watchpoints


On Thu, 2010-12-23 at 20:16 +0000, Pedro Alves wrote:
> I think this looks great.  Thanks a million for following through!

Awesome! Thanks for the review.

> On Thursday 23 December 2010 18:49:42, Thiago Jung Bauermann wrote:
> > +int
> > +is_scalar_type_recursive (struct type *t)
> > +{
> > +  CHECK_TYPEDEF (t);
> > +
> > +  if (is_scalar_type (t))
> > +    return 1;
> > +  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);
> > +    }
> 
> What does the "TYPE_NFIELDS (t) == 1" do ?

TYPE_NFIELDS (t) == 1 && TYPE_CODE (TYPE_INDEX_TYPE (t)) == TYPE_CODE_RANGE
is a way to determine that the given array type has known bounds.

> I think you're missing at least pointers and references.  These should
> also get the "exact" treatment, no?  Take a look at valprint.c:scalar_type_p.

There are different places in GDB which classify types as scalars and
non-scalars. Some list explicitly the scalar types and everything else
is non-scalar, and some (like scalar_type_p_ do the opposite. I thought
that the former approach was more conservative.

But I didn't know about scalar_type_p and since there's a function
that's used in a central place like val_print, then I can just use it.
This new version of the patch renames scalar_type_p to is_scalar_type
(to match is_integral_type) and moves it to gdbtypes.c.

> Could you please add small describing comments above these new
> functions?  ("return true if type T is a blah, blah".)

I added:

/* Return true if TYPE is scalar.  */                                          
  
int
is_scalar_type (struct type *type)

and

/* 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)

> > +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 just one debug register per watchpoint is %s.\n"), value);
> > +}
> > +
> 
> Should be "Use of exact watchpoints is ...", I think?  Thus getting rid
> of the small lie that not all watchpoints (in the user perspective) will
> use just one debug register, leaving the just one debug register
> issue explanation to the help string (as you already have).

Good point. Changed to:

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);
}

Also the apropos strings are now:

                           _("\
Set whether to use just one debug register for watchpoints on scalars."),
                           _("\
Show whether to use just one debug register for watchpoints on scalars."),

Ok?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2010-12-27  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	Implement support for PowerPC BookE ranged watchpoints.

gdb/
	* breakpoint.h 
	(struct breakpoint_ops) <extra_resources_needed>: New methods
	Initialize to NULL in all existing breakpoint_ops instances.
	(struct breakpoint) <exact>: New field.
	(target_exact_watchpoints): Declare external global.
	* breakpoint.c (target_exact_watchpoints): New global flag.
	(update_watchpoint): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.
	(hw_watchpoint_used_count): Call breakpoint's
	breakpoint_ops.extra_resources_needed if available.  Change to
	count number of bp_locations, instead of number of high-level
	breakpoints.
	(insert_watchpoint, remove_watchpoint): Use fixed length of 1 byte
	if the watchpoint is exact.
	(extra_resources_needed_watchpoint): New function.
	(watchpoint_breakpoint_ops): Add extra_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): Accept 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): Move and rename from
	valprint.c:scalar_type_p.  Update callers.
	(is_scalar_type_recursive): New function.
	* gdbtypes.h (is_scalar_type, 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) <to_region_ok_for_hw_watchpoint>:
	Mention documentation comment in the target macro.
	(target_region_ok_for_hw_watchpoint): Document return value.
	* valprint.c (scalar_type_p): Move and rename to
	gdbtypes.c:is_scalar_type.

gdb/doc/
	* gdb.texinfo (PowerPC Embedded): Document ranged watchpoints and
	the "set powerpc exact-watchpoints" flag.


diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 7ea01c7..3a2a266 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10821,6 +10821,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   print_it_catch_exception,
   print_one_catch_exception,
   print_mention_catch_exception,
@@ -10859,6 +10860,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
   print_mention_catch_exception_unhandled,
@@ -10895,6 +10897,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_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 003899c..9c10b30 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);
 
@@ -345,6 +345,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.  */
@@ -1394,25 +1397,33 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
 	    && reparse)
 	  {
-	    int i, mem_cnt, other_type_used;
-
-	    /* 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;
-	    i = hw_watchpoint_used_count (bp_hardware_watchpoint,
-					  &other_type_used);
-	    mem_cnt = can_use_hardware_watchpoint (val_chain);
-
-	    if (!mem_cnt)
+	    int reg_cnt;
+
+	    reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact);
+
+	    if (!reg_cnt)
 	      b->type = bp_watchpoint;
 	    else
 	      {
-		int target_resources_ok = target_can_use_hardware_watchpoint
-		  (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
+		int i, other_type_used, target_resources_ok;
+		enum bptype orig_type;
+
+		if (b->ops && b->ops->extra_resources_needed)
+		  reg_cnt += b->ops->extra_resources_needed (b, NULL);
+
+		/* 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.  */
+		orig_type = b->type;
+		b->type = bp_watchpoint;
+		i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+					      &other_type_used);
+
+		target_resources_ok = target_can_use_hardware_watchpoint
+		  (bp_hardware_watchpoint, i + reg_cnt, other_type_used)
 		if (target_resources_ok <= 0)
 		  b->type = bp_watchpoint;
 		else
@@ -6004,6 +6015,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   insert_catch_fork,
   remove_catch_fork,
   breakpoint_hit_catch_fork,
+  NULL, /* extra_resources_needed */
   print_it_catch_fork,
   print_one_catch_fork,
   print_mention_catch_fork,
@@ -6095,6 +6107,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   insert_catch_vfork,
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
+  NULL, /* extra_resources_needed */
   print_it_catch_vfork,
   print_one_catch_vfork,
   print_mention_catch_vfork,
@@ -6376,6 +6389,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   insert_catch_syscall,
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
+  NULL, /* extra_resources_needed */
   print_it_catch_syscall,
   print_one_catch_syscall,
   print_mention_catch_syscall,
@@ -6529,6 +6543,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   insert_catch_exec,
   remove_catch_exec,
   breakpoint_hit_catch_exec,
+  NULL, /* extra_resources_needed */
   print_it_catch_exec,
   print_one_catch_exec,
   print_mention_catch_exec,
@@ -6570,19 +6585,29 @@ static int
 hw_watchpoint_used_count (enum bptype type, int *other_type_used)
 {
   struct breakpoint *b;
+  struct bp_location *bl;
   int i = 0;
 
   *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)
+	    {
+	      i++;
+
+	      /* Special types of hardware watchpoints may use more than
+		 one register.  */
+	      if (b->ops && b->ops->extra_resources_needed)
+		i += b->ops->extra_resources_needed (b, bl);
+	    }
 	else if (is_hardware_watchpoint (b))
 	  *other_type_used = 1;
-      }
-  }
+    }
+
   return i;
 }
 
@@ -8119,8 +8144,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.  */
@@ -8128,8 +8155,31 @@ 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 "extra_resources_needed" breakpoint_ops method for
+   hardware watchpoints.  */
+
+static int
+extra_resources_needed_watchpoint (const struct breakpoint *b,
+				   const struct bp_location *bl)
+{
+  if (bl)
+    {
+      int ret, length = bl->owner->exact? 1 : bl->length;
+
+      ret = target_region_ok_for_hw_watchpoint (bl->address, length);
+
+      gdb_assert (ret > 0);
+
+      return ret - 1;
+    }
+  else
+    return 0;
 }
 
 /* The breakpoint_ops structure to be used in hardware watchpoints.  */
@@ -8139,6 +8189,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   insert_watchpoint,
   remove_watchpoint,
   NULL, /* breakpoint_hit */
+  extra_resources_needed_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
   NULL, /* print_mention */
@@ -8165,7 +8216,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;
 
@@ -8300,14 +8351,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."));
@@ -8318,7 +8369,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);
@@ -8389,6 +8440,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   b->val_valid = 1;
   b->ops = &watchpoint_breakpoint_ops;
 
+  /* Use an exact watchpoint only when there's one memory region to be
+     watched, which needs only one debug register.  */
+  b->exact = target_exact_watchpoints && reg_cnt == 1;
+
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
   else
@@ -8428,12 +8483,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 need 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 can not 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;
@@ -8486,12 +8544,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;
 		}
 	    }
 	}
@@ -8915,6 +8979,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* insert */
   NULL, /* remove */
   NULL, /* breakpoint_hit */
+  NULL, /* extra_resources_needed */
   print_exception_catchpoint,
   print_one_exception_catchpoint,
   print_mention_exception_catchpoint,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 12c2df2..8e68532 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -372,6 +372,16 @@ struct breakpoint_ops
      breakpoint was hit.  */
   int (*breakpoint_hit) (struct breakpoint *);
 
+  /* Tell how many additional hardware resources (debug registers) are needed
+     for this breakpoint.  The bp_location argument may be NULL if the method
+     is called at a point where no location is assigned to the breakpoint yet.
+
+     We always count at least one resource, so if this function returns 1, then
+     GDB will consider that the breakpoint needes 2 registers.  If this element
+     is NULL, then no additional resources are needed.  */
+  int (*extra_resources_needed) (const struct breakpoint *,
+				 const struct bp_location *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
   enum print_stop_action (*print_it) (struct breakpoint *);
@@ -411,6 +421,13 @@ DEF_VEC_P(bp_location_p);
    detail to the breakpoints module.  */
 struct counted_command_line;
 
+/* Some targets (eg, 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
@@ -577,7 +594,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/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0e1d553..b647c53 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18728,9 +18728,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:
 
@@ -18751,6 +18767,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 b651098..f33b9b8 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1955,6 +1955,74 @@ is_integral_type (struct type *t)
 	 || (TYPE_CODE (t) == TYPE_CODE_BOOL)));
 }
 
+/* Return true if TYPE is scalar.  */
+
+int
+is_scalar_type (struct type *type)
+{
+  CHECK_TYPEDEF (type);
+
+  while (TYPE_CODE (type) == TYPE_CODE_REF)
+    {
+      type = TYPE_TARGET_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 1ce2d91..f3534f5 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1475,6 +1475,10 @@ extern int can_dereference (struct type *);
 
 extern int is_integral_type (struct type *);
 
+extern int is_scalar_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 18ddee7..7c853a9 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1489,9 +1489,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
@@ -1878,6 +1885,51 @@ 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.  */
+
+static void
+create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
+			   int len, int rw, struct expression *cond)
+{
+  if (len == 1)
+    {
+      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->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)
@@ -1889,23 +1941,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);
 
       ALL_LWPS (lp, ptid)
 	booke_insert_point (&p, TIDGET (ptid));
@@ -1973,23 +2010,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);
 
       ALL_LWPS (lp, ptid)
 	booke_remove_point (&p, TIDGET (ptid));
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 81a99b6..f5f0f72 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -4177,6 +4177,14 @@ powerpc_set_vector_abi (char *args, int from_tty,
     internal_error (__FILE__, __LINE__, "could not update architecture");
 }
 
+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.  */
 
 extern initialize_file_ftype _initialize_rs6000_tdep; /* -Wmissing-prototypes */
@@ -4233,4 +4241,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 per watchpoint on scalars."),
+			   _("\
+Show whether to use just one debug register per watchpoint 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 bc70107..2ef5c56 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -452,7 +452,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);
@@ -1313,6 +1317,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)
 
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 5cba023..804b2d2 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -218,33 +218,6 @@ show_addressprint (struct ui_file *file, int from_tty,
 }
 
 
-/* A helper function for val_print.  When printing in "summary" mode,
-   we want to print scalar arguments, but not aggregate arguments.
-   This function distinguishes between the two.  */
-
-static int
-scalar_type_p (struct type *type)
-{
-  CHECK_TYPEDEF (type);
-  while (TYPE_CODE (type) == TYPE_CODE_REF)
-    {
-      type = TYPE_TARGET_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;
-    }
-}
-
 /* Helper function to check the validity of some bits of a value.
 
    If TYPE represents some aggregate type (e.g., a structure), return 1.
@@ -343,7 +316,7 @@ val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
 
   /* Handle summary mode.  If the value is a scalar, print it;
      otherwise, print an ellipsis.  */
-  if (options->summary && !scalar_type_p (type))
+  if (options->summary && !is_scalar_type (type))
     {
       fprintf_filtered (stream, "...");
       return 0;



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]