PR 10450
[deliverable/binutils-gdb.git] / gdb / breakpoint.c
index d879b5754133c9d815c371caa150e6823de99314..1beb45c46f5cd4b323f3ba657af123d29af48a1f 100644 (file)
@@ -985,6 +985,24 @@ fetch_watchpoint_value (struct expression *exp, struct value **valp,
     }
 }
 
+/* Assuming that B is a watchpoint: returns true if the current thread
+   and its running state are safe to evaluate or update watchpoint B.
+   Watchpoints on local expressions need to be evaluated in the
+   context of the thread that was current when the watchpoint was
+   created, and, that thread needs to be stopped to be able to select
+   the correct frame context.  Watchpoints on global expressions can
+   be evaluated on any thread, and in any state.  It is presently left
+   to the target allowing memory accesses when threads are
+   running.  */
+
+static int
+watchpoint_in_thread_scope (struct breakpoint *b)
+{
+  return (ptid_equal (b->watchpoint_thread, null_ptid)
+         || (ptid_equal (inferior_ptid, b->watchpoint_thread)
+             && !is_executing (inferior_ptid)));
+}
+
 /* Assuming that B is a watchpoint:
    - Reparse watchpoint expression, if REPARSE is non-zero
    - Evaluate expression and store the result in B->val
@@ -1041,7 +1059,12 @@ update_watchpoint (struct breakpoint *b, int reparse)
   struct bp_location *loc;
   int frame_saved;
   bpstat bs;
-  struct program_space *frame_pspace;
+
+  /* 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
+     that was used to create the watchpoint.  */
+  if (!watchpoint_in_thread_scope (b))
+    return;
 
   /* We don't free locations.  They are stored in bp_location array and
      update_global_locations will eventually delete them and remove
@@ -1074,8 +1097,6 @@ update_watchpoint (struct breakpoint *b, int reparse)
        select_frame (fi);
     }
 
-  frame_pspace = get_frame_program_space (get_selected_frame (NULL));
-
   if (within_current_scope && reparse)
     {
       char *s;
@@ -1100,9 +1121,16 @@ update_watchpoint (struct breakpoint *b, int reparse)
      don't try to insert watchpoint.  We don't automatically delete
      such watchpoint, though, since failure to parse expression
      is different from out-of-scope watchpoint.  */
-  if (within_current_scope && b->exp)
+  if ( !target_has_execution)
+    {
+      /* Without execution, memory can't change.  No use to try and
+        set watchpoint locations.  The watchpoint will be reset when
+        the target gains execution, through breakpoint_re_set.  */
+    }
+  else if (within_current_scope && b->exp)
     {
       struct value *val_chain, *v, *result, *next;
+      struct program_space *frame_pspace;
 
       fetch_watchpoint_value (b->exp, &v, &result, &val_chain);
 
@@ -1141,6 +1169,8 @@ update_watchpoint (struct breakpoint *b, int reparse)
              }
          }
 
+      frame_pspace = get_frame_program_space (get_selected_frame (NULL));
+
       /* Look at each value on the value chain.  */
       for (v = val_chain; v; v = next)
        {
@@ -2350,6 +2380,38 @@ software_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
   return 0;
 }
 
+int
+hardware_watchpoint_inserted_in_range (struct address_space *aspace,
+                                      CORE_ADDR addr, ULONGEST len)
+{
+  struct breakpoint *bpt;
+
+  ALL_BREAKPOINTS (bpt)
+    {
+      struct bp_location *loc;
+
+      if (bpt->type != bp_hardware_watchpoint
+         && bpt->type != bp_access_watchpoint)
+       continue;
+
+      if (!breakpoint_enabled (bpt))
+       continue;
+
+      for (loc = bpt->loc; loc; loc = loc->next)
+       if (loc->pspace->aspace == aspace && loc->inserted)
+         {
+           CORE_ADDR l, h;
+
+           /* Check for intersection.  */
+           l = max (loc->address, addr);
+           h = min (loc->address + loc->length, addr + len);
+           if (l < h)
+             return 1;
+         }
+    }
+  return 0;
+}
+
 /* breakpoint_thread_match (PC, PTID) returns true if the breakpoint at
    PC is valid for process/thread PTID.  */
 
@@ -3112,7 +3174,10 @@ watchpoints_triggered (struct target_waitstatus *ws)
 #define BP_TEMPFLAG 1
 #define BP_HARDWAREFLAG 2
 
-/* Check watchpoint condition.  */
+/* Evaluate watchpoint condition expression and check if its value changed.
+
+   P should be a pointer to struct bpstat, but is defined as a void *
+   in order for this function to be usable with catch_errors.  */
 
 static int
 watchpoint_check (void *p)
@@ -3124,6 +3189,12 @@ watchpoint_check (void *p)
 
   b = bs->breakpoint_at->owner;
 
+  /* 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
+     that was used to create the watchpoint.  */
+  if (!watchpoint_in_thread_scope (b))
+    return WP_VALUE_NOT_CHANGED;
+
   if (b->exp_valid_block == NULL)
     within_current_scope = 1;
   else
@@ -3177,8 +3248,12 @@ watchpoint_check (void *p)
       struct value *new_val;
 
       fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+
+      /* We use value_equal_contents instead of value_equal because the latter
+        coerces an array to a pointer, thus comparing just the address of the
+        array instead of its contents.  This is not what we want.  */
       if ((b->val != NULL) != (new_val != NULL)
-         || (b->val != NULL && !value_equal (b->val, new_val)))
+         || (b->val != NULL && !value_equal_contents (b->val, new_val)))
        {
          if (new_val != NULL)
            {
@@ -3238,6 +3313,11 @@ bpstat_check_location (const struct bp_location *bl,
 {
   struct breakpoint *b = bl->owner;
 
+  /* By definition, the inferior does not report stops at
+     tracepoints.  */
+  if (b->type == bp_tracepoint)
+    return 0;
+
   if (b->type != bp_watchpoint
       && b->type != bp_hardware_watchpoint
       && b->type != bp_read_watchpoint
@@ -3481,80 +3561,84 @@ bpstat_stop_status (struct address_space *aspace,
   /* Pointer to the last thing in the chain currently.  */
   bpstat bs = root_bs;
   int ix;
-  int need_remove_insert, update_locations = 0;
+  int need_remove_insert;
 
-  ALL_BP_LOCATIONS (bl, blp_tmp)
-  {
-    b = bl->owner;
-    gdb_assert (b);
-    if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
-      continue;
+  /* ALL_BP_LOCATIONS iteration would break across
+     update_global_location_list possibly executed by
+     bpstat_check_breakpoint_conditions's inferior call.  */
 
-    /* For hardware watchpoints, we look only at the first location.
-       The watchpoint_check function will work on entire expression,
-       not the individual locations.  For read watchopints, the
-       watchpoints_triggered function have checked all locations
-       already.  */
-    if (b->type == bp_hardware_watchpoint && bl != b->loc)
-      continue;
+  ALL_BREAKPOINTS (b)
+    {
+      if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
+       continue;
 
-    if (!bpstat_check_location (bl, aspace, bp_addr))
-      continue;
+      for (bl = b->loc; bl != NULL; bl = bl->next)
+       {
+         /* For hardware watchpoints, we look only at the first location.
+            The watchpoint_check function will work on entire expression,
+            not the individual locations.  For read watchopints, the
+            watchpoints_triggered function have checked all locations
+            already.  */
+         if (b->type == bp_hardware_watchpoint && bl != b->loc)
+           break;
 
-    /* Come here if it's a watchpoint, or if the break address matches */
+         if (bl->shlib_disabled)
+           continue;
 
-    bs = bpstat_alloc (bl, bs);        /* Alloc a bpstat to explain stop */
+         if (!bpstat_check_location (bl, aspace, bp_addr))
+           continue;
 
-    /* Assume we stop.  Should we find watchpoint that is not actually
-       triggered, or if condition of breakpoint is false, we'll reset
-       'stop' to 0.  */
-    bs->stop = 1;
-    bs->print = 1;
+         /* Come here if it's a watchpoint, or if the break address matches */
 
-    bpstat_check_watchpoint (bs);
-    if (!bs->stop)
-      continue;
+         bs = bpstat_alloc (bl, bs);   /* Alloc a bpstat to explain stop */
 
-    if (b->type == bp_thread_event || b->type == bp_overlay_event
-       || b->type == bp_longjmp_master)
-      /* We do not stop for these.  */
-      bs->stop = 0;
-    else
-      bpstat_check_breakpoint_conditions (bs, ptid);
-  
-    if (bs->stop)
-      {
-       if (b->enable_state != bp_disabled)
-         ++(b->hit_count);
+         /* Assume we stop.  Should we find watchpoint that is not actually
+            triggered, or if condition of breakpoint is false, we'll reset
+            'stop' to 0.  */
+         bs->stop = 1;
+         bs->print = 1;
 
-       /* We will stop here */
-       if (b->disposition == disp_disable)
-         {
-           if (b->enable_state != bp_permanent)
-             b->enable_state = bp_disabled;
-           update_locations = 1;
-         }
-       if (b->silent)
-         bs->print = 0;
-       bs->commands = b->commands;
-       if (bs->commands
-           && (strcmp ("silent", bs->commands->line) == 0
-               || (xdb_commands && strcmp ("Q", bs->commands->line) == 0)))
-         {
-           bs->commands = bs->commands->next;
-           bs->print = 0;
-         }
-       bs->commands = copy_command_lines (bs->commands);
-      }
+         bpstat_check_watchpoint (bs);
+         if (!bs->stop)
+           continue;
 
-    /* Print nothing for this entry if we dont stop or if we dont print.  */
-    if (bs->stop == 0 || bs->print == 0)
-      bs->print_it = print_it_noop;
-  }
+         if (b->type == bp_thread_event || b->type == bp_overlay_event
+             || b->type == bp_longjmp_master)
+           /* We do not stop for these.  */
+           bs->stop = 0;
+         else
+           bpstat_check_breakpoint_conditions (bs, ptid);
+       
+         if (bs->stop)
+           {
+             ++(b->hit_count);
 
-  /* Delay this call which would break the ALL_BP_LOCATIONS iteration above.  */
-  if (update_locations)
-    update_global_location_list (0);
+             /* We will stop here */
+             if (b->disposition == disp_disable)
+               {
+                 if (b->enable_state != bp_permanent)
+                   b->enable_state = bp_disabled;
+                 update_global_location_list (0);
+               }
+             if (b->silent)
+               bs->print = 0;
+             bs->commands = b->commands;
+             if (bs->commands
+                 && (strcmp ("silent", bs->commands->line) == 0
+                     || (xdb_commands && strcmp ("Q",
+                                                 bs->commands->line) == 0)))
+               {
+                 bs->commands = bs->commands->next;
+                 bs->print = 0;
+               }
+             bs->commands = copy_command_lines (bs->commands);
+           }
+
+         /* Print nothing for this entry if we dont stop or dont print.  */
+         if (bs->stop == 0 || bs->print == 0)
+           bs->print_it = print_it_noop;
+       }
+    }
 
   for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
     {
@@ -3585,22 +3669,17 @@ bpstat_stop_status (struct address_space *aspace,
     for (bs = root_bs->next; bs != NULL; bs = bs->next)
       if (!bs->stop
          && bs->breakpoint_at->owner
-         && (bs->breakpoint_at->owner->type == bp_hardware_watchpoint
-             || bs->breakpoint_at->owner->type == bp_read_watchpoint
-             || bs->breakpoint_at->owner->type == bp_access_watchpoint))
+         && is_hardware_watchpoint (bs->breakpoint_at->owner))
        {
-         /* remove/insert can invalidate bs->breakpoint_at, if this
-            location is no longer used by the watchpoint.  Prevent
-            further code from trying to use it.  */
+         update_watchpoint (bs->breakpoint_at->owner, 0 /* don't reparse. */);
+         /* Updating watchpoints invalidates bs->breakpoint_at.
+            Prevent further code from trying to use it.  */
          bs->breakpoint_at = NULL;
          need_remove_insert = 1;
        }
 
   if (need_remove_insert)
-    {
-      remove_breakpoints ();
-      insert_breakpoints ();
-    }
+    update_global_location_list (1);
 
   return root_bs->next;
 }
@@ -3867,6 +3946,8 @@ bpstat_causes_stop (bpstat bs)
 
 \f
 
+/* Print the LOC location out of the list of B->LOC locations.  */
+
 static void print_breakpoint_location (struct breakpoint *b,
                                       struct bp_location *loc,
                                       char *wrap_indent,
@@ -3874,10 +3955,13 @@ static void print_breakpoint_location (struct breakpoint *b,
 {
   struct cleanup *old_chain = save_current_program_space ();
 
+  if (loc != NULL && loc->shlib_disabled)
+    loc = NULL;
+
   if (loc != NULL)
     set_current_program_space (loc->pspace);
 
-  if (b->source_file)
+  if (b->source_file && loc)
     {
       struct symbol *sym 
        = find_pc_sect_function (loc->address, loc->section);
@@ -3903,15 +3987,14 @@ static void print_breakpoint_location (struct breakpoint *b,
       
       ui_out_field_int (uiout, "line", b->line_number);
     }
-  else if (!b->loc)
+  else if (loc)
     {
-      ui_out_field_string (uiout, "pending", b->addr_string);
-    }
-  else
-    {
-      print_address_symbolic (loc->address, stb->stream, demangle, "");
+      print_address_symbolic (loc->gdbarch, loc->address, stb->stream,
+                             demangle, "");
       ui_out_field_stream (uiout, "at", stb);
     }
+  else
+    ui_out_field_string (uiout, "pending", b->addr_string);
 
   do_cleanups (old_chain);
 }
@@ -4580,21 +4663,28 @@ set_default_breakpoint (int valid, struct program_space *pspace,
    these types to be a duplicate of an actual breakpoint at address zero:
 
       bp_watchpoint
-      bp_hardware_watchpoint
-      bp_read_watchpoint
-      bp_access_watchpoint
-      bp_catchpoint */
+      bp_catchpoint
+
+*/
 
 static int
 breakpoint_address_is_meaningful (struct breakpoint *bpt)
 {
   enum bptype type = bpt->type;
 
-  return (type != bp_watchpoint
-         && type != bp_hardware_watchpoint
-         && type != bp_read_watchpoint
-         && type != bp_access_watchpoint
-         && type != bp_catchpoint);
+  return (type != bp_watchpoint && type != bp_catchpoint);
+}
+
+/* Assuming LOC1 and LOC2's owners are hardware watchpoints, returns
+   true if LOC1 and LOC2 represent the same watchpoint location.  */
+
+static int
+watchpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
+{
+  return (loc1->owner->type == loc2->owner->type
+         && loc1->pspace->aspace == loc2->pspace->aspace
+         && loc1->address == loc2->address
+         && loc1->length == loc2->length);
 }
 
 /* Returns true if {ASPACE1,ADDR1} and {ASPACE2,ADDR2} represent the
@@ -4611,6 +4701,25 @@ breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
          && addr1 == addr2);
 }
 
+/* Assuming LOC1 and LOC2's types' have meaningful target addresses
+   (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
+   represent the same location.  */
+
+static int
+breakpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
+{
+  int hw_point1 = is_hardware_watchpoint (loc1->owner);
+  int hw_point2 = is_hardware_watchpoint (loc2->owner);
+
+  if (hw_point1 != hw_point2)
+    return 0;
+  else if (hw_point1)
+    return watchpoint_locations_match (loc1, loc2);
+  else
+    return breakpoint_address_match (loc1->pspace->aspace, loc1->address,
+                                    loc2->pspace->aspace, loc2->address);
+}
+
 static void
 breakpoint_adjustment_warning (CORE_ADDR from_addr, CORE_ADDR to_addr,
                                int bnum, int have_bnum)
@@ -6251,13 +6360,14 @@ expand_line_sal_maybe (struct symtab_and_line sal)
 
   if (expanded.nelts == 1)
     {
-      /* We had one sal, we got one sal.  Without futher
-        processing, just return the original sal.  */
+      /* We had one sal, we got one sal.  Return that sal, adjusting it
+         past the function prologue if necessary.  */
       xfree (expanded.sals);
       expanded.nelts = 1;
       expanded.sals = xmalloc (sizeof (struct symtab_and_line));
       sal.pc = original_pc;
       expanded.sals[0] = sal;
+      skip_prologue_sal (&expanded.sals[0]);
       do_cleanups (old_chain);
       return expanded;      
     }
@@ -6546,7 +6656,7 @@ find_condition_and_thread (char *tok, CORE_ADDR pc,
          if (tok == tmptok)
            error (_("Junk after task keyword."));
          if (!valid_task_id (*task))
-           error (_("Unknown task %d\n"), *task);
+           error (_("Unknown task %d."), *task);
        }
       else
        error (_("Junk at end of arguments."));
@@ -6992,7 +7102,6 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
 {
   struct gdbarch *gdbarch = get_current_arch ();
   struct breakpoint *b, *scope_breakpoint = NULL;
-  struct symtab_and_line sal;
   struct expression *exp;
   struct block *exp_valid_block;
   struct value *val, *mark;
@@ -7003,14 +7112,11 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   int toklen;
   char *cond_start = NULL;
   char *cond_end = NULL;
-  struct expression *cond = NULL;
   int i, other_type_used, target_resources_ok = 0;
   enum bptype bp_type;
   int mem_cnt = 0;
   int thread = -1;
 
-  init_sal (&sal);             /* initialize to zeroes */
-
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
@@ -7072,8 +7178,6 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
         }
     }
 
-  sal.pspace = current_program_space;
-
   /* Parse the rest of the arguments.  */
   innermost_block = NULL;
   exp_start = arg;
@@ -7102,8 +7206,11 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   toklen = end_tok - tok;
   if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
     {
+      struct expression *cond;
+
       tok = cond_start = end_tok + 1;
       cond = parse_exp_1 (&tok, 0, 0);
+      xfree (cond);
       cond_end = tok;
     }
   if (*tok)
@@ -7173,7 +7280,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
     }
 
   /* Now set up the breakpoint.  */
-  b = set_raw_breakpoint (gdbarch, sal, bp_type);
+  b = set_raw_breakpoint_without_location (NULL, bp_type);
   set_breakpoint_count (breakpoint_count + 1);
   b->number = breakpoint_count;
   b->thread = thread;
@@ -7183,16 +7290,21 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
   b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
-  b->loc->cond = cond;
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
   else
     b->cond_string = 0;
 
   if (frame)
-    b->watchpoint_frame = get_frame_id (frame);
+    {
+      b->watchpoint_frame = get_frame_id (frame);
+      b->watchpoint_thread = inferior_ptid;
+    }
   else
-    b->watchpoint_frame = null_frame_id;
+    {
+      b->watchpoint_frame = null_frame_id;
+      b->watchpoint_thread = null_ptid;
+    }
 
   if (scope_breakpoint != NULL)
     {
@@ -7203,6 +7315,11 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
     }
 
   value_free_to_mark (mark);
+
+  /* Finally update the new watchpoint.  This creates the locations
+     that should be inserted.  */
+  update_watchpoint (b, 1);
+
   mention (b);
   update_global_location_list (1);
 }
@@ -8112,15 +8229,17 @@ breakpoint_auto_delete (bpstat bs)
   }
 }
 
-/* A comparison function for bp_location A and B being interfaced to qsort.
+/* A comparison function for bp_location AP and BP being interfaced to qsort.
    Sort elements primarily by their ADDRESS (no matter what does
    breakpoint_address_is_meaningful say for its OWNER), secondarily by ordering
    first bp_permanent OWNERed elements and terciarily just ensuring the array
    is sorted stable way despite qsort being an instable algorithm.  */
 
 static int
-bp_location_compare (struct bp_location *a, struct bp_location *b)
+bp_location_compare (const void *ap, const void *bp)
 {
+  struct bp_location *a = *(void **) ap;
+  struct bp_location *b = *(void **) bp;
   int a_perm = a->owner->enable_state == bp_permanent;
   int b_perm = b->owner->enable_state == bp_permanent;
 
@@ -8141,17 +8260,6 @@ bp_location_compare (struct bp_location *a, struct bp_location *b)
   return (a > b) - (a < b);
 }
 
-/* Interface bp_location_compare as the COMPAR parameter of qsort function.  */
-
-static int
-bp_location_compare_for_qsort (const void *ap, const void *bp)
-{
-  struct bp_location *a = *(void **) ap;
-  struct bp_location *b = *(void **) bp;
-
-  return bp_location_compare (a, b);
-}
-
 /* Set bp_location_placed_address_before_address_max and
    bp_location_shadow_len_after_address_max according to the current content of
    the bp_location array.  */
@@ -8210,9 +8318,16 @@ update_global_location_list (int should_insert)
   struct bp_location **locp, *loc;
   struct cleanup *cleanups;
 
-  /* The first bp_location being the only one non-DUPLICATE for the current run
-     of the same ADDRESS.  */
-  struct bp_location *loc_first;
+  /* Used in the duplicates detection below.  When iterating over all
+     bp_locations, points to the first bp_location of a given address.
+     Breakpoints and watchpoints of different types are never
+     duplicates of each other.  Keep one pointer for each type of
+     breakpoint/watchpoint, so we only need to loop over all locations
+     once.  */
+  struct bp_location *bp_loc_first;  /* breakpoint */
+  struct bp_location *wp_loc_first;  /* hardware watchpoint */
+  struct bp_location *awp_loc_first; /* access watchpoint */
+  struct bp_location *rwp_loc_first; /* read watchpoint */
 
   /* Saved former bp_location array which we compare against the newly built
      bp_location from the current state of ALL_BREAKPOINTS.  */
@@ -8235,7 +8350,7 @@ update_global_location_list (int should_insert)
     for (loc = b->loc; loc; loc = loc->next)
       *locp++ = loc;
   qsort (bp_location, bp_location_count, sizeof (*bp_location),
-        bp_location_compare_for_qsort);
+        bp_location_compare);
 
   bp_location_target_extensions_update ();
 
@@ -8311,10 +8426,7 @@ update_global_location_list (int should_insert)
                    {
                      struct bp_location *loc2 = *loc2p;
 
-                     if (breakpoint_address_match (loc2->pspace->aspace,
-                                                   loc2->address,
-                                                   old_loc->pspace->aspace,
-                                                   old_loc->address))
+                     if (breakpoint_locations_match (loc2, old_loc))
                        {
                          /* For the sake of should_be_inserted.
                             Duplicates check below will fix up this later.  */
@@ -8411,17 +8523,24 @@ update_global_location_list (int should_insert)
        }
     }
 
-  /* Rescan breakpoints at the same address and section,
-     marking the first one as "first" and any others as "duplicates".
-     This is so that the bpt instruction is only inserted once.
-     If we have a permanent breakpoint at the same place as BPT, make
-     that one the official one, and the rest as duplicates.  Permanent
-     breakpoints are sorted first for the same address.  */
+  /* Rescan breakpoints at the same address and section, marking the
+     first one as "first" and any others as "duplicates".  This is so
+     that the bpt instruction is only inserted once.  If we have a
+     permanent breakpoint at the same place as BPT, make that one the
+     official one, and the rest as duplicates.  Permanent breakpoints
+     are sorted first for the same address.
 
-  loc_first = NULL;
+     Do the same for hardware watchpoints, but also considering the
+     watchpoint's type (regular/access/read) and length.  */
+
+  bp_loc_first = NULL;
+  wp_loc_first = NULL;
+  awp_loc_first = NULL;
+  rwp_loc_first = NULL;
   ALL_BP_LOCATIONS (loc, locp)
     {
       struct breakpoint *b = loc->owner;
+      struct bp_location **loc_first_p;
 
       if (b->enable_state == bp_disabled
          || b->enable_state == bp_call_disabled
@@ -8437,21 +8556,28 @@ update_global_location_list (int should_insert)
                        _("allegedly permanent breakpoint is not "
                        "actually inserted"));
 
-      if (loc_first == NULL
-         || (overlay_debugging && loc->section != loc_first->section)
-         || !breakpoint_address_match (loc->pspace->aspace, loc->address,
-                                       loc_first->pspace->aspace,
-                                       loc_first->address))
+      if (b->type == bp_hardware_watchpoint)
+       loc_first_p = &wp_loc_first;
+      else if (b->type == bp_read_watchpoint)
+       loc_first_p = &rwp_loc_first;
+      else if (b->type == bp_access_watchpoint)
+       loc_first_p = &awp_loc_first;
+      else
+       loc_first_p = &bp_loc_first;
+
+      if (*loc_first_p == NULL
+         || (overlay_debugging && loc->section != (*loc_first_p)->section)
+         || !breakpoint_locations_match (loc, *loc_first_p))
        {
-         loc_first = loc;
+         *loc_first_p = loc;
          loc->duplicate = 0;
          continue;
        }
 
       loc->duplicate = 1;
 
-      if (loc_first->owner->enable_state == bp_permanent && loc->inserted
-          && b->enable_state != bp_permanent)
+      if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
+         && b->enable_state != bp_permanent)
        internal_error (__FILE__, __LINE__,
                        _("another breakpoint was inserted on top of "
                        "a permanent breakpoint"));
@@ -9384,6 +9510,35 @@ show_breakpoint_cmd (char *args, int from_tty)
 {
 }
 
+/* Invalidate last known value of any hardware watchpoint if
+   the memory which that value represents has been written to by
+   GDB itself.  */
+
+static void
+invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
+                                     const bfd_byte *data)
+{
+  struct breakpoint *bp;
+
+  ALL_BREAKPOINTS (bp)
+    if (bp->enable_state == bp_enabled
+       && bp->type == bp_hardware_watchpoint
+       && bp->val_valid && bp->val)
+      {
+       struct bp_location *loc;
+
+       for (loc = bp->loc; loc != NULL; loc = loc->next)
+         if (loc->loc_type == bp_loc_hardware_watchpoint
+             && loc->address + loc->length > addr
+             && addr + len > loc->address)
+           {
+             value_free (bp->val);
+             bp->val = NULL;
+             bp->val_valid = 0;
+           }
+      }
+}
+
 /* Use default_breakpoint_'s, or nothing if they aren't valid.  */
 
 struct symtabs_and_lines
@@ -9971,6 +10126,7 @@ _initialize_breakpoint (void)
 
   observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
   observer_attach_inferior_exit (clear_syscall_counts);
+  observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
 
   breakpoint_chain = 0;
   /* Don't bother to call set_breakpoint_count.  $bpnum isn't useful
This page took 0.034537 seconds and 4 git commands to generate.