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; }; /* 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.149 diff -u -p -r1.149 breakpoint.c --- breakpoint.c 17 Jan 2004 21:56:12 -0000 1.149 +++ breakpoint.c 21 Jan 2004 02:34:10 -0000 @@ -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 @@ -326,7 +328,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. */ @@ -560,9 +562,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); @@ -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", " "); + 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; @@ -3477,6 +3490,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, ""); @@ -3513,7 +3530,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 */ @@ -3744,14 +3769,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 ", @@ -3840,6 +3865,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) @@ -3874,6 +3900,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) @@ -4050,6 +4077,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 @@ -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. */ + 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 = ©_arg; + parse_args.sals_p = &sals; + parse_args.addr_string_p = &addr_string; + parse_args.not_found_ptr = ¬_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); + + 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 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); + } + + 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; + } if (b->enable_state == bp_shlib_disabled) - { - char buf[1], *lib; + { + 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) != NULL) + del_b = b; /* Mark pending breakpoint for deletion. */ + } + } - /* 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; - } + if (del_b) + delete_breakpoint (del_b); } #endif @@ -4716,14 +4860,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)) @@ -4799,7 +4950,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; @@ -4840,9 +4992,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) @@ -4896,6 +5050,17 @@ 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. */ @@ -4906,16 +5071,22 @@ break_command_1 (char *arg, int flag, in 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; @@ -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 = ¬_found; + + rc = catch_exceptions_with_msg (uiout, do_captured_parse_breakpoint, + &parse_args, NULL, &err_msg, + RETURN_MASK_ALL); + + 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; + 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 + 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 *)); @@ -4962,62 +5165,91 @@ 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); } + 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."); @@ -5064,7 +5296,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; @@ -6763,6 +6995,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; @@ -6968,6 +7201,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; @@ -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 (); + if ((new_bp = resolve_pending_breakpoint (bpt)) != 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; + 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);