📄 infrun.c
字号:
normal_stop ();}/* Record the pc and sp of the program the last time it stopped. These are just used internally by wait_for_inferior, but need to be preserved over calls to it and cleared when the inferior is started. */static CORE_ADDR prev_pc;static CORE_ADDR prev_sp;static CORE_ADDR prev_func_start;static char *prev_func_name;voidinit_wait_for_inferior_keep_brkpts(){ /* These are meaningless until the first time through wait_for_inferior. */ prev_pc = 0; prev_sp = 0; prev_func_start = 0; prev_func_name = NULL; trap_expected_after_continue = 0; stop_signal = 0; /* Don't confuse first call to proceed(). */}/* Initialize static vars when a new inferior begins. */voidinit_wait_for_inferior (){ init_wait_for_inferior_keep_brkpts(); breakpoints_inserted = 0; mark_breakpoints_out ();}voidremote_go(){ clear_proceed_status(); stop_soon_quietly = 1; trap_expected = 0; wait_for_inferior(); normal_stop();}/* Wait for control to return from inferior to debugger. If inferior gets a signal, we may decide to start it up again instead of returning. That is why there is a loop in this function. When this function actually returns it means the inferior should be left stopped and GDB should read more commands. */voidwait_for_inferior (){ WAITTYPE w; int another_trap; int random_signal; CORE_ADDR stop_sp; CORE_ADDR stop_func_start; char *stop_func_name; CORE_ADDR prologue_pc, tmp; int stop_step_resume_break; struct symtab_and_line sal; int remove_breakpoints_on_following_step = 0; int current_line; int handling_longjmp = 0; /* FIXME */ sal = find_pc_line(prev_pc, 0); current_line = sal.line; while (1) { /* Clean up saved state that will become invalid. */ pc_changed = 0; flush_cached_frames (); registers_changed (); target_wait (&w);#ifdef SIGTRAP_STOP_AFTER_LOAD /* Somebody called load(2), and it gave us a "trap signal after load". Ignore it gracefully. */ SIGTRAP_STOP_AFTER_LOAD (w);#endif /* See if the process still exists; clean up if it doesn't. */ if (WIFEXITED (w)) { target_terminal_ours (); /* Must do this before mourn anyway */ if (WEXITSTATUS (w)) printf_filtered ("\nProgram exited with code 0%o.\n", (unsigned int)WEXITSTATUS (w)); else if (!batch_mode()) printf_filtered ("\nProgram exited normally.\n"); fflush (stdout); target_mourn_inferior ();#ifdef NO_SINGLE_STEP one_stepped = 0;#endif stop_print_frame = 0; break; } else if (!WIFSTOPPED (w)) { stop_print_frame = 0; stop_signal = WTERMSIG (w); target_terminal_ours (); /* Must do this before mourn anyway */ target_kill (); /* kill mourns as well */#ifdef PRINT_RANDOM_SIGNAL printf_filtered ("\nProgram terminated: "); PRINT_RANDOM_SIGNAL (stop_signal);#else printf_filtered ("\nProgram terminated with signal %d, %s\n", stop_signal, safe_strsignal (stop_signal));#endif printf_filtered ("The inferior process no longer exists.\n"); fflush (stdout);#ifdef NO_SINGLE_STEP one_stepped = 0;#endif break; } #ifdef NO_SINGLE_STEP if (one_stepped) single_step (0); /* This actually cleans up the ss */#endif /* NO_SINGLE_STEP */ stop_pc = read_pc (); set_current_frame ( create_new_frame (read_register (FP_REGNUM), read_pc ())); stop_frame_address = FRAME_FP (get_current_frame ()); stop_sp = read_register (SP_REGNUM); stop_func_start = 0; stop_func_name = 0; /* Don't care about return value; stop_func_start and stop_func_name will both be 0 if it doesn't work. */ find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start); stop_func_start += FUNCTION_START_OFFSET; another_trap = 0; bpstat_clear (&stop_bpstat); stop_step = 0; stop_stack_dummy = 0; stop_print_frame = 1; stop_step_resume_break = 0; random_signal = 0; stopped_by_random_signal = 0; breakpoints_failed = 0; /* Look at the cause of the stop, and decide what to do. The alternatives are: 1) break; to really stop and return to the debugger, 2) drop through to start up again (set another_trap to 1 to single step once) 3) set random_signal to 1, and the decision between 1 and 2 will be made according to the signal handling tables. */ stop_signal = WSTOPSIG (w); /* First, distinguish signals caused by the debugger from signals that have to do with the program's own actions. Note that breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending on the operating system version. Here we detect when a SIGILL or SIGEMT is really a breakpoint and change it to SIGTRAP. */ if (stop_signal == SIGTRAP || (breakpoints_inserted && (stop_signal == SIGILL#ifdef SIGEMT || stop_signal == SIGEMT#endif )) || stop_soon_quietly) { if (stop_signal == SIGTRAP && stop_after_trap) { stop_print_frame = 0; break; } if (stop_soon_quietly) break; /* Don't even think about breakpoints if just proceeded over a breakpoint. However, if we are trying to proceed over a breakpoint and end up in sigtramp, then step_resume_break_address will be set and we should check whether we've hit the step breakpoint. */ if (stop_signal == SIGTRAP && trap_expected && step_resume_break_address == 0) bpstat_clear (&stop_bpstat); else { /* See if there is a breakpoint at the current PC. */#if DECR_PC_AFTER_BREAK /* Notice the case of stepping through a jump that lands just after a breakpoint. Don't confuse that with hitting the breakpoint. What we check for is that 1) stepping is going on and 2) the pc before the last insn does not match the address of the breakpoint before the current pc. */ if (prev_pc == stop_pc - DECR_PC_AFTER_BREAK || !step_range_end || step_resume_break_address || handling_longjmp /* FIXME */)#endif /* DECR_PC_AFTER_BREAK not zero */ { /* See if we stopped at the special breakpoint for stepping over a subroutine call. If both are zero, this wasn't the reason for the stop. */ if (step_resume_break_address && stop_pc - DECR_PC_AFTER_BREAK == step_resume_break_address) { stop_step_resume_break = 1; if (DECR_PC_AFTER_BREAK) { stop_pc -= DECR_PC_AFTER_BREAK; write_register (PC_REGNUM, stop_pc); pc_changed = 0; } } else { stop_bpstat = bpstat_stop_status (&stop_pc, stop_frame_address); /* Following in case break condition called a function. */ stop_print_frame = 1; } } } if (stop_signal == SIGTRAP) random_signal = !(bpstat_explains_signal (stop_bpstat) || trap_expected || stop_step_resume_break || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) || (step_range_end && !step_resume_break_address)); else { random_signal = !(bpstat_explains_signal (stop_bpstat) || stop_step_resume_break /* End of a stack dummy. Some systems (e.g. Sony news) give another signal besides SIGTRAP, so check here as well as above. */ || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) ); if (!random_signal) stop_signal = SIGTRAP; } } else random_signal = 1; /* For the program's own signals, act according to the signal handling tables. */ if (random_signal) { /* Signal not for debugging purposes. */ int printed = 0; stopped_by_random_signal = 1; if (stop_signal >= NSIG || signal_print[stop_signal]) { printed = 1; target_terminal_ours_for_output ();#ifdef PRINT_RANDOM_SIGNAL PRINT_RANDOM_SIGNAL (stop_signal);#else printf_filtered ("\nProgram received signal %d, %s\n", stop_signal, safe_strsignal (stop_signal));#endif /* PRINT_RANDOM_SIGNAL */ fflush (stdout); } if (stop_signal >= NSIG || signal_stop[stop_signal]) break; /* If not going to stop, give terminal back if we took it away. */ else if (printed) target_terminal_inferior (); /* Note that virtually all the code below does `if !random_signal'. Perhaps this code should end with a goto or continue. At least one (now fixed) bug was caused by this -- a !random_signal was missing in one of the tests below. */ } /* Handle cases caused by hitting a breakpoint. */ if (!random_signal) if (bpstat_explains_signal (stop_bpstat)) { CORE_ADDR jmp_buf_pc; switch (stop_bpstat->breakpoint_at->type) /* FIXME */ { /* If we hit the breakpoint at longjmp, disable it for the duration of this command. Then, install a temporary breakpoint at the target of the jmp_buf. */ case bp_longjmp: disable_longjmp_breakpoint(); remove_breakpoints (); breakpoints_inserted = 0; if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going; /* Need to blow away step-resume breakpoint, as it interferes with us */ remove_step_breakpoint (); step_resume_break_address = 0; stop_step_resume_break = 0;#if 0 /* FIXME - Need to implement nested temporary breakpoints */ if (step_over_calls > 0) set_longjmp_resume_breakpoint(jmp_buf_pc, get_current_frame()); else#endif /* 0 */ set_longjmp_resume_breakpoint(jmp_buf_pc, NULL); handling_longjmp = 1; /* FIXME */ goto keep_going; case bp_longjmp_resume: remove_breakpoints (); breakpoints_inserted = 0;#if 0 /* FIXME - Need to implement nested temporary breakpoints */ if (step_over_calls && (stop_frame_address INNER_THAN step_frame_address)) { another_trap = 1; goto keep_going; }#endif /* 0 */ disable_longjmp_breakpoint(); handling_longjmp = 0; /* FIXME */ break; default: fprintf(stderr, "Unknown breakpoint type %d\n", stop_bpstat->breakpoint_at->type); case bp_watchpoint: case bp_breakpoint: case bp_until: case bp_finish: /* Does a breakpoint want us to stop? */ if (bpstat_stop (stop_bpstat)) { stop_print_frame = bpstat_should_print (stop_bpstat); goto stop_stepping; } /* Otherwise, must remove breakpoints and single-step to get us past the one we hit. */ else { remove_breakpoints (); remove_step_breakpoint (); breakpoints_inserted = 0; another_trap = 1; } break; } } else if (stop_step_resume_break) { /* But if we have hit the step-resumption breakpoint, remove it. It has done its job getting us here. The sp test is to make sure that we don't get hung up in recursive calls in functions without frame pointers. If the stack pointer isn't outside of where the breakpoint was set (within a routine to be stepped over), we're in the middle of a recursive call. Not true for reg window machines (sparc) because the must change frames to call things and the stack pointer doesn't have to change if it the bp was set in a routine without a frame (pc can be stored in some other window). The removal of the sp test is to allow calls to alloca. Nasty things were happening. Oh, well, gdb can only handle one level deep of lack of frame pointer. */ /* Disable test for step_frame_address match so that we always stop even if the frames don't match. Reason: if we hit the step_resume_breakpoint, there is no way to temporarily disable it so that we can step past it. If we leave the breakpoint in, then we loop forever repeatedly hitting, but never getting past the breakpoint. This change keeps nexting over recursive function calls from hanging gdb. */#if 0 if (* step_frame_address == 0 || (step_frame_address == stop_frame_address))#endif { remove_step_breakpoint (); step_resume_break_address = 0; /* If were waiting for a trap, hitting the step_resume_break doesn't count as getting it. */ if (trap_expected) another_trap = 1; } } /* We come here if we hit a breakpoint but should not stop for it. Possibly we also were stepping and should stop for that. So fall through and test for stepping. But, if not stepping, do not stop. */ /* If this is the breakpoint at the end of a stack dummy, just stop silently. */ if (!random_signal && PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)) { stop_print_frame = 0; stop_stack_dummy = 1;#ifdef HP_OS_BUG trap_expected_after_continue = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -