X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fbreakpoint.c;h=2db375340eb137dba18c07a92fc53ee9d945bace;hb=cf3e377e61e7861677252feb4d06ba8fcea1e5c1;hp=678ea2b2857b00a46606bafe4f5582780bc75e30;hpb=359a097f9fac5066bce1f1fc78ff99d61c1d94cc;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 678ea2b285..2db375340e 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -347,7 +347,11 @@ read_memory_nobpt (memaddr, myaddr, len) struct breakpoint *b; if (memory_breakpoint_size < 0) - /* No breakpoints on this machine. */ + /* No breakpoints on this machine. FIXME: This should be + dependent on the debugging target. Probably want + target_insert_breakpoint to return a size, saying how many + bytes of the shadow contents are used, or perhaps have + something like target_xfer_shadow. */ return target_read_memory (memaddr, myaddr, len); ALL_BREAKPOINTS (b) @@ -490,19 +494,18 @@ remove_breakpoints () b->inserted = 0; #ifdef BREAKPOINT_DEBUG printf ("Removed breakpoint at %s", - local_hex_string(b->address)); + local_hex_string((unsigned long) b->address)); printf (", shadow %s", - local_hex_string(b->shadow_contents[0])); + local_hex_string((unsigned long) b->shadow_contents[0])); printf (", %s.\n", - local_hex_string(b->shadow_contents[1])); + local_hex_string((unsigned long) b->shadow_contents[1])); #endif /* BREAKPOINT_DEBUG */ } return 0; } -/* Clear the "inserted" flag in all breakpoints. - This is done when the inferior is loaded. */ +/* Clear the "inserted" flag in all breakpoints. */ void mark_breakpoints_out () @@ -513,6 +516,26 @@ mark_breakpoints_out () b->inserted = 0; } +/* Clear the "inserted" flag in all breakpoints and delete any breakpoints + which should go away between runs of the program. */ + +void +breakpoint_init_inferior () +{ + register struct breakpoint *b, *temp; + + ALL_BREAKPOINTS_SAFE (b, temp) + { + b->inserted = 0; + + /* If the call dummy breakpoint is at the entry point it will + cause problems when the inferior is rerun, so we better + get rid of it. */ + if (b->type == bp_call_dummy) + delete_breakpoint (b); + } +} + /* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at PC. When continuing from a location with a breakpoint, we actually single step once before calling insert_breakpoints. */ @@ -566,7 +589,7 @@ bpstat_copy (bs) { bpstat p = NULL; bpstat tmp; - bpstat retval; + bpstat retval = NULL; if (bs == NULL) return bs; @@ -705,16 +728,6 @@ print_it_normal (bs) || (bs->breakpoint_at->type != bp_breakpoint && bs->breakpoint_at->type != bp_watchpoint)) return 0; - - /* If bpstat_stop_status says don't print, OK, we won't. An example - circumstance is when we single-stepped for both a watchpoint and - for a "stepi" instruction. The bpstat says that the watchpoint - explains the stop, but we shouldn't print because the watchpoint's - value didn't change -- and the real reason we are stopping here - rather than continuing to step (as the watchpoint would've had us do) - is because of the "stepi". */ - if (!bs->print) - return 0; if (bs->breakpoint_at->type == bp_breakpoint) { @@ -766,7 +779,7 @@ bpstat_print (bs) if (bs->next) return bpstat_print (bs->next); - fprintf_filtered (stderr, "gdb internal error: in bpstat_print\n"); + /* We reached the end of the chain without printing anything. */ return 0; } @@ -796,11 +809,125 @@ bpstat_alloc (b, cbs) bs->breakpoint_at = b; /* If the condition is false, etc., don't do the commands. */ bs->commands = NULL; - bs->momentary = b->disposition == delete; bs->old_val = NULL; bs->print_it = print_it_normal; return bs; } + +/* Return the frame which we can use to evaluate the expression + whose valid block is valid_block, or NULL if not in scope. + + This whole concept is probably not the way to do things (it is incredibly + slow being the main reason, not to mention fragile (e.g. the sparc + frame pointer being fetched as 0 bug causes it to stop)). Instead, + introduce a version of "struct frame" which survives over calls to the + inferior, but which is better than FRAME_ADDR in the sense that it lets + us evaluate expressions relative to that frame (on some machines, it + can just be a FRAME_ADDR). Save one of those instead of (or in addition + to) the exp_valid_block, and then use it to evaluate the watchpoint + expression, with no need to do all this backtracing every time. + + Or better yet, what if it just copied the struct frame and its next + frame? Off the top of my head, I would think that would work + because things like (a29k) rsize and msize, or (sparc) bottom just + depend on the frame, and aren't going to be different just because + the inferior has done something. Trying to recalculate them + strikes me as a lot of work, possibly even impossible. Saving the + next frame is needed at least on a29k, where get_saved_register + uses fi->next->saved_msp. For figuring out whether that frame is + still on the stack, I guess this needs to be machine-specific (e.g. + a29k) but I think + + read_fp () INNER_THAN watchpoint_frame->frame + + would generally work. + + Of course the scope of the expression could be less than a whole + function; perhaps if the innermost frame is the one which the + watchpoint is relative to (another machine-specific thing, usually + + FRAMELESS_FUNCTION_INVOCATION (get_current_frame(), fromleaf) + read_fp () == wp_frame->frame + && !fromleaf + + ), *then* it could do a + + contained_in (get_current_block (), wp->exp_valid_block). + + */ + +FRAME +within_scope (valid_block) + struct block *valid_block; +{ + FRAME fr = get_current_frame (); + struct frame_info *fi = get_frame_info (fr); + CORE_ADDR func_start; + + /* If caller_pc_valid is true, we are stepping through + a function prologue, which is bounded by callee_func_start + (inclusive) and callee_prologue_end (exclusive). + caller_pc is the pc of the caller. + + Yes, this is hairy. */ + static int caller_pc_valid = 0; + static CORE_ADDR caller_pc; + static CORE_ADDR callee_func_start; + static CORE_ADDR callee_prologue_end; + + find_pc_partial_function (fi->pc, (PTR)NULL, &func_start, (CORE_ADDR *)NULL); + func_start += FUNCTION_START_OFFSET; + if (fi->pc == func_start) + { + /* We just called a function. The only other case I + can think of where the pc would equal the pc of the + start of a function is a frameless function (i.e. + no prologue) where we branch back to the start + of the function. In that case, SKIP_PROLOGUE won't + find one, and we'll clear caller_pc_valid a few lines + down. */ + caller_pc_valid = 1; + caller_pc = SAVED_PC_AFTER_CALL (fr); + callee_func_start = func_start; + SKIP_PROLOGUE (func_start); + callee_prologue_end = func_start; + } + if (caller_pc_valid) + { + if (fi->pc < callee_func_start + || fi->pc >= callee_prologue_end) + caller_pc_valid = 0; + } + + if (contained_in (block_for_pc (caller_pc_valid + ? caller_pc + : fi->pc), + valid_block)) + { + return fr; + } + fr = get_prev_frame (fr); + + /* If any active frame is in the exp_valid_block, then it's + OK. Note that this might not be the same invocation of + the exp_valid_block that we were watching a little while + ago, or the same one as when the watchpoint was set (e.g. + we are watching a local variable in a recursive function. + When we return from a recursive invocation, then we are + suddenly watching a different instance of the variable). + + At least for now I am going to consider this a feature. */ + for (; fr != NULL; fr = get_prev_frame (fr)) + { + fi = get_frame_info (fr); + if (contained_in (block_for_pc (fi->pc), + valid_block)) + { + return fr; + } + } + return NULL; +} /* Possible return values for watchpoint_check (this can't be an enum because of check_errors). */ @@ -814,23 +941,31 @@ bpstat_alloc (b, cbs) /* Check watchpoint condition. */ static int watchpoint_check (p) - PTR p; + char *p; { bpstat bs = (bpstat) p; + FRAME fr; int within_current_scope; - if (bs->breakpoint_at->exp_valid_block != NULL) - within_current_scope = - contained_in (get_selected_block (), bs->breakpoint_at->exp_valid_block); - else + if (bs->breakpoint_at->exp_valid_block == NULL) within_current_scope = 1; - + else + { + fr = within_scope (bs->breakpoint_at->exp_valid_block); + within_current_scope = fr != NULL; + if (within_current_scope) + /* If we end up stopping, the current frame will get selected + in normal_stop. So this call to select_frame won't affect + the user. */ + select_frame (fr, -1); + } + if (within_current_scope) { /* We use value_{,free_to_}mark because it could be a *long* time before we return to the command level and - call free_all_values. */ - /* But couldn't we just call free_all_values instead? */ + call free_all_values. We can't call free_all_values because + we might be in the middle of evaluating a function call. */ value mark = value_mark (); value new_val = evaluate_expression (bs->breakpoint_at->exp); @@ -872,20 +1007,33 @@ which its expression is valid.\n", bs->breakpoint_at->number); /* This is used when everything which needs to be printed has already been printed. But we still want to print the frame. */ static int -print_it_noop (bs) +print_it_done (bs) bpstat bs; { return 0; } +/* This is used when nothing should be printed for this bpstat entry. */ + +static int +print_it_noop (bs) + bpstat bs; +{ + return -1; +} + +/* Get a bpstat associated with having just stopped at address *PC + and frame address FRAME_ADDRESS. Update *PC to point at the + breakpoint (if we hit a breakpoint). NOT_A_BREAKPOINT is nonzero + if this is known to not be a real breakpoint (it could still be a + watchpoint, though). */ + /* Determine whether we stopped at a breakpoint, etc, or whether we don't understand this stop. Result is a chain of bpstat's such that: if we don't understand the stop, the result is a null pointer. - if we understand why we stopped, the result is not null, and - the first element of the chain contains summary "stop" and - "print" flags for the whole chain. + if we understand why we stopped, the result is not null. Each element of the chain refers to a particular breakpoint or watchpoint at which we have stopped. (We may have stopped for @@ -896,15 +1044,13 @@ print_it_noop (bs) */ - bpstat -bpstat_stop_status (pc, frame_address) +bpstat_stop_status (pc, frame_address, not_a_breakpoint) CORE_ADDR *pc; FRAME_ADDR frame_address; + int not_a_breakpoint; { register struct breakpoint *b; - int stop = 0; - int print = 0; CORE_ADDR bp_addr; #if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) /* True if we've hit a breakpoint (as opposed to a watchpoint). */ @@ -920,21 +1066,21 @@ bpstat_stop_status (pc, frame_address) ALL_BREAKPOINTS (b) { - int this_bp_stop; - int this_bp_print; - if (b->enable == disabled) continue; if (b->type != bp_watchpoint && b->address != bp_addr) continue; + if (b->type != bp_watchpoint && not_a_breakpoint) + continue; + /* Come here if it's a watchpoint, or if the break address matches */ bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */ - this_bp_stop = 1; - this_bp_print = 1; + bs->stop = 1; + bs->print = 1; if (b->type == bp_watchpoint) { @@ -942,11 +1088,12 @@ bpstat_stop_status (pc, frame_address) "Error evaluating expression for watchpoint %d\n"; char message[sizeof (message1) + 30 /* slop */]; sprintf (message, message1, b->number); - switch (catch_errors (watchpoint_check, (char *) bs, message)) + switch (catch_errors (watchpoint_check, (char *) bs, message, + RETURN_MASK_ALL)) { case WP_DISABLED: /* We've already printed what needs to be printed. */ - bs->print_it = print_it_noop; + bs->print_it = print_it_done; /* Stop. */ break; case WP_VALUE_CHANGED: @@ -954,6 +1101,8 @@ bpstat_stop_status (pc, frame_address) break; case WP_VALUE_NOT_CHANGED: /* Don't stop. */ + bs->print_it = print_it_noop; + bs->stop = 0; continue; default: /* Can't happen. */ @@ -963,7 +1112,7 @@ bpstat_stop_status (pc, frame_address) b->enable = disabled; printf_filtered ("Watchpoint %d disabled.\n", b->number); /* We've already printed what needs to be printed. */ - bs->print_it = print_it_noop; + bs->print_it = print_it_done; /* Stop. */ break; } @@ -974,10 +1123,10 @@ bpstat_stop_status (pc, frame_address) #endif if (b->frame && b->frame != frame_address) - this_bp_stop = 0; + bs->stop = 0; else { - int value_is_zero; + int value_is_zero = 0; if (b->cond) { @@ -986,18 +1135,19 @@ bpstat_stop_status (pc, frame_address) select_frame (get_current_frame (), 0); value_is_zero = catch_errors (breakpoint_cond_eval, (char *)(b->cond), - "Error in testing breakpoint condition:\n"); + "Error in testing breakpoint condition:\n", + RETURN_MASK_ALL); /* FIXME-someday, should give breakpoint # */ free_all_values (); } if (b->cond && value_is_zero) { - this_bp_stop = 0; + bs->stop = 0; } else if (b->ignore_count > 0) { b->ignore_count--; - this_bp_stop = 0; + bs->stop = 0; } else { @@ -1006,48 +1156,195 @@ bpstat_stop_status (pc, frame_address) b->enable = disabled; bs->commands = b->commands; if (b->silent) - this_bp_print = 0; + bs->print = 0; if (bs->commands && STREQ ("silent", bs->commands->line)) { bs->commands = bs->commands->next; - this_bp_print = 0; + bs->print = 0; } } } - if (this_bp_stop) - stop = 1; - if (this_bp_print) - print = 1; + /* 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; } bs->next = NULL; /* Terminate the chain */ bs = root_bs->next; /* Re-grab the head of the chain */ +#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) if (bs) { - bs->stop = stop; - bs->print = print; -#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) if (real_breakpoint) { *pc = bp_addr; #if defined (SHIFT_INST_REGS) - { - CORE_ADDR pc = read_register (PC_REGNUM); - CORE_ADDR npc = read_register (NPC_REGNUM); - if (pc != npc) - { - write_register (NNPC_REGNUM, npc); - write_register (NPC_REGNUM, pc); - } - } + SHIFT_INST_REGS(); #else /* No SHIFT_INST_REGS. */ write_pc (bp_addr); #endif /* No SHIFT_INST_REGS. */ } -#endif /* DECR_PC_AFTER_BREAK != 0. */ } +#endif /* DECR_PC_AFTER_BREAK != 0. */ return bs; } + +/* Tell what to do about this bpstat. */ +struct bpstat_what +bpstat_what (bs) + bpstat bs; +{ + /* Classify each bpstat as one of the following. */ + enum class { + /* This bpstat element has no effect on the main_action. */ + no_effect = 0, + + /* There was a watchpoint, stop but don't print. */ + wp_silent, + + /* There was a watchpoint, stop and print. */ + wp_noisy, + + /* There was a breakpoint but we're not stopping. */ + bp_nostop, + + /* There was a breakpoint, stop but don't print. */ + bp_silent, + + /* There was a breakpoint, stop and print. */ + bp_noisy, + + /* We hit the longjmp breakpoint. */ + long_jump, + + /* We hit the longjmp_resume breakpoint. */ + long_resume, + + /* This is just used to count how many enums there are. */ + class_last + }; + + /* Here is the table which drives this routine. So that we can + format it pretty, we define some abbreviations for the + enum bpstat_what codes. */ +#define keep_c BPSTAT_WHAT_KEEP_CHECKING +#define stop_s BPSTAT_WHAT_STOP_SILENT +#define stop_n BPSTAT_WHAT_STOP_NOISY +#define single BPSTAT_WHAT_SINGLE +#define setlr BPSTAT_WHAT_SET_LONGJMP_RESUME +#define clrlr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME +#define clrlrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE +/* "Can't happen." Might want to print an error message. + abort() is not out of the question, but chances are GDB is just + a bit confused, not unusable. */ +#define err BPSTAT_WHAT_STOP_NOISY + + /* Given an old action and a class, come up with a new action. */ + /* One interesting property of this table is that wp_silent is the same + as bp_silent and wp_noisy is the same as bp_noisy. That is because + after stopping, the check for whether to step over a breakpoint + (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without + reference to how we stopped. We retain separate wp_silent and bp_silent + codes in case we want to change that someday. */ + static const enum bpstat_what_main_action + table[(int)class_last][(int)BPSTAT_WHAT_LAST] = + { + /* old action */ + /* keep_c stop_s stop_n single setlr clrlr clrlrs */ + +/*no_effect*/ {keep_c, stop_s, stop_n, single, setlr , clrlr , clrlrs}, +/*wp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s}, +/*wp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n}, +/*bp_nostop*/ {single, stop_s, stop_n, single, setlr , clrlrs, clrlrs}, +/*bp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s}, +/*bp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n}, +/*long_jump*/ {setlr , stop_s, stop_n, setlr , err , err , err }, +/*long_resume*/ {clrlr , stop_s, stop_n, clrlrs, err , err , err } + }; +#undef keep_c +#undef stop_s +#undef stop_n +#undef single +#undef setlr +#undef clrlr +#undef clrlrs +#undef err + enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING; + struct bpstat_what retval; + + retval.call_dummy = 0; + retval.step_resume = 0; + for (; bs != NULL; bs = bs->next) + { + enum class bs_class = no_effect; + if (bs->breakpoint_at == NULL) + /* I suspect this can happen if it was a momentary breakpoint + which has since been deleted. */ + continue; + switch (bs->breakpoint_at->type) + { + case bp_breakpoint: + case bp_until: + case bp_finish: + if (bs->stop) + { + if (bs->print) + bs_class = bp_noisy; + else + bs_class = bp_silent; + } + else + bs_class = bp_nostop; + break; + case bp_watchpoint: + if (bs->stop) + { + if (bs->print) + bs_class = wp_noisy; + else + bs_class = wp_silent; + } + else + /* There was a watchpoint, but we're not stopping. This requires + no further action. */ + bs_class = no_effect; + break; + case bp_longjmp: + bs_class = long_jump; + break; + case bp_longjmp_resume: + bs_class = long_resume; + break; + case bp_step_resume: +#if 0 + /* Need to temporarily disable this until we can fix the bug + with nexting over a breakpoint with ->stop clear causing + an infinite loop. For now, treat the breakpoint as having + been hit even if the frame is wrong. */ + if (bs->stop) + { +#endif + retval.step_resume = 1; + /* We don't handle this via the main_action. */ + bs_class = no_effect; +#if 0 + } + else + /* It is for the wrong frame. */ + bs_class = bp_nostop; +#endif + break; + case bp_call_dummy: + /* Make sure the action is stop (silent or noisy), so infrun.c + pops the dummy frame. */ + bs_class = bp_silent; + retval.call_dummy = 1; + break; + } + current_action = table[(int)bs_class][(int)current_action]; + } + retval.main_action = current_action; + return retval; +} /* Nonzero if we should step constantly (e.g. watchpoints on machines without hardware support). This isn't related to a specific bpstat, @@ -1078,16 +1375,12 @@ breakpoint_1 (bnum, allflag) CORE_ADDR last_addr = (CORE_ADDR)-1; int found_a_breakpoint = 0; static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint", - "longjmp", "longjmp resume"}; + "longjmp", "longjmp resume", "step resume", + "call dummy" }; static char *bpdisps[] = {"del", "dis", "keep"}; static char bpenables[] = "ny"; + char wrap_indent[80]; - if (!breakpoint_chain) - { - printf_filtered ("No breakpoints or watchpoints.\n"); - return; - } - ALL_BREAKPOINTS (b) if (bnum == -1 || bnum == b->number) @@ -1107,41 +1400,49 @@ breakpoint_1 (bnum, allflag) bptypes[(int)b->type], bpdisps[(int)b->disposition], bpenables[(int)b->enable]); + strcpy (wrap_indent, " "); + if (addressprint) + strcat (wrap_indent, " "); switch (b->type) { case bp_watchpoint: print_expression (b->exp, stdout); break; + case bp_breakpoint: case bp_until: case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_step_resume: + case bp_call_dummy: if (addressprint) - printf_filtered ("%s ", local_hex_string_custom(b->address, "08")); + printf_filtered ("%s ", local_hex_string_custom ((unsigned long) b->address, "08l")); last_addr = b->address; - if (b->symtab) + if (b->source_file) { sym = find_pc_function (b->address); if (sym) { fputs_filtered ("in ", stdout); fputs_filtered (SYMBOL_SOURCE_NAME (sym), stdout); + wrap_here (wrap_indent); fputs_filtered (" at ", stdout); } - fputs_filtered (b->symtab->filename, stdout); + fputs_filtered (b->source_file, stdout); printf_filtered (":%d", b->line_number); } else print_address_symbolic (b->address, stdout, demangle, " "); + break; } printf_filtered ("\n"); if (b->frame) printf_filtered ("\tstop only in stack frame at %s\n", - local_hex_string(b->frame)); + local_hex_string((unsigned long) b->frame)); if (b->cond) { printf_filtered ("\tstop only if "); @@ -1160,9 +1461,13 @@ breakpoint_1 (bnum, allflag) } } - if (!found_a_breakpoint - && bnum != -1) - printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum); + if (!found_a_breakpoint) + { + if (bnum == -1) + printf_filtered ("No breakpoints or watchpoints.\n"); + else + printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum); + } else /* Compare against (CORE_ADDR)-1 in case some compiler decides that a comparison of an unsigned with -1 is always false. */ @@ -1226,7 +1531,7 @@ describe_other_breakpoints (pc) (b->enable == disabled) ? " (disabled)" : "", (others > 1) ? "," : ((others == 1) ? " and" : "")); } - printf ("also set at pc %s.\n", local_hex_string(pc)); + printf ("also set at pc %s.\n", local_hex_string((unsigned long) pc)); } } @@ -1287,7 +1592,11 @@ set_raw_breakpoint (sal) b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint)); memset (b, 0, sizeof (*b)); b->address = sal.pc; - b->symtab = sal.symtab; + if (sal.symtab == NULL) + b->source_file = NULL; + else + b->source_file = savestring (sal.symtab->filename, + strlen (sal.symtab->filename)); b->line_number = sal.line; b->enable = enabled; b->next = 0; @@ -1456,15 +1765,16 @@ mention (b) break; case bp_breakpoint: printf_filtered ("Breakpoint %d at %s", b->number, - local_hex_string(b->address)); - if (b->symtab) + local_hex_string((unsigned long) b->address)); + if (b->source_file) printf_filtered (": file %s, line %d.", - b->symtab->filename, b->line_number); + b->source_file, b->line_number); break; case bp_until: case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_step_resume: break; } printf_filtered ("\n"); @@ -1523,11 +1833,14 @@ break_command_1 (arg, tempflag, from_tty) /* Pointers in arg to the start, and one past the end, of the condition. */ char *cond_start = NULL; - char *cond_end; + char *cond_end = NULL; /* Pointers in arg to the start, and one past the end, of the address part. */ char *addr_start = NULL; - char *addr_end; + char *addr_end = NULL; + struct cleanup *old_chain; + struct cleanup *canonical_strings_chain = NULL; + char **canonical = (char **)NULL; int i; @@ -1567,9 +1880,9 @@ break_command_1 (arg, tempflag, from_tty) && (!current_source_symtab || (arg && (*arg == '+' || *arg == '-')))) sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, - default_breakpoint_line); + default_breakpoint_line, &canonical); else - sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0); + sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical); addr_end = arg; } @@ -1577,6 +1890,20 @@ break_command_1 (arg, tempflag, from_tty) if (! sals.nelts) return; + /* Make sure that all storage allocated in decode_line_1 gets freed in case + the following `for' loop errors out. */ + old_chain = make_cleanup (free, sals.sals); + if (canonical != (char **)NULL) + { + make_cleanup (free, canonical); + canonical_strings_chain = make_cleanup (null_cleanup, 0); + for (i = 0; i < sals.nelts; i++) + { + if (canonical[i] != NULL) + make_cleanup (free, canonical[i]); + } + } + /* Resolve all line numbers to PC's, and verify that conditions can be parsed, before setting any breakpoints. */ for (i = 0; i < sals.nelts; i++) @@ -1598,6 +1925,10 @@ break_command_1 (arg, tempflag, from_tty) } } + /* Remove the canonical strings from the cleanup, they are needed below. */ + if (canonical != (char **)NULL) + discard_cleanups (canonical_strings_chain); + /* Now set all the breakpoints. */ for (i = 0; i < sals.nelts; i++) { @@ -1612,11 +1943,11 @@ break_command_1 (arg, tempflag, from_tty) b->type = bp_breakpoint; b->cond = cond; - /* FIXME: We should add the filename if this is a static function - and probably if it is a line number (the line numbers could - have changed when we re-read symbols; possibly better to disable - the breakpoint in that case). */ - if (addr_start) + /* If a canonical line spec is needed use that instead of the + command string. */ + if (canonical != (char **)NULL && canonical[i] != NULL) + b->addr_string = canonical[i]; + else if (addr_start) b->addr_string = savestring (addr_start, addr_end - addr_start); if (cond_start) b->cond_string = savestring (cond_start, cond_end - cond_start); @@ -1632,7 +1963,7 @@ break_command_1 (arg, tempflag, from_tty) printf ("Multiple breakpoints were set.\n"); printf ("Use the \"delete\" command to delete unwanted breakpoints.\n"); } - free ((PTR)sals.sals); + do_cleanups (old_chain); } /* Helper function for break_command_1 and disassemble_command. */ @@ -1732,9 +2063,9 @@ until_break_command (arg, from_tty) if (default_breakpoint_valid) sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, - default_breakpoint_line); + default_breakpoint_line, (char ***)NULL); else - sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0); + sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, (char ***)NULL); if (sals.nelts != 1) error ("Couldn't get information on specified line."); @@ -2010,7 +2341,7 @@ catch_command_1 (arg, tempflag, from_tty) else { /* Grab selected catch clauses. */ - error ("catch NAME not implemeneted"); + error ("catch NAME not implemented"); #if 0 /* This isn't used; I don't know what it was for. */ sals = map_catch_names (arg, catch_breakpoint); @@ -2052,10 +2383,7 @@ catch_command_1 (arg, tempflag, from_tty) b->enable = enabled; b->disposition = tempflag ? delete : donttouch; - printf ("Breakpoint %d at %s", b->number, local_hex_string(b->address)); - if (b->symtab) - printf (": file %s, line %d.", b->symtab->filename, b->line_number); - printf ("\n"); + mention (b); } if (sals.nelts > 1) @@ -2136,8 +2464,12 @@ clear_command (arg, from_tty) sal = sals.sals[i]; found = (struct breakpoint *) 0; while (breakpoint_chain - && (sal.pc ? breakpoint_chain->address == sal.pc - : (breakpoint_chain->symtab == sal.symtab + && (sal.pc + ? breakpoint_chain->address == sal.pc + : (breakpoint_chain->source_file != NULL + && sal.symtab != NULL + && STREQ (breakpoint_chain->source_file, + sal.symtab->filename) && breakpoint_chain->line_number == sal.line))) { b1 = breakpoint_chain; @@ -2149,8 +2481,11 @@ clear_command (arg, from_tty) ALL_BREAKPOINTS (b) while (b->next && b->next->type != bp_watchpoint - && (sal.pc ? b->next->address == sal.pc - : (b->next->symtab == sal.symtab + && (sal.pc + ? b->next->address == sal.pc + : (b->next->source_file != NULL + && sal.symtab != NULL + && STREQ (b->next->source_file, sal.symtab->filename) && b->next->line_number == sal.line))) { b1 = b->next; @@ -2189,7 +2524,8 @@ breakpoint_auto_delete (bs) bpstat bs; { for (; bs; bs = bs->next) - if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete) + if (bs->breakpoint_at && bs->breakpoint_at->disposition == delete + && bs->stop) delete_breakpoint (bs->breakpoint_at); } @@ -2203,7 +2539,7 @@ delete_breakpoint (bpt) register bpstat bs; if (bpt->inserted) - target_remove_breakpoint(bpt->address, bpt->shadow_contents); + target_remove_breakpoint(bpt->address, bpt->shadow_contents); if (breakpoint_chain == bpt) breakpoint_chain = bpt->next; @@ -2216,16 +2552,38 @@ delete_breakpoint (bpt) } check_duplicates (bpt->address); + /* If this breakpoint was inserted, and there is another breakpoint + at the same address, we need to insert the other breakpoint. */ + if (bpt->inserted) + { + ALL_BREAKPOINTS (b) + if (b->address == bpt->address + && !b->duplicate + && b->enable != disabled) + { + int val; + val = target_insert_breakpoint (b->address, b->shadow_contents); + if (val != 0) + { + fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number); + memory_error (val, b->address); /* which bombs us out */ + } + else + b->inserted = 1; + } + } free_command_lines (&bpt->commands); if (bpt->cond) - free ((PTR)bpt->cond); + free (bpt->cond); if (bpt->cond_string != NULL) - free ((PTR)bpt->cond_string); + free (bpt->cond_string); if (bpt->addr_string != NULL) - free ((PTR)bpt->addr_string); + free (bpt->addr_string); if (bpt->exp_string != NULL) - free ((PTR)bpt->exp_string); + free (bpt->exp_string); + if (bpt->source_file != NULL) + free (bpt->source_file); if (xgdb_verbose && bpt->type == bp_breakpoint) printf ("breakpoint #%d deleted\n", bpt->number); @@ -2288,25 +2646,45 @@ breakpoint_re_set_one (bint) b->enable = disabled; s = b->addr_string; - sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0); + sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0, (char ***)NULL); for (i = 0; i < sals.nelts; i++) { resolve_sal_pc (&sals.sals[i]); - if (b->symtab != sals.sals[i].symtab - || b->line_number != sals.sals[i].line - || b->address != sals.sals[i].pc) + + /* Reparse conditions, they might contain references to the + old symtab. */ + if (b->cond_string != NULL) { - b->symtab = sals.sals[i].symtab; + s = b->cond_string; + if (b->cond) + free ((PTR)b->cond); + b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0); + } + + /* We need to re-set the breakpoint if the address changes...*/ + if (b->address != sals.sals[i].pc + /* ...or new and old breakpoints both have source files, and + the source file name or the line number changes... */ + || (b->source_file != NULL + && sals.sals[i].symtab != NULL + && (!STREQ (b->source_file, sals.sals[i].symtab->filename) + || b->line_number != sals.sals[i].line) + ) + /* ...or we switch between having a source file and not having + one. */ + || ((b->source_file == NULL) != (sals.sals[i].symtab == NULL)) + ) + { + if (b->source_file != NULL) + free (b->source_file); + if (sals.sals[i].symtab == NULL) + b->source_file = NULL; + else + b->source_file = + savestring (sals.sals[i].symtab->filename, + strlen (sals.sals[i].symtab->filename)); b->line_number = sals.sals[i].line; b->address = sals.sals[i].pc; - - if (b->cond_string != NULL) - { - s = b->cond_string; - if (b->cond) - free ((PTR)b->cond); - b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0); - } check_duplicates (b->address); @@ -2339,7 +2717,8 @@ breakpoint_re_set_one (bint) s = b->cond_string; b->cond = parse_exp_1 (&s, (struct block *)0, 0); } - mention (b); + if (b->enable == enabled) + mention (b); break; default: @@ -2349,6 +2728,7 @@ breakpoint_re_set_one (bint) case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_call_dummy: delete_breakpoint (b); break; } @@ -2364,17 +2744,11 @@ breakpoint_re_set () static char message1[] = "Error in re-setting breakpoint %d:\n"; char message[sizeof (message1) + 30 /* slop */]; - /* If we have no current source symtab, and we have any breakpoints, - go through the work of making a source context. */ - if (current_source_symtab == NULL && breakpoint_chain != 0) - { - select_source_symtab (NULL); - } - ALL_BREAKPOINTS_SAFE (b, temp) { sprintf (message, message1, b->number); /* Format possible error msg */ - catch_errors (breakpoint_re_set_one, (char *) b, message); + catch_errors (breakpoint_re_set_one, (char *) b, message, + RETURN_MASK_ALL); } create_longjmp_breakpoint("longjmp"); @@ -2496,6 +2870,9 @@ static void enable_breakpoint (bpt) struct breakpoint *bpt; { + FRAME save_selected_frame = NULL; + int save_selected_frame_level = -1; + bpt->enable = enabled; if (xgdb_verbose && bpt->type == bp_breakpoint) @@ -2504,14 +2881,20 @@ enable_breakpoint (bpt) check_duplicates (bpt->address); if (bpt->type == bp_watchpoint) { - if (bpt->exp_valid_block != NULL - && !contained_in (get_selected_block (), bpt->exp_valid_block)) + if (bpt->exp_valid_block != NULL) { - printf_filtered ("\ + FRAME fr = within_scope (bpt->exp_valid_block); + 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 = disabled; - return; + bpt->enable = disabled; + return; + } + save_selected_frame = selected_frame; + save_selected_frame_level = selected_frame_level; + select_frame (fr, -1); } value_free (bpt->val); @@ -2520,6 +2903,9 @@ is valid is not currently in scope.\n", bpt->number); release_value (bpt->val); if (VALUE_LAZY (bpt->val)) value_fetch_lazy (bpt->val); + + if (save_selected_frame_level >= 0) + select_frame (save_selected_frame, save_selected_frame_level); } } @@ -2628,9 +3014,11 @@ decode_line_spec_1 (string, funfirstline) error ("Empty line specification."); if (default_breakpoint_valid) sals = decode_line_1 (&string, funfirstline, - default_breakpoint_symtab, default_breakpoint_line); + default_breakpoint_symtab, default_breakpoint_line, + (char ***)NULL); else - sals = decode_line_1 (&string, funfirstline, (struct symtab *)NULL, 0); + sals = decode_line_1 (&string, funfirstline, + (struct symtab *)NULL, 0, (char ***)NULL); if (*string) error ("Junk at end of line specification: %s", string); return sals;