PR 10450
[deliverable/binutils-gdb.git] / gdb / breakpoint.c
index 4340c5ddf6abd8b21275b8632f974832792d0c5e..1beb45c46f5cd4b323f3ba657af123d29af48a1f 100644 (file)
@@ -3174,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)
@@ -3245,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)
            {
@@ -3306,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
@@ -3549,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)
     {
@@ -3930,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,
@@ -3937,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);
@@ -3966,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);
 }
@@ -9490,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
@@ -10077,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.02844 seconds and 4 git commands to generate.