Index: breakpoint.c =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.142 diff -u -r1.142 breakpoint.c --- breakpoint.c 6 Nov 2003 18:35:05 -0000 1.142 +++ breakpoint.c 21 Nov 2003 21:10:33 -0000 @@ -119,6 +119,8 @@ static int get_number_trailer (char **, int); +static int do_captured_parse_breakpoint (void *); + void set_breakpoint_count (int); typedef enum @@ -563,9 +565,12 @@ /* 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); @@ -757,7 +762,7 @@ /* Permanent breakpoints cannot be inserted or removed. Disabled breakpoints should not be inserted. */ - if (bpt->owner->enable_state != bp_enabled) + if (bpt->owner->enable_state != bp_enabled || bpt->owner->pending) return 0; if (bpt->inserted || bpt->duplicate) @@ -1103,7 +1108,7 @@ { /* Permanent breakpoints cannot be inserted or removed. Disabled breakpoints should not be inserted. */ - if (b->owner->enable_state != bp_enabled) + if (b->owner->enable_state != bp_enabled || b->owner->pending) continue; /* FIXME drow/2003-10-07: This code should be pushed elsewhere when @@ -1454,6 +1459,7 @@ } else if (b->loc_type == bp_loc_hardware_watchpoint && b->owner->enable_state == bp_enabled + && !b->owner->pending && !b->duplicate) { struct value *v; @@ -1510,6 +1516,7 @@ b->owner->type == bp_catch_vfork || b->owner->type == bp_catch_exec) && b->owner->enable_state == bp_enabled + && !b->owner->pending && !b->duplicate) { val = -1; @@ -1535,6 +1542,7 @@ else if ((b->owner->type == bp_catch_catch || b->owner->type == bp_catch_throw) && b->owner->enable_state == bp_enabled + && !b->owner->pending && !b->duplicate) { @@ -1546,6 +1554,7 @@ else if (ep_is_exception_catchpoint (b->owner) && b->inserted /* sometimes previous insert doesn't happen */ && b->owner->enable_state == bp_enabled + && !b->owner->pending && !b->duplicate) { @@ -1671,7 +1680,8 @@ && bpt->loc_type != bp_loc_hardware_breakpoint) continue; - if ((bpt->owner->enable_state == bp_enabled + if (((bpt->owner->enable_state == bp_enabled + && !bpt->owner->pending) || bpt->owner->enable_state == bp_permanent) && bpt->address == pc) /* bp is enabled and matches pc */ { @@ -1768,7 +1778,8 @@ && bpt->loc_type != bp_loc_hardware_breakpoint) continue; - if ((bpt->owner->enable_state == bp_enabled + if (((bpt->owner->enable_state == bp_enabled + && !bpt->owner->pending) || bpt->owner->enable_state == bp_permanent) && bpt->address == pc && (bpt->owner->thread == -1 || bpt->owner->thread == thread)) @@ -2572,7 +2583,8 @@ { if (b->enable_state == bp_disabled || b->enable_state == bp_shlib_disabled - || b->enable_state == bp_call_disabled) + || b->enable_state == bp_call_disabled + || b->pending) continue; if (b->type != bp_watchpoint @@ -3175,7 +3187,7 @@ { struct breakpoint *b; ALL_BREAKPOINTS (b) - if (b->enable_state == bp_enabled && b->type == bp_watchpoint) + if (b->enable_state == bp_enabled && !b->pending && b->type == bp_watchpoint) return 1; return 0; } @@ -3186,7 +3198,7 @@ { struct bp_location *bpt; ALL_BP_LOCATIONS (bpt) - if ((bpt->owner->enable_state == bp_enabled) + if ((bpt->owner->enable_state == bp_enabled && !bpt->owner->pending) && bpt->inserted && bpt->loc_type == bp_loc_hardware_watchpoint) return 1; @@ -3454,7 +3466,15 @@ 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", " "); + else + ui_out_field_string (uiout, "addr", " "); + } + else + ui_out_field_core_addr (uiout, "addr", b->loc->address); } annotate_field (5); *last_addr = b->loc->address; @@ -3473,6 +3493,10 @@ 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, ""); @@ -3509,7 +3533,15 @@ 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, "\tpending stop 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 */ @@ -3740,14 +3772,14 @@ 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 ", @@ -3836,6 +3868,7 @@ 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) @@ -3870,6 +3903,7 @@ { 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) @@ -4046,6 +4080,7 @@ 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 @@ -4265,6 +4300,7 @@ if (((b->type == bp_breakpoint) || (b->type == bp_hardware_breakpoint)) && b->enable_state == bp_enabled && + !b->pending && !b->loc->duplicate && PC_SOLIB (b->loc->address)) { @@ -4284,22 +4320,104 @@ } } +struct captured_parse_breakpoint_args + { + char **arg_p; + struct symtabs_and_lines *sals_p; + char ***addr_string_p; + }; + /* 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; + if (b == NULL) + break; + } if (b->enable_state == bp_shlib_disabled) - { - char buf[1]; + { + char buf[1]; + + /* Do not reenable the breakpoint if the shared library + is still not mapped in. */ + if (target_read_memory (b->loc->address, buf, 1) == 0) + b->enable_state = bp_enabled; + } + else if (b->pending && (b->enable_state == bp_enabled)) + { + /* 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. */ + char **cond_string = (char **) NULL; + char *copy_arg = b->addr_string; + char **addr_string; + struct captured_parse_breakpoint_args parse_args; + int rc; + struct ui_file *old_gdb_stderr; + + sals.sals = NULL; + sals.nelts = 0; + addr_string = NULL; + + parse_args.arg_p = ©_arg; + parse_args.sals_p = &sals; + parse_args.addr_string_p = &addr_string; - /* Do not reenable the breakpoint if the shared library - is still not mapped in. */ - if (target_read_memory (b->loc->address, buf, 1) == 0) - b->enable_state = bp_enabled; - } + old_gdb_stderr = gdb_stderr; + gdb_stderr = ui_file_new (); + + rc = catch_errors (do_captured_parse_breakpoint, &parse_args, + NULL, RETURN_MASK_ALL); + + ui_file_delete (gdb_stderr); + gdb_stderr = old_gdb_stderr; + + if (rc == GDB_RC_OK) + { + enum language old_language = current_language->la_language; + int old_input_radix = input_radix; + char *arg; + struct breakpoint *b1; + + printf_filtered ("Pending breakpoint <%s> resolved\n", b->addr_string); + + /* Set language, input-radix, then reissue breakpoint command. Following the + command, restore the language and input-radix. */ + 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; + 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"); + } + set_language (old_language); + input_radix = old_input_radix; + del_b = b; /* Delete on next pass. */ + } + } + } + + if (del_b) + delete_breakpoint (del_b); } #endif @@ -4486,7 +4604,7 @@ *other_type_used = 0; ALL_BREAKPOINTS (b) { - if (b->enable_state == bp_enabled) + if (b->enable_state == bp_enabled && !b->pending) { if (b->type == type) i++; @@ -4712,14 +4830,21 @@ 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)) @@ -4892,6 +5017,16 @@ } } +static int +do_captured_parse_breakpoint (void *data) +{ + struct captured_parse_breakpoint_args *args = data; + + parse_breakpoint_sals (args->arg_p, args->sals_p, args->addr_string_p); + + 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. */ @@ -4902,14 +5037,18 @@ 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 *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; @@ -4919,19 +5058,40 @@ 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; + + rc = catch_errors (do_captured_parse_breakpoint, &parse_args, + NULL, RETURN_MASK_ALL); + + if (rc != GDB_RC_OK) + { + if (!query ("Make breakpoint pending? ")) + return; + copy_arg = (char *)xmalloc (strlen (addr_start)); + strcpy (copy_arg, addr_start); + addr_string = ©_arg; + sals.nelts = 1; + sals.sals = &pending_sal; + pending_sal.pc = 0; + pending = 1; + } + 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 *)); @@ -4958,62 +5118,87 @@ /* 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) + char *tok = arg; + while (tok && *tok) { - 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); + 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); } + 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; + 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."); @@ -6759,6 +6944,7 @@ && !b->loc->duplicate && b->enable_state != bp_disabled && b->enable_state != bp_shlib_disabled + && !b->pending && b->enable_state != bp_call_disabled) { int val; @@ -6964,8 +7150,12 @@ 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) + if (b->enable_state != bp_shlib_disabled) b->enable_state = bp_disabled; set_language (b->language); @@ -7058,7 +7248,7 @@ value_free (b->val); b->val = evaluate_expression (b->exp); release_value (b->val); - if (VALUE_LAZY (b->val) && b->enable_state == bp_enabled) + if (VALUE_LAZY (b->val) && b->enable_state == bp_enabled && !b->pending) value_fetch_lazy (b->val); if (b->cond_string != NULL) @@ -7068,7 +7258,7 @@ xfree (b->cond); b->cond = parse_exp_1 (&s, (struct block *) 0, 0); } - if (b->enable_state == bp_enabled) + if (b->enable_state == bp_enabled && !b->pending) mention (b); value_free_to_mark (mark); break; Index: breakpoint.h =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.h,v retrieving revision 1.26 diff -u -r1.26 breakpoint.h --- breakpoint.h 6 Nov 2003 18:24:55 -0000 1.26 +++ breakpoint.h 21 Nov 2003 21:10:33 -0000 @@ -158,11 +158,14 @@ automatically enabled and reset when the call "lands" (either completes, or stops at another eventpoint). */ - bp_permanent /* There is a breakpoint instruction hard-wired into + bp_permanent, /* There is a breakpoint instruction hard-wired into the target's code. Don't try to write another breakpoint instruction on top of it, or restore its value. Step over it using the architecture's SKIP_INSN macro. */ + bp_shlib_pending, /* The eventpoint could not be set as an shlib has + not yet been loaded the first time. When the + shlib is loaded, it will be reissued. */ }; @@ -385,6 +388,15 @@ /* 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; }; /* The following stuff is an abstract data type "bpstat" ("breakpoint