This is the mail archive of the gdb-patches@sources.redhat.com 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: [RFA]: pending breakpoint support [1/3]


Daniel Jacobowitz wrote:
On Wed, Jan 21, 2004 at 03:52:42PM -0500, Jeff Johnston wrote:

This is the first of the last 3 patches for pending breakpoint support.
This patch adds the actual support.  The other two patches are the
documentation (previously approved, but before code was accepted) and
changes to the testsuite.

This patch accounts for previous comments on the breakpoint code.

Ok to commit?


Sorry, but a number of my comments from last time still apply, and I
have some others.  The concept is looking great now, though!


Actually, I'm the one who's sorry. I worked on a number of these issues but they were strewn about multiple copies. I never finished the multiple parsing issue. Anyway, I have a new and improved patch attached that addresses the issues below. I have included answers to questions below as well.


2004-01-26 Jeff Johnston <jjohnstn@redhat.com>

        * breakpoint.h (struct breakpoint): Add new flag, from_tty,
        and pending fields for pending breakpoint support.
        * breakpoint.c (breakpoint_enabled): Add check for not pending.
        (condition_command): Only parse condition if not a pending
        breakpoint.
        (print_one_breakpoint): Add support for pending breakpoints.
        (describe_other_breakpoints): Add checks to verify we are not
        dealing with pending breakpoints.
        (check_duplicates): Don't check pending breakpoints.
        (set_raw_breakpoint): Initialize pending flag.
        (do_restore_lang_radix_cleanup): New cleanup routine.
        (resolve_pending_breakpoint): New function.
        (re_enable_breakpoints_in_shlibs): Try and resolve any
        pending breakpoints via resolve_pending_breakpoint.
        (mention): Add pending breakpoint support.
        (parse_breakpoint_sals): Add new parameter to pass to
        decode_line_1 to indicate silent errors when files or functions
        are not found.  Change all callers.
        (do_captured_parse_breakpoint): New function.
        (break_command_1): Change prototype to return an rc value and to
        take an optional pending breakpoint pointer.  Support creating
        a pending breakpoint if a "not found" form of error occurs when
        parsing the breakpoint.  Also support resolving an existing pending
        breakpoint and be silent if the resolution fails.
        (create_breakpoints): Change prototype to take pending breakpoint
        pointer.  When resolving a pending breakpoint, use the new pointer
        to provide a conditional or commands added by the end-user.
        (delete_breakpoint): Add appropriate check for pending.
        (breakpoint_re_set_one): Ditto.
        (do_enable_breakpoint): Ditto.



Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.26
diff -u -p -r1.26 breakpoint.h
--- breakpoint.h	6 Nov 2003 18:24:55 -0000	1.26
+++ breakpoint.h	21 Jan 2004 02:34:10 -0000
@@ -385,6 +385,15 @@ struct breakpoint

    /* Methods associated with this breakpoint.  */
    struct breakpoint_ops *ops;
+
+    /* Initial from_tty value.  */
+    int from_tty;
+
+    /* Initial flag value.  */
+    int flag;
+
+    /* Is breakpoint pending on shlib loads?  */
+    int pending;


Can you read this comment and figure out from it what flag is, or even
where to look for more information? I can't. Please indicate where
they come from, and that they are used for pending breakpoints. Something more descriptive than "flag" would be good.



Ok, done.



@@ -3458,7 +3463,15 @@ print_one_breakpoint (struct breakpoint if (addressprint)
{
annotate_field (4);
- ui_out_field_core_addr (uiout, "addr", b->loc->address);
+ if (b->pending)
+ {
+ if (TARGET_ADDR_BIT <= 32)
+ ui_out_field_string (uiout, "addr", "<PENDING> ");
+ else
+ ui_out_field_string (uiout, "addr", "<PENDING> ");
+ }
+ else
+ ui_out_field_core_addr (uiout, "addr", b->loc->address);
}
annotate_field (5);
*last_addr = b->loc->address;


Last time I said:

  I'm curious what effect this will have on MI consumers.  Also, the
  resulting MI output will be somewhat gruesome with the embedded spaces.
  Maybe:
        ui_out_field_string (uiout, "addr", "<PENDING>");
        ui_out_text (uiout, "addr", "  ");
  but I'm not sure that works without testing it.

  The other possible alternative is not outputting addr at all for
  MI-like uiouts.  May be better to do this (more flexible).

I still don't know what to do about the latter, but please try the
former.


The answer appears to be ui_out_spaces() which under mi does nothing and under cli does exactly what I want it to do.



@@ -4288,23 +4316,139 @@ disable_breakpoints_in_shlibs (int silen
  }
}

+struct captured_parse_breakpoint_args
+  {
+    char **arg_p;
+    struct symtabs_and_lines *sals_p;
+    char ***addr_string_p;
+    int *not_found_ptr;
+  };
+
+struct lang_and_radix
+  {
+    enum language lang;
+    int radix;
+  };
+
+/* Cleanup helper routine to restore the current language and
+   input radix.  */
+static void
+do_restore_lang_radix_cleanup (void *old)
+{
+  struct lang_and_radix *p = old;
+  set_language (p->lang);
+  input_radix = p->radix;
+}
+
+/* Try and resolve a pending breakpoint.  */
+static struct breakpoint *
+resolve_pending_breakpoint (struct breakpoint *b)
+{
+  /* Try and reparse the breakpoint in case the shared library
+     is now loaded.  */
+  struct symtabs_and_lines sals;
+  struct symtab_and_line pending_sal;
+  /* Pointers in arg to the start, and one past the end, of the
+     condition.  */


Last time I read this patch I read this comment and said "Huh?"  That
still applies :) What pointers in what arg to the end of what
condition?


I agree. Comment removed.



+ char **cond_string = (char **) NULL;
+ char *copy_arg = b->addr_string;
+ char **addr_string;
+ char *errmsg;
+ struct captured_parse_breakpoint_args parse_args;
+ int rc;
+ int not_found = 0;
+ struct ui_file *old_gdb_stderr;
+ + sals.sals = NULL;
+ sals.nelts = 0;
+ addr_string = NULL;
+ + parse_args.arg_p = &copy_arg;
+ parse_args.sals_p = &sals;
+ parse_args.addr_string_p = &addr_string;
+ parse_args.not_found_ptr = &not_found;
+ + rc = catch_exceptions (uiout, do_captured_parse_breakpoint, + &parse_args, NULL, RETURN_MASK_ALL);
+ + if (rc == GDB_RC_OK)
+ {
+ struct lang_and_radix old_lr;
+ struct cleanup *old_chain;
+ char *arg;
+ struct breakpoint *b1;
+ + printf_filtered ("Pending breakpoint \"%s\" resolved\n", b->addr_string);
+ + /* Set language, input-radix, then reissue breakpoint command. + Ensure the language and input-radix are restored afterwards. */
+ old_lr.lang = current_language->la_language;
+ old_lr.radix = input_radix;
+ old_chain = make_cleanup (do_restore_lang_radix_cleanup, &old_lr);


Thanks for adding the cleanup.


+ + set_language (b->language);
+ input_radix = b->input_radix;
+ break_command_1 (b->addr_string, b->flag, b->from_tty);
+ b1 = breakpoint_chain;
+ while (b1->next)
+ b1 = b1->next;


I would really prefer that you not walk the breakpoint chain looking
for the last breakpoint.


Fixed. I know pass the pending breakpoint along so I don't have to walk the chain anymore.



+ /* If there is condition specified, it should be copied over. */
+ if (b->cond_string)
+ {
+ arg = b->cond_string;
+ b1->cond_string = savestring (arg, strlen (arg));
+ b1->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+ if (*arg)
+ error ("Junk at end of expression");
+ }
+ /* If there are commands associated with the breakpoint, they should + be copied too. */
+ if (b->commands)
+ {
+ b1->commands = copy_command_lines (b->commands);
+ }


No, I've already asked you to do entire section differently:
This, on the other hand, is not OK. First of all you're wasting work -
you parse the breakpoint location twice. Then you go grubbing around
in the breakpoint chain looking for it, which assumes it will be added
at the end of the chain - it will, but that sort of detail shouldn't be
exposed. And break_command_1 can currently create multiple
breakpoints, so you'll get that wrong too.
decode_line_1 can end up prompting the user; you should have a testcase
for that and make sure it does something sane. Easiest way is probably
to put it in gdb.cp using an overloaded function. All set breakpoints
should get the condition and commands.
Can you arrange for most of this function to happen inside
break_command_1, possibly by giving it a pending breakpoint as an
optional argument? Other ideas?


Also, I'm 99% sure you mean b1->loc->address above.  b->loc->address is
the pending breakpoint's address, which is unset.


You are correct about the loc->address. I have implemented your suggestion. The break_command_1 routine now has a return code and takes an optional argument for a pending breakpoint to resolve. It pass the pending breakpoint pointer to the create_breakpoints code so that if multiple breakpoints are created, operations can be done when the breakpoint is created rather than finding them on the list. Anyway, the result is that only one parsing is performed and the breakpoint list does not need to be traversed. The caller can also find out if the breakpoint was successful without having to use a catch.


One minor change is needed to the pending.exp test because of the redesign. Rather than stating the breakpoint is resolved and then showing the new breakpoints, the issuing of the message has been moved to after confirmation of the resolved breakpoints created. It has been slightly reworded as well.

+
+      do_cleanups (old_chain);
+      return b1; /* Pending breakpoint resolved.  */
+    }
+
+  /* Otherwise, we didn't successfully resolve pending breakpoint.  */
+  return NULL;
+}
+
/* Try to reenable any breakpoints in shared libraries.  */
void
re_enable_breakpoints_in_shlibs (void)
{
  struct breakpoint *b;
+  struct breakpoint *del_b = NULL;

  ALL_BREAKPOINTS (b)
+  {
+    if (del_b)
+      {
+	delete_breakpoint (del_b);
+	del_b = NULL;
+      }


I said:
  No, use ALL_BREAKPOINTS_SAFE and you can get rid of del_b.


Agreed, done.



@@ -4923,19 +5094,51 @@ break_command_1 (char *arg, int flag, in
  sals.sals = NULL;
  sals.nelts = 0;
  addr_string = NULL;
-  parse_breakpoint_sals (&arg, &sals, &addr_string);

- if (!sals.nelts)
+ parse_args.arg_p = &arg;
+ parse_args.sals_p = &sals;
+ parse_args.addr_string_p = &addr_string;
+ parse_args.not_found_ptr = &not_found;
+
+ rc = catch_exceptions_with_msg (uiout, do_captured_parse_breakpoint, + &parse_args, NULL, &err_msg, + RETURN_MASK_ALL);


Awesome, the need to play with the text of the error message is gone.


+
+  if (rc != GDB_RC_OK)
+    {
+      /* Check for file or function not found.  */
+      if (not_found)
+	{
+	  error_output_message (NULL, err_msg);
+	  xfree (err_msg);
+	  if (!query ("Make breakpoint pending on future shared library load? "))
+	    return;


I said:
  I'm still not really happy with this wording.  What does that mean?
  Plus, it'll look really out of place if we don't have shared library
  support.

When reading the testsuite diffs I asked:
  Might deferred be a better name for this concept anyway?

Comments?


This is a case of "you can't please everybody all the time". I am certainly happy with it. I wanted to distinguish it from "future-break". The two people who are using it are happy with the terminology. One of them doesn't like the word "deferred" - like I said, you can't please everybody. Anyway, we are dealing with a whopping sampling of 4 people here. The breakpoint is "pending" on a future event - that is certainly true. Yes, it could also be considered "deferred" until a future event. There are multiple choices, I have made my choice "pending". Like all unfamiliar terminology, people get used to it once they know what it is. I am sure there are lots of such instances in gdb - for example, "inferior".


Regarding shared libraries: I chose to spell it out at present because that is the only way such a breakpoint gets resolved. I would imagine that on a platform without shared libraries, a user wouldn't say "y" and if they did, it certainly wouldn't affect them much as it would never occur. You have to remember that this would only occur when the user enters a breakpoint location that doesn't exist. I also mentioned perviously that a future option would be added to make it so the query wouldn't be necessary. The people who use this all the time always want it defaulted and I imagine those that don't have shared libraries never want it on. The first step is to get the base functionality in.


+	  copy_arg = (char *)xmalloc (strlen (addr_start));
+	  strcpy (copy_arg, addr_start);


I said:
  The cast is not necessary nowadays.  There are also a number of
  functions for doing this, which don't suffer from the off-by-one error
  above :)  Try xstrdup instead.


Ok.



+ addr_string = &copy_arg;


I said:
  Is addr_string guaranteed to still be NULL at this point, or are we
  leaking?

The answer to this question is somewhere in the depths of
decode_line_1, so I'm not sure what the answer is.


Well, it only gets there on a "not-found" error from decode_line_1 so the onus is on decode_line_1 and it's children to do proper cleanups which is outside of this patch.



+	  sals.nelts = 1;
+	  sals.sals = &pending_sal;
+	  pending_sal.pc = 0;
+	  pending = 1;
+	}
+      else
+	return;
+    }
+  else if (!sals.nelts)
    return;

+
  /* Create a chain of things that always need to be cleaned up. */
  old_chain = make_cleanup (null_cleanup, 0);

- /* Make sure that all storage allocated to SALS gets freed. */
- make_cleanup (xfree, sals.sals);
-
- /* Cleanup the addr_string array but not its contents. */
- make_cleanup (xfree, addr_string);
+ if (!pending)
+ {
+ /* Make sure that all storage allocated to SALS gets freed. */
+ make_cleanup (xfree, sals.sals);
+ + /* Cleanup the addr_string array but not its contents. */
+ make_cleanup (xfree, addr_string);
+ }


  /* Allocate space for all the cond expressions. */
  cond = xcalloc (sals.nelts, sizeof (struct expression *));


Yes, you don't want to free addr_string, but a few lines further down
you probably want to add a cleanup to free copy_arg on the
breakpoint_chain.


Added, thanks.



@@ -7363,70 +7600,92 @@ do_enable_breakpoint (struct breakpoint error ("Hardware breakpoints used exceeds limit.");
}


- if (bpt->enable_state != bp_permanent)
- bpt->enable_state = bp_enabled;
- bpt->disposition = disposition;
- check_duplicates (bpt);
- breakpoints_changed ();
-
- if (bpt->type == bp_watchpoint || - bpt->type == bp_hardware_watchpoint ||
- bpt->type == bp_read_watchpoint || - bpt->type == bp_access_watchpoint)
- {
- if (bpt->exp_valid_block != NULL)
- {
- struct frame_info *fr =
- fr = frame_find_by_id (bpt->watchpoint_frame);
- if (fr == NULL)
+ if (bpt->pending)
+ {
+ if (bpt->enable_state != bp_enabled)
+ {
+ /* When enabling a pending breakpoint, we need to check if the breakpoint
+ is resolvable since shared libraries could have been loaded
+ after the breakpoint was disabled. */
+ struct breakpoint *new_bp;
+ breakpoints_changed ();


I said:
  Sure this is necessary?  If we resolve the breakpoint successfully,
  this will get called from set_raw_breakpoint.


It is necessary because when we aren't successful, the breakpoint status will still change from disabled to enabled but we won't have created a new breakpoint.



+ if ((new_bp = resolve_pending_breakpoint (bpt)) != NULL)


I said:
  Might as well not use assignment-in-if-statement in new code.

I think this is in the ARI.


Fixed.



Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.26
diff -u -p -r1.26 breakpoint.h
--- breakpoint.h	6 Nov 2003 18:24:55 -0000	1.26
+++ breakpoint.h	27 Jan 2004 19:50:31 -0000
@@ -385,6 +385,17 @@ struct breakpoint
 
     /* Methods associated with this breakpoint.  */
     struct breakpoint_ops *ops;
+
+    /* Was breakpoint issued from a tty?  Saved for the use of pending breakpoints.  */
+    int from_tty;
+
+    /* Flag value for pending breakpoint.
+       first bit  : 0 non-temporary, 1 temporary.
+       second bit : 0 normal breakpoint, 1 hardware breakpoint. */
+    int flag;
+
+    /* Is breakpoint pending on shlib loads?  */
+    int pending;
   };
 
 /* The following stuff is an abstract data type "bpstat" ("breakpoint
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.151
diff -u -p -r1.151 breakpoint.c
--- breakpoint.c	27 Jan 2004 03:13:34 -0000	1.151
+++ breakpoint.c	27 Jan 2004 19:50:31 -0000
@@ -89,7 +89,7 @@ extern void break_at_finish_at_depth_com
 
 extern void tbreak_at_finish_command (char *, int);
 
-static void break_command_1 (char *, int, int);
+static int break_command_1 (char *, int, int, struct breakpoint *);
 
 static void mention (struct breakpoint *);
 
@@ -119,6 +119,8 @@ static void condition_command (char *, i
 
 static int get_number_trailer (char **, int);
 
+static int do_captured_parse_breakpoint (struct ui_out *, void *);
+
 void set_breakpoint_count (int);
 
 typedef enum
@@ -322,7 +324,7 @@ int exception_support_initialized = 0;
 static int
 breakpoint_enabled (struct breakpoint *b)
 {
-  return b->enable_state == bp_enabled;
+  return (b->enable_state == bp_enabled && !b->pending);
 }
 
 /* Set breakpoint count to NUM.  */
@@ -556,9 +558,12 @@ condition_command (char *arg, int from_t
 	  /* I don't know if it matters whether this is the string the user
 	     typed in or the decompiled expression.  */
 	  b->cond_string = savestring (arg, strlen (arg));
-	  b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
-	  if (*arg)
-	    error ("Junk at end of expression");
+	  if (!b->pending)
+	    {
+	      b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+	      if (*arg)
+		error ("Junk at end of expression");
+	    }
 	}
       breakpoints_changed ();
       breakpoint_modify_event (b->number);
@@ -3451,7 +3456,16 @@ print_one_breakpoint (struct breakpoint 
 	if (addressprint)
 	  {
 	    annotate_field (4);
-	    ui_out_field_core_addr (uiout, "addr", b->loc->address);
+	    if (b->pending)
+	      {
+		ui_out_field_string (uiout, "addr", "<PENDING>");
+		if (TARGET_ADDR_BIT <= 32)
+		  ui_out_spaces (uiout, 2);
+		else
+		  ui_out_spaces (uiout, 8);
+	      }
+	    else
+	      ui_out_field_core_addr (uiout, "addr", b->loc->address);
 	  }
 	annotate_field (5);
 	*last_addr = b->loc->address;
@@ -3470,6 +3484,10 @@ print_one_breakpoint (struct breakpoint 
 	    ui_out_text (uiout, ":");
 	    ui_out_field_int (uiout, "line", b->line_number);
 	  }
+	else if (b->pending)
+	  {
+	    ui_out_field_string (uiout, "pending", b->addr_string);
+	  }
 	else
 	  {
 	    print_address_symbolic (b->loc->address, stb->stream, demangle, "");
@@ -3506,7 +3524,15 @@ print_one_breakpoint (struct breakpoint 
       ui_out_field_stream (uiout, "cond", stb);
       ui_out_text (uiout, "\n");
     }
-  
+
+  if (b->pending && b->cond_string)
+    {
+      annotate_field (7);
+      ui_out_text (uiout, "\tstop only if ");
+      ui_out_field_string (uiout, "cond", b->cond_string);
+      ui_out_text (uiout, "\n");
+    }
+
   if (b->thread != -1)
     {
       /* FIXME should make an annotation for this */
@@ -3737,14 +3763,14 @@ describe_other_breakpoints (CORE_ADDR pc
 
   ALL_BREAKPOINTS (b)
     if (b->loc->address == pc)	/* address match / overlay match */
-      if (!overlay_debugging || b->loc->section == section)
+      if (!b->pending && (!overlay_debugging || b->loc->section == section))
 	others++;
   if (others > 0)
     {
       printf_filtered ("Note: breakpoint%s ", (others > 1) ? "s" : "");
       ALL_BREAKPOINTS (b)
 	if (b->loc->address == pc)	/* address match / overlay match */
-	  if (!overlay_debugging || b->loc->section == section)
+	  if (!b->pending && (!overlay_debugging || b->loc->section == section))
 	    {
 	      others--;
 	      printf_filtered ("%d%s%s ",
@@ -3833,6 +3859,7 @@ check_duplicates (struct breakpoint *bpt
   ALL_BP_LOCATIONS (b)
     if (b->owner->enable_state != bp_disabled
 	&& b->owner->enable_state != bp_shlib_disabled
+	&& !b->owner->pending
 	&& b->owner->enable_state != bp_call_disabled
 	&& b->address == address	/* address / overlay match */
 	&& (!overlay_debugging || b->section == section)
@@ -3867,6 +3894,7 @@ check_duplicates (struct breakpoint *bpt
 	  {
 	    if (b->owner->enable_state != bp_disabled
 		&& b->owner->enable_state != bp_shlib_disabled
+		&& !b->owner->pending
 		&& b->owner->enable_state != bp_call_disabled
 		&& b->address == address	/* address / overlay match */
 		&& (!overlay_debugging || b->section == section)
@@ -4043,6 +4071,7 @@ set_raw_breakpoint (struct symtab_and_li
   b->forked_inferior_pid = 0;
   b->exec_pathname = NULL;
   b->ops = NULL;
+  b->pending = 0;
 
   /* Add this breakpoint to the end of the chain
      so that a list of breakpoints will come out in order
@@ -4281,23 +4310,90 @@ disable_breakpoints_in_shlibs (int silen
   }
 }
 
+struct captured_parse_breakpoint_args
+  {
+    char **arg_p;
+    struct symtabs_and_lines *sals_p;
+    char ***addr_string_p;
+    int *not_found_ptr;
+  };
+
+struct lang_and_radix
+  {
+    enum language lang;
+    int radix;
+  };
+
+/* Cleanup helper routine to restore the current language and
+   input radix.  */
+static void
+do_restore_lang_radix_cleanup (void *old)
+{
+  struct lang_and_radix *p = old;
+  set_language (p->lang);
+  input_radix = p->radix;
+}
+
+/* Try and resolve a pending breakpoint.  */
+static int
+resolve_pending_breakpoint (struct breakpoint *b)
+{
+  /* Try and reparse the breakpoint in case the shared library
+     is now loaded.  */
+  struct symtabs_and_lines sals;
+  struct symtab_and_line pending_sal;
+  char **cond_string = (char **) NULL;
+  char *copy_arg = b->addr_string;
+  char **addr_string;
+  char *errmsg;
+  int rc;
+  int not_found = 0;
+  struct ui_file *old_gdb_stderr;
+  struct lang_and_radix old_lr;
+  struct cleanup *old_chain;
+  
+  /* Set language, input-radix, then reissue breakpoint command. 
+     Ensure the language and input-radix are restored afterwards.  */
+  old_lr.lang = current_language->la_language;
+  old_lr.radix = input_radix;
+  old_chain = make_cleanup (do_restore_lang_radix_cleanup, &old_lr);
+  
+  set_language (b->language);
+  input_radix = b->input_radix;
+  rc = break_command_1 (b->addr_string, b->flag, b->from_tty, b);
+  
+  if (rc == GDB_RC_OK)
+    /* Pending breakpoint has been resolved.  */
+    printf_filtered ("Resolves pending breakpoint \"%s\"\n", b->addr_string);
+
+  do_cleanups (old_chain);
+  return rc;
+}
+
 /* Try to reenable any breakpoints in shared libraries.  */
 void
 re_enable_breakpoints_in_shlibs (void)
 {
-  struct breakpoint *b;
+  struct breakpoint *b, *tmp;
 
-  ALL_BREAKPOINTS (b)
+  ALL_BREAKPOINTS_SAFE (b, tmp)
+  {
     if (b->enable_state == bp_shlib_disabled)
-    {
-      char buf[1], *lib;
-
-      /* Do not reenable the breakpoint if the shared library
-         is still not mapped in.  */
-      lib = PC_SOLIB (b->loc->address);
-      if (lib != NULL && target_read_memory (b->loc->address, buf, 1) == 0)
-	b->enable_state = bp_enabled;
-    }
+      {
+	char buf[1], *lib;
+	
+	/* Do not reenable the breakpoint if the shared library
+	   is still not mapped in.  */
+	lib = PC_SOLIB (b->loc->address);
+	if (lib != NULL && target_read_memory (b->loc->address, buf, 1) == 0)
+	  b->enable_state = bp_enabled;
+      }
+    else if (b->pending && (b->enable_state == bp_enabled))
+      {
+	if (resolve_pending_breakpoint (b) == GDB_RC_OK)
+	  delete_breakpoint (b);
+      }
+  }
 }
 
 #endif
@@ -4709,14 +4805,21 @@ mention (struct breakpoint *b)
 
   if (say_where)
     {
-      if (addressprint || b->source_file == NULL)
+      if (b->pending)
 	{
-	  printf_filtered (" at ");
-	  print_address_numeric (b->loc->address, 1, gdb_stdout);
+	  printf_filtered (" (%s) pending.", b->addr_string);
+	}
+      else
+	{
+	  if (addressprint || b->source_file == NULL)
+	    {
+	      printf_filtered (" at ");
+	      print_address_numeric (b->loc->address, 1, gdb_stdout);
+	    }
+	  if (b->source_file)
+	    printf_filtered (": file %s, line %d.",
+			     b->source_file, b->line_number);
 	}
-      if (b->source_file)
-	printf_filtered (": file %s, line %d.",
-			 b->source_file, b->line_number);
     }
   do_cleanups (old_chain);
   if (ui_out_is_mi_like_p (uiout))
@@ -4729,6 +4832,11 @@ mention (struct breakpoint *b)
    SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i],
    COND[i] and COND_STRING[i] values.
 
+   The parameter PENDING_BP points to a pending breakpoint that is
+   the basis of the breakpoints currently being created.  The pending
+   breakpoint may contain a separate condition string or commands
+   that were added after the initial pending breakpoint was created.
+
    NOTE: If the function succeeds, the caller is expected to cleanup
    the arrays ADDR_STRING, COND_STRING, COND and SALS (but not the
    array contents).  If the function fails (error() is called), the
@@ -4739,7 +4847,8 @@ static void
 create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
 		    struct expression **cond, char **cond_string,
 		    enum bptype type, enum bpdisp disposition,
-		    int thread, int ignore_count, int from_tty)
+		    int thread, int ignore_count, int from_tty,
+		    struct breakpoint *pending_bp)
 {
   if (type == bp_hardware_breakpoint)
     {
@@ -4779,6 +4888,26 @@ create_breakpoints (struct symtabs_and_l
 	b->ignore_count = ignore_count;
 	b->enable_state = bp_enabled;
 	b->disposition = disposition;
+	/* If resolving a pending breakpoint, a check must be made to see if
+	   the user has specified a new condition or commands for the 
+	   breakpoint.  A new condition will override any condition that was 
+	   initially specified with the initial breakpoint command.  */
+	if (pending_bp)
+	  {
+	    char *arg;
+	    if (pending_bp->cond_string)
+	      {
+		arg = pending_bp->cond_string;
+		b->cond_string = savestring (arg, strlen (arg));
+		b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+		if (*arg)
+		  error ("Junk at end of pending breakpoint condition expression");
+	      }
+	    /* If there are commands associated with the breakpoint, they should 
+	       be copied too.  */
+	    if (pending_bp->commands)
+	      b->commands = copy_command_lines (pending_bp->commands);
+	  }
 	mention (b);
       }
   }    
@@ -4792,7 +4921,8 @@ create_breakpoints (struct symtabs_and_l
 static void
 parse_breakpoint_sals (char **address,
 		       struct symtabs_and_lines *sals,
-		       char ***addr_string)
+		       char ***addr_string,
+		       int *not_found_ptr)
 {
   char *addr_start = *address;
   *addr_string = NULL;
@@ -4833,9 +4963,11 @@ parse_breakpoint_sals (char **address,
  	      || ((strchr ("+-", (*address)[0]) != NULL)
  		  && ((*address)[1] != '['))))
 	*sals = decode_line_1 (address, 1, default_breakpoint_symtab,
-			       default_breakpoint_line, addr_string, NULL);
+			       default_breakpoint_line, addr_string, 
+			       not_found_ptr);
       else
-	*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0, addr_string, NULL);
+	*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
+		               addr_string, not_found_ptr);
     }
   /* For any SAL that didn't have a canonical string, fill one in. */
   if (sals->nelts > 0 && *addr_string == NULL)
@@ -4889,26 +5021,46 @@ breakpoint_sals_to_pc (struct symtabs_an
     }
 }
 
+static int
+do_captured_parse_breakpoint (struct ui_out *ui, void *data)
+{
+  struct captured_parse_breakpoint_args *args = data;
+  
+  parse_breakpoint_sals (args->arg_p, args->sals_p, args->addr_string_p, 
+		         args->not_found_ptr);
+
+  return GDB_RC_OK;
+}
+
 /* Set a breakpoint according to ARG (function, linenum or *address)
    flag: first bit  : 0 non-temporary, 1 temporary.
-   second bit : 0 normal breakpoint, 1 hardware breakpoint. */
+   second bit : 0 normal breakpoint, 1 hardware breakpoint. 
 
-static void
-break_command_1 (char *arg, int flag, int from_tty)
+   PENDING_BP is non-NULL when this function is being called to resolve
+   a pending breakpoint.  */
+
+static int
+break_command_1 (char *arg, int flag, int from_tty, struct breakpoint *pending_bp)
 {
   int tempflag, hardwareflag;
   struct symtabs_and_lines sals;
   struct expression **cond = 0;
+  struct symtab_and_line pending_sal;
   /* Pointers in arg to the start, and one past the end, of the
      condition.  */
   char **cond_string = (char **) NULL;
+  char *copy_arg;
+  char *err_msg;
   char *addr_start = arg;
   char **addr_string;
   struct cleanup *old_chain;
   struct cleanup *breakpoint_chain = NULL;
-  int i;
+  struct captured_parse_breakpoint_args parse_args;
+  int i, rc;
+  int pending = 0;
   int thread = -1;
   int ignore_count = 0;
+  int not_found = 0;
 
   hardwareflag = flag & BP_HARDWAREFLAG;
   tempflag = flag & BP_TEMPFLAG;
@@ -4916,19 +5068,55 @@ break_command_1 (char *arg, int flag, in
   sals.sals = NULL;
   sals.nelts = 0;
   addr_string = NULL;
-  parse_breakpoint_sals (&arg, &sals, &addr_string);
 
-  if (!sals.nelts)
-    return;
+  parse_args.arg_p = &arg;
+  parse_args.sals_p = &sals;
+  parse_args.addr_string_p = &addr_string;
+  parse_args.not_found_ptr = &not_found;
+
+  rc = catch_exceptions_with_msg (uiout, do_captured_parse_breakpoint, 
+		  		  &parse_args, NULL, &err_msg, 
+				  RETURN_MASK_ALL);
+
+  /* If caller is interested in rc value from parse, set value.  */
+
+  if (rc != GDB_RC_OK)
+    {
+      /* Check for file or function not found.  */
+      if (not_found)
+	{
+	  /* If called to resolve pending breakpoint, just return error code.  */
+	  if (pending_bp)
+	    return rc;
+
+	  error_output_message (NULL, err_msg);
+	  xfree (err_msg);
+	  if (!query ("Make breakpoint pending on future shared library load? "))
+	    return rc;
+	  copy_arg = xstrdup (addr_start);
+	  addr_string = &copy_arg;
+	  sals.nelts = 1;
+	  sals.sals = &pending_sal;
+	  pending_sal.pc = 0;
+	  pending = 1;
+	}
+      else
+	return rc;
+    }
+  else if (!sals.nelts)
+    return GDB_RC_FAIL;
 
   /* Create a chain of things that always need to be cleaned up. */
   old_chain = make_cleanup (null_cleanup, 0);
 
-  /* Make sure that all storage allocated to SALS gets freed.  */
-  make_cleanup (xfree, sals.sals);
-
-  /* Cleanup the addr_string array but not its contents. */
-  make_cleanup (xfree, addr_string);
+  if (!pending)
+    {
+      /* Make sure that all storage allocated to SALS gets freed.  */
+      make_cleanup (xfree, sals.sals);
+      
+      /* Cleanup the addr_string array but not its contents. */
+      make_cleanup (xfree, addr_string);
+    }
 
   /* Allocate space for all the cond expressions. */
   cond = xcalloc (sals.nelts, sizeof (struct expression *));
@@ -4955,62 +5143,94 @@ break_command_1 (char *arg, int flag, in
 
   /* Resolve all line numbers to PC's and verify that the addresses
      are ok for the target.  */
-  breakpoint_sals_to_pc (&sals, addr_start);
+  if (!pending)
+    breakpoint_sals_to_pc (&sals, addr_start);
 
   /* Verify that condition can be parsed, before setting any
      breakpoints.  Allocate a separate condition expression for each
      breakpoint. */
   thread = -1;			/* No specific thread yet */
-  for (i = 0; i < sals.nelts; i++)
+  if (!pending)
     {
-      char *tok = arg;
-      while (tok && *tok)
+      for (i = 0; i < sals.nelts; i++)
 	{
-	  char *end_tok;
-	  int toklen;
-	  char *cond_start = NULL;
-	  char *cond_end = NULL;
-	  while (*tok == ' ' || *tok == '\t')
-	    tok++;
-
-	  end_tok = tok;
-
-	  while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
-	    end_tok++;
-
-	  toklen = end_tok - tok;
-
-	  if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
-	    {
-	      tok = cond_start = end_tok + 1;
-	      cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
-	      make_cleanup (xfree, cond[i]);
-	      cond_end = tok;
-	      cond_string[i] = savestring (cond_start, cond_end - cond_start);
-	      make_cleanup (xfree, cond_string[i]);
-	    }
-	  else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+	  char *tok = arg;
+	  while (tok && *tok)
 	    {
-	      char *tmptok;
-
-	      tok = end_tok + 1;
-	      tmptok = tok;
-	      thread = strtol (tok, &tok, 0);
-	      if (tok == tmptok)
-		error ("Junk after thread keyword.");
-	      if (!valid_thread_id (thread))
-		error ("Unknown thread %d\n", thread);
+	      char *end_tok;
+	      int toklen;
+	      char *cond_start = NULL;
+	      char *cond_end = NULL;
+	      while (*tok == ' ' || *tok == '\t')
+		tok++;
+	      
+	      end_tok = tok;
+	      
+	      while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+		end_tok++;
+	      
+	      toklen = end_tok - tok;
+	      
+	      if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+		{
+		  tok = cond_start = end_tok + 1;
+		  cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 
+				         0);
+		  make_cleanup (xfree, cond[i]);
+		  cond_end = tok;
+		  cond_string[i] = savestring (cond_start, 
+				               cond_end - cond_start);
+		  make_cleanup (xfree, cond_string[i]);
+		}
+	      else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+		{
+		  char *tmptok;
+		  
+		  tok = end_tok + 1;
+		  tmptok = tok;
+		  thread = strtol (tok, &tok, 0);
+		  if (tok == tmptok)
+		    error ("Junk after thread keyword.");
+		  if (!valid_thread_id (thread))
+		    error ("Unknown thread %d\n", thread);
+		}
+	      else
+		error ("Junk at end of arguments.");
 	    }
-	  else
-	    error ("Junk at end of arguments.");
 	}
+      create_breakpoints (sals, addr_string, cond, cond_string,
+			  hardwareflag ? bp_hardware_breakpoint 
+			  : bp_breakpoint,
+			  tempflag ? disp_del : disp_donttouch,
+			  thread, ignore_count, from_tty,
+			  pending_bp);
     }
+  else
+    {
+      struct symtab_and_line sal;
+      struct breakpoint *b;
 
-  create_breakpoints (sals, addr_string, cond, cond_string,
-		      hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
-		      tempflag ? disp_del : disp_donttouch,
-		      thread, ignore_count, from_tty);
+      sal.symtab = NULL;
+      sal.pc = 0;
 
+      make_cleanup (xfree, copy_arg);
+
+      b = set_raw_breakpoint (sal, hardwareflag ? bp_hardware_breakpoint 
+		              : bp_breakpoint);
+      set_breakpoint_count (breakpoint_count + 1);
+      b->number = breakpoint_count;
+      b->cond = *cond;
+      b->thread = thread;
+      b->addr_string = *addr_string;
+      b->cond_string = *cond_string;
+      b->ignore_count = ignore_count;
+      b->pending = 1;
+      b->disposition = tempflag ? disp_del : disp_donttouch;
+      b->from_tty = from_tty;
+      b->flag = flag;
+      mention (b);
+    }
+  
   if (sals.nelts > 1)
     {
       warning ("Multiple breakpoints were set.");
@@ -5021,6 +5241,8 @@ break_command_1 (char *arg, int flag, in
   discard_cleanups (breakpoint_chain);
   /* But cleanup everything else. */
   do_cleanups (old_chain);
+
+  return GDB_RC_OK;
 }
 
 /* Set a breakpoint of TYPE/DISPOSITION according to ARG (function,
@@ -5057,7 +5279,7 @@ do_captured_breakpoint (void *data)
   sals.nelts = 0;
   address_end = args->address;
   addr_string = NULL;
-  parse_breakpoint_sals (&address_end, &sals, &addr_string);
+  parse_breakpoint_sals (&address_end, &sals, &addr_string, 0);
 
   if (!sals.nelts)
     return GDB_RC_NONE;
@@ -5121,7 +5343,8 @@ do_captured_breakpoint (void *data)
   create_breakpoints (sals, addr_string, cond, cond_string,
 		      args->hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
 		      args->tempflag ? disp_del : disp_donttouch,
-		      args->thread, args->ignore_count, 0/*from-tty*/);
+		      args->thread, args->ignore_count, 0/*from-tty*/, 
+		      NULL/*pending_bp*/);
 
   /* That's it. Discard the cleanups for data inserted into the
      breakpoint. */
@@ -5213,7 +5436,7 @@ break_at_finish_at_depth_command_1 (char
 	    addr_string = xstrprintf ("*0x%s %s", paddr_nz (high), extra_args);
 	  else
 	    addr_string = xstrprintf ("*0x%s", paddr_nz (high));
-	  break_command_1 (addr_string, flag, from_tty);
+	  break_command_1 (addr_string, flag, from_tty, NULL);
 	  xfree (addr_string);
 	}
       else
@@ -5296,7 +5519,7 @@ break_at_finish_command_1 (char *arg, in
 				       extra_args);
 	  else
 	    break_string = xstrprintf ("*0x%s", paddr_nz (high));
-	  break_command_1 (break_string, flag, from_tty);
+	  break_command_1 (break_string, flag, from_tty, NULL);
 	  xfree (break_string);
 	}
       else
@@ -5363,7 +5586,7 @@ resolve_sal_pc (struct symtab_and_line *
 void
 break_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, 0, from_tty);
+  break_command_1 (arg, 0, from_tty, NULL);
 }
 
 void
@@ -5381,7 +5604,7 @@ break_at_finish_at_depth_command (char *
 void
 tbreak_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, BP_TEMPFLAG, from_tty);
+  break_command_1 (arg, BP_TEMPFLAG, from_tty, NULL);
 }
 
 void
@@ -5393,13 +5616,13 @@ tbreak_at_finish_command (char *arg, int
 static void
 hbreak_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, BP_HARDWAREFLAG, from_tty);
+  break_command_1 (arg, BP_HARDWAREFLAG, from_tty, NULL);
 }
 
 static void
 thbreak_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty);
+  break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty, NULL);
 }
 
 static void
@@ -5440,7 +5663,7 @@ stopin_command (char *arg, int from_tty)
   if (badInput)
     printf_filtered ("Usage: stop in <function | address>\n");
   else
-    break_command_1 (arg, 0, from_tty);
+    break_command_1 (arg, 0, from_tty, NULL);
 }
 
 static void
@@ -5472,7 +5695,7 @@ stopat_command (char *arg, int from_tty)
   if (badInput)
     printf_filtered ("Usage: stop at <line>\n");
   else
-    break_command_1 (arg, 0, from_tty);
+    break_command_1 (arg, 0, from_tty, NULL);
 }
 
 /* accessflag:  hw_write:  watch write, 
@@ -6679,6 +6902,7 @@ delete_breakpoint (struct breakpoint *bp
 	    && !b->loc->duplicate
 	    && b->enable_state != bp_disabled
 	    && b->enable_state != bp_shlib_disabled
+	    && !b->pending
 	    && b->enable_state != bp_call_disabled)
 	{
 	  int val;
@@ -6884,6 +7108,10 @@ breakpoint_re_set_one (void *bint)
          shlib_disabled breakpoint though.  There's a fair chance we
          can't re-set it if the shared library it's in hasn't been
          loaded yet.  */
+
+      if (b->pending)
+	break;
+
       save_enable = b->enable_state;
       if (b->enable_state != bp_shlib_disabled)
         b->enable_state = bp_disabled;
@@ -7279,70 +7507,92 @@ do_enable_breakpoint (struct breakpoint 
 	error ("Hardware breakpoints used exceeds limit.");
     }
 
-  if (bpt->enable_state != bp_permanent)
-    bpt->enable_state = bp_enabled;
-  bpt->disposition = disposition;
-  check_duplicates (bpt);
-  breakpoints_changed ();
-
-  if (bpt->type == bp_watchpoint || 
-      bpt->type == bp_hardware_watchpoint ||
-      bpt->type == bp_read_watchpoint || 
-      bpt->type == bp_access_watchpoint)
-    {
-      if (bpt->exp_valid_block != NULL)
-	{
-	  struct frame_info *fr =
-	  fr = frame_find_by_id (bpt->watchpoint_frame);
-	  if (fr == NULL)
+  if (bpt->pending)
+    {
+      if (bpt->enable_state != bp_enabled)
+	{
+	  /* When enabling a pending breakpoint, we need to check if the breakpoint
+	     is resolvable since shared libraries could have been loaded
+	     after the breakpoint was disabled.  */
+	  struct breakpoint *new_bp;
+	  breakpoints_changed ();
+ 	  if (resolve_pending_breakpoint (bpt) == GDB_RC_OK)
 	    {
-	      printf_filtered ("\
-Cannot enable watchpoint %d because the block in which its expression\n\
-is valid is not currently in scope.\n", bpt->number);
-	      bpt->enable_state = bp_disabled;
+	      delete_breakpoint (bpt);
 	      return;
 	    }
-
-	  save_selected_frame = deprecated_selected_frame;
-	  save_selected_frame_level = frame_relative_level (deprecated_selected_frame);
-	  select_frame (fr);
+	  bpt->enable_state = bp_enabled;
+	  bpt->disposition = disposition;
 	}
-
-      value_free (bpt->val);
-      mark = value_mark ();
-      bpt->val = evaluate_expression (bpt->exp);
-      release_value (bpt->val);
-      if (VALUE_LAZY (bpt->val))
-	value_fetch_lazy (bpt->val);
-
-      if (bpt->type == bp_hardware_watchpoint ||
-	  bpt->type == bp_read_watchpoint ||
+    }
+  else  /* Not a pending breakpoint.  */
+    {
+      if (bpt->enable_state != bp_permanent)
+	bpt->enable_state = bp_enabled;
+      bpt->disposition = disposition;
+      check_duplicates (bpt);
+      breakpoints_changed ();
+      
+      if (bpt->type == bp_watchpoint || 
+	  bpt->type == bp_hardware_watchpoint ||
+	  bpt->type == bp_read_watchpoint || 
 	  bpt->type == bp_access_watchpoint)
 	{
-	  int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
-	  int mem_cnt = can_use_hardware_watchpoint (bpt->val);
-
-	  /* Hack around 'unused var' error for some targets here */
-	  (void) mem_cnt, i;
-	  target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
-				   bpt->type, i + mem_cnt, other_type_used);
-	  /* we can consider of type is bp_hardware_watchpoint, convert to 
-	     bp_watchpoint in the following condition */
-	  if (target_resources_ok < 0)
+	  if (bpt->exp_valid_block != NULL)
 	    {
-	      printf_filtered ("\
+	      struct frame_info *fr =
+		fr = frame_find_by_id (bpt->watchpoint_frame);
+	      if (fr == NULL)
+		{
+		  printf_filtered ("\
+Cannot enable watchpoint %d because the block in which its expression\n\
+is valid is not currently in scope.\n", bpt->number);
+		  bpt->enable_state = bp_disabled;
+		  return;
+		}
+	      
+	      save_selected_frame = deprecated_selected_frame;
+	      save_selected_frame_level = frame_relative_level (deprecated_selected_frame);
+	      select_frame (fr);
+	    }
+	  
+	  value_free (bpt->val);
+	  mark = value_mark ();
+	  bpt->val = evaluate_expression (bpt->exp);
+	  release_value (bpt->val);
+	  if (VALUE_LAZY (bpt->val))
+	    value_fetch_lazy (bpt->val);
+	  
+	  if (bpt->type == bp_hardware_watchpoint ||
+	      bpt->type == bp_read_watchpoint ||
+	      bpt->type == bp_access_watchpoint)
+	    {
+	      int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
+	      int mem_cnt = can_use_hardware_watchpoint (bpt->val);
+	      
+	      /* Hack around 'unused var' error for some targets here */
+	      (void) mem_cnt, i;
+	      target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
+									bpt->type, i + mem_cnt, other_type_used);
+	      /* we can consider of type is bp_hardware_watchpoint, convert to 
+		 bp_watchpoint in the following condition */
+	      if (target_resources_ok < 0)
+		{
+		  printf_filtered ("\
 Cannot enable watchpoint %d because target watch resources\n\
 have been allocated for other watchpoints.\n", bpt->number);
-	      bpt->enable_state = bp_disabled;
-	      value_free_to_mark (mark);
-	      return;
+		  bpt->enable_state = bp_disabled;
+		  value_free_to_mark (mark);
+		  return;
+		}
 	    }
+	  
+	  if (save_selected_frame_level >= 0)
+	    select_frame (save_selected_frame);
+	  value_free_to_mark (mark);
 	}
-
-      if (save_selected_frame_level >= 0)
-	select_frame (save_selected_frame);
-      value_free_to_mark (mark);
     }
+
   if (modify_breakpoint_hook)
     modify_breakpoint_hook (bpt);
   breakpoint_modify_event (bpt->number);

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