📄 breakpoint.c
字号:
if (b->enable != disabled && b->address == pc) return 1; return 0;}/* bpstat stuff. External routines' interfaces are documented in breakpoint.h. *//* Clear a bpstat so that it says we are not at any breakpoint. Also free any storage that is part of a bpstat. */voidbpstat_clear (bsp) bpstat *bsp;{ bpstat p; bpstat q; if (bsp == 0) return; p = *bsp; while (p != NULL) { q = p->next; if (p->old_val != NULL) value_free (p->old_val); free ((PTR)p); p = q; } *bsp = NULL;}/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that is part of the bpstat is copied as well. */bpstatbpstat_copy (bs) bpstat bs;{ bpstat p = NULL; bpstat tmp; bpstat retval; if (bs == NULL) return bs; for (; bs != NULL; bs = bs->next) { tmp = (bpstat) xmalloc (sizeof (*tmp)); memcpy (tmp, bs, sizeof (*tmp)); if (p == NULL) /* This is the first thing in the chain. */ retval = tmp; else p->next = tmp; p = tmp; } p->next = NULL; return retval;}/* Find the bpstat associated with this breakpoint */bpstatbpstat_find_breakpoint(bsp, breakpoint) bpstat bsp; struct breakpoint *breakpoint;{ if (bsp == NULL) return NULL; for (;bsp != NULL; bsp = bsp->next) { if (bsp->breakpoint_at == breakpoint) return bsp; } return NULL;}/* Return the breakpoint number of the first breakpoint we are stopped at. *BSP upon return is a bpstat which points to the remaining breakpoints stopped at (but which is not guaranteed to be good for anything but further calls to bpstat_num). Return 0 if passed a bpstat which does not indicate any breakpoints. */intbpstat_num (bsp) bpstat *bsp;{ struct breakpoint *b; if ((*bsp) == NULL) return 0; /* No more breakpoint values */ else { b = (*bsp)->breakpoint_at; *bsp = (*bsp)->next; if (b == NULL) return -1; /* breakpoint that's been deleted since */ else return b->number; /* We have its number */ }}/* Modify BS so that the actions will not be performed. */voidbpstat_clear_actions (bs) bpstat bs;{ for (; bs != NULL; bs = bs->next) { bs->commands = NULL; if (bs->old_val != NULL) { value_free (bs->old_val); bs->old_val = NULL; } }}/* Stub for cleaning up our state if we error-out of a breakpoint command *//* ARGSUSED */static voidcleanup_executing_breakpoints (ignore) int ignore;{ executing_breakpoint_commands = 0;}/* Execute all the commands associated with all the breakpoints at this location. Any of these commands could cause the process to proceed beyond this point, etc. We look out for such changes by checking the global "breakpoint_proceeded" after each command. */voidbpstat_do_actions (bsp) bpstat *bsp;{ bpstat bs; struct cleanup *old_chain; executing_breakpoint_commands = 1; old_chain = make_cleanup (cleanup_executing_breakpoints, 0);top: bs = *bsp; breakpoint_proceeded = 0; for (; bs != NULL; bs = bs->next) { while (bs->commands) { char *line = bs->commands->line; bs->commands = bs->commands->next; execute_command (line, 0); /* If the inferior is proceeded by the command, bomb out now. The bpstat chain has been blown away by wait_for_inferior. But since execution has stopped again, there is a new bpstat to look at, so start over. */ if (breakpoint_proceeded) goto top; } } executing_breakpoint_commands = 0; discard_cleanups (old_chain);}/* Print a message indicating what happened. Returns nonzero to say that only the source line should be printed after this (zero return means print the frame as well as the source line). */intbpstat_print (bs) bpstat bs;{ /* bs->breakpoint_at can be NULL if it was a momentary breakpoint which has since been deleted. */ if (bs == NULL || bs->breakpoint_at == NULL || (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) { /* I think the user probably only wants to see one breakpoint number, not all of them. */ printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number); return 0; } if (bs->old_val != NULL) { printf_filtered ("\nWatchpoint %d, ", bs->breakpoint_at->number); print_expression (bs->breakpoint_at->exp, stdout); printf_filtered ("\nOld value = "); value_print (bs->old_val, stdout, 0, Val_pretty_default); printf_filtered ("\nNew value = "); value_print (bs->breakpoint_at->val, stdout, 0, Val_pretty_default); printf_filtered ("\n"); value_free (bs->old_val); bs->old_val = NULL; return 1; } /* Maybe another breakpoint in the chain caused us to stop. (Currently all watchpoints go on the bpstat whether hit or not. That probably could (should) be changed, provided care is taken with respect to bpstat_explains_signal). */ if (bs->next) return bpstat_print (bs->next); fprintf_filtered (stderr, "gdb internal error: in bpstat_print\n"); return 0;}/* Evaluate the expression EXP and return 1 if value is zero. This is used inside a catch_errors to evaluate the breakpoint condition. The argument is a "struct expression *" that has been cast to char * to make it pass through catch_errors. */static intbreakpoint_cond_eval (exp) char *exp;{ return !value_true (evaluate_expression ((struct expression *)exp));}/* Allocate a new bpstat and chain it to the current one. */static bpstatbpstat_alloc (b, cbs) register struct breakpoint *b; bpstat cbs; /* Current "bs" value */{ bpstat bs; bs = (bpstat) xmalloc (sizeof (*bs)); cbs->next = bs; 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; return bs;}/* 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. Each element of the chain refers to a particular breakpoint or watchpoint at which we have stopped. (We may have stopped for several reasons concurrently.) Each element of the chain has valid next, breakpoint_at, commands, FIXME??? fields. */ bpstatbpstat_stop_status (pc, frame_address) CORE_ADDR *pc; FRAME_ADDR frame_address;{ 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). */ int real_breakpoint = 0;#endif /* Root of the chain of bpstat's */ struct bpstat root_bs[1]; /* Pointer to the last thing in the chain currently. */ bpstat bs = root_bs; /* Get the address where the breakpoint would have been. */ bp_addr = *pc - DECR_PC_AFTER_BREAK; 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; /* 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; if (b->type == bp_watchpoint) { int within_current_scope; if (b->exp_valid_block != NULL) within_current_scope = contained_in (get_selected_block (), b->exp_valid_block); else within_current_scope = 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. */ value mark = value_mark (); value new_val = evaluate_expression (b->exp); if (!value_equal (b->val, new_val)) { release_value (new_val); value_free_to_mark (mark); bs->old_val = b->val; b->val = new_val; /* We will stop here */ } else { /* Nothing changed, don't do anything. */ value_free_to_mark (mark); continue; /* We won't stop here */ } } else { /* This seems like the only logical thing to do because if we temporarily ignored the watchpoint, then when we reenter the block in which it is valid it contains garbage (in the case of a function, it may have two garbage values, one before and one after the prologue). So we can't even detect the first assignment to it and watch after that (since the garbage may or may not equal the first value assigned). */ b->enable = disabled; printf_filtered ("\Watchpoint %d disabled because the program has left the block in\n\which its expression is valid.\n", b->number); /* We won't stop here */ /* FIXME, maybe we should stop here!!! */ continue; } }#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) else real_breakpoint = 1;#endif if (b->frame && b->frame != frame_address) this_bp_stop = 0; else { int value_is_zero; if (b->cond) { /* Need to select the frame, with all that implies so that the conditions will have the right context. */ select_frame (get_current_frame (), 0); value_is_zero = catch_errors (breakpoint_cond_eval, (char *)(b->cond), "Error in testing breakpoint condition:\n"); /* FIXME-someday, should give breakpoint # */ free_all_values (); } if (b->cond && value_is_zero) { this_bp_stop = 0; } else if (b->ignore_count > 0) { b->ignore_count--; this_bp_stop = 0; } else { /* We will stop here */ if (b->disposition == disable) b->enable = disabled; bs->commands = b->commands; if (b->silent) this_bp_print = 0; if (bs->commands && !strcmp ("silent", bs->commands->line)) { bs->commands = bs->commands->next; this_bp_print = 0; } } } if (this_bp_stop) stop = 1; if (this_bp_print) print = 1; } bs->next = NULL; /* Terminate the chain */ bs = root_bs->next; /* Re-grab the head of the chain */ 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); } }#else /* No SHIFT_INST_REGS. */ write_pc (bp_addr);#endif /* No SHIFT_INST_REGS. */ }#endif /* DECR_PC_AFTER_BREAK != 0. */ } return bs;}/* Nonzero if we should step constantly (e.g. watchpoints on machines without hardware support). This isn't related to a specific bpstat, just to things like whether watchpoints are set. */int bpstat_should_step (){ struct breakpoint *b; ALL_BREAKPOINTS (b) if (b->enable == enabled && b->type == bp_watchpoint) return 1; return 0;}/* Print information on breakpoint number BNUM, or -1 if all. If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS is nonzero, process only watchpoints. */static voidbreakpoint_1 (bnum, allflag) int bnum; int allflag;{ register struct breakpoint *b; register struct command_line *l; register struct symbol *sym; CORE_ADDR last_addr = (CORE_ADDR)-1; int found_a_breakpoint = 0; static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint", "longjmp", "longjmp resume"}; static char *bpdisps[] = {"del", "dis", "keep"}; static char bpenables[] = "ny"; if (!breakpoint_chain) { printf_filtered ("No breakpoints or watchpoints.\n"); return; } ALL_BREAKPOINTS (b) if (bnum == -1 || bnum == b->number) {/* We only print out user settable breakpoints unless the allflag is set. */ if (!allflag && b->type != bp_breakpoint && b->type != bp_watchpoint) continue; if (!found_a_breakpoint++) printf_filtered ("Num Type Disp Enb %sWhat\n", addressprint ? "Address " : ""); printf_filtered ("%-3d %-14s %-4s %-3c ", b->number, bptypes[(int)b->type], bpdisps[(int)b->disposition], bpenables[(int)b->enable]); 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: if (addressprint) printf_filtered ("%s ", local_hex_string_custom(b->address, "08")); last_addr = b->address; if (b->symtab) { sym = find_pc_function (b->address); if (sym) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -