GNU Binutils with patches for OS216
リビジョン | da33b5bf66650ddadd113bbe6eeed1ed5da37b25 (tree) |
---|---|
日時 | 2008-06-10 09:13:15 |
作者 | Michael Snyder <msnyder@vmwa...> |
コミッター | Michael Snyder |
Daniel Jacobowitz' update to Michael Snyder's reverse debugging patches
@@ -0,0 +1,70 @@ | ||
1 | +2007-07-13 Daniel Jacobowitz <dan@codesourcery.com> | |
2 | + | |
3 | + * infcall.c (call_function_by_hand): Always restore inferior state | |
4 | + for now. | |
5 | + * infrun.c (save_inferior_status): Call to_doing_call. | |
6 | + (restore_inferior_status): Likewise. | |
7 | + (discard_inferior_status): Warn; this should not be reached. | |
8 | + * remote.c (remote_doing_call): New. | |
9 | + (init_remote_ops, init_remote_async_ops): Use it. | |
10 | + * target.c (update_current_target): Handle to_doing_call. | |
11 | + * target.h (struct target_ops): Add to_doing_call. | |
12 | + | |
13 | +2007-04-18 Daniel Jacobowitz <dan@codesourcery.com> | |
14 | + | |
15 | + gdb/ | |
16 | + * infcmd.c (finish_backwards): Correct check for whether to back | |
17 | + up after finishing. | |
18 | + | |
19 | +2007-04-18 Daniel Jacobowitz <dan@codesourcery.com> | |
20 | + | |
21 | + gdb/ | |
22 | + * arm-tdep.c (arm_scan_epilogue): New. | |
23 | + (arm_make_prologue_cache): Use it. | |
24 | + (arm_epilogue_unwind_sniffer): New. | |
25 | + (arm_gdbarch_init): Register it. | |
26 | + | |
27 | +2007-04-13 Daniel Jacobowitz <dan@codesourcery.com> | |
28 | + | |
29 | + Updated patch based on: | |
30 | + 2006-03-31 Michael Snyder <msnyder@redhat.com> | |
31 | + User interface for reverse execution. | |
32 | + * Makefile.in (reverse.c): New file. | |
33 | + * reverse.c: New file. User interface for reverse execution. | |
34 | + | |
35 | +2007-04-13 Daniel Jacobowitz <dan@codesourcery.com> | |
36 | + | |
37 | + Updated patch based on: | |
38 | + 2006-03-31 Michael Snyder <msnyder@redhat.com> | |
39 | + Execution interface for reverse execution. | |
40 | + * breakpoint.c (breakpoint_silence): New function. | |
41 | + * breakpoint.h (breakpoint_silence): Export. | |
42 | + * infcmd.c (finish_command): Check for reverse exec direction. | |
43 | + (finish_backward): New function, handle finish cmd in reverse. | |
44 | + * infrun.c (enum inferior_stop_reason): Add NO_HISTORY reason. | |
45 | + (handle_inferior_event): Handle TARGET_WAITKIND_NO_HISTORY. | |
46 | + Handle stepping over a function call in reverse. | |
47 | + Handle stepping thru a line range in reverse. | |
48 | + Handle setting a step-resume breakpoint in reverse. | |
49 | + Handle stepping into a function in reverse. | |
50 | + Handle stepping between line ranges in reverse. | |
51 | + (print_stop_reason): Print reason for NO_HISTORY. | |
52 | + | |
53 | +2007-04-13 Daniel Jacobowitz <dan@codesourcery.com> | |
54 | + | |
55 | + Updated patch based on: | |
56 | + 2006-03-31 Michael Snyder <msnyder@redhat.com> | |
57 | + Target interface for reverse execution. | |
58 | + * target.h (enum target_waitkind): | |
59 | + Add new wait event, TARGET_WAITKIND_NO_HISTORY. | |
60 | + (enum exec_direction_kind): New enum. | |
61 | + (struct target_ops): New methods to_set_execdir, to_get_execdir. | |
62 | + (target_set_execution_direction): New macro. | |
63 | + (target_get_execution_direction): New macro. | |
64 | + * target.c (update_current_target): Inherit new execdir methods. | |
65 | + | |
66 | + * remote.c (remote_get_execdir, remote_set_execdir): New methods. | |
67 | + (_initialize_remote): Add new methods to remote target vector. | |
68 | + (remote_resume): Check for reverse exec direction, and send | |
69 | + appropriate command to target. | |
70 | + (remote_wait): Check target response for NO_HISTORY status. |
@@ -552,7 +552,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \ | ||
552 | 552 | objfiles.c osabi.c observer.c \ |
553 | 553 | p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \ |
554 | 554 | prologue-value.c \ |
555 | - regcache.c reggroups.c remote.c remote-fileio.c \ | |
555 | + regcache.c reggroups.c remote.c remote-fileio.c reverse.c \ | |
556 | 556 | scm-exp.c scm-lang.c scm-valprint.c \ |
557 | 557 | sentinel-frame.c \ |
558 | 558 | serial.c ser-base.c ser-unix.c \ |
@@ -952,7 +952,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ | ||
952 | 952 | std-regs.o \ |
953 | 953 | signals.o \ |
954 | 954 | gdb-events.o \ |
955 | - exec.o bcache.o objfiles.o observer.o minsyms.o maint.o demangle.o \ | |
955 | + exec.o reverse.o \ | |
956 | + bcache.o objfiles.o observer.o minsyms.o maint.o demangle.o \ | |
956 | 957 | dbxread.o coffread.o coff-pe-read.o elfread.o \ |
957 | 958 | dwarf2read.o mipsread.o stabsread.o corefile.o \ |
958 | 959 | dwarf2expr.o dwarf2loc.o dwarf2-frame.o \ |
@@ -2546,6 +2547,8 @@ remote-sim.o: remote-sim.c $(defs_h) $(inferior_h) $(value_h) \ | ||
2546 | 2547 | remote-utils.o: remote-utils.c $(defs_h) $(gdb_string_h) $(gdbcmd_h) \ |
2547 | 2548 | $(target_h) $(serial_h) $(gdbcore_h) $(inferior_h) $(remote_utils_h) \ |
2548 | 2549 | $(regcache_h) |
2550 | +reverse.o: reverse.c $(defs_h) $(gdb_string_h) $(target_h) $(cli_cmds_h) \ | |
2551 | + $(cli_decode_h) $(top_h) | |
2549 | 2552 | rs6000-nat.o: rs6000-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdbcore_h) \ |
2550 | 2553 | $(xcoffsolib_h) $(symfile_h) $(objfiles_h) $(libbfd_h) $(bfd_h) \ |
2551 | 2554 | $(exceptions_h) $(gdb_stabs_h) $(regcache_h) $(arch_utils_h) \ |
@@ -888,6 +888,45 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac | ||
888 | 888 | cache->frameoffset = 0; |
889 | 889 | } |
890 | 890 | |
891 | +/* This function tries to guess whether we are in the epilogue of an | |
892 | + ARM function. We need to detect whether the stack frame has | |
893 | + already been destroyed - if it has, then neither the prologue | |
894 | + scanner nor GCC's unwind tables will be valid. This is very hokey | |
895 | + and generally unsafe. */ | |
896 | + | |
897 | +static int | |
898 | +arm_scan_epilogue (struct frame_info *next_frame, | |
899 | + struct arm_prologue_cache *cache) | |
900 | +{ | |
901 | + unsigned int insn; | |
902 | + gdb_byte buf[4]; | |
903 | + CORE_ADDR prev_pc = frame_pc_unwind (next_frame); | |
904 | + | |
905 | + /* Assume there is no frame until proven otherwise. */ | |
906 | + if (cache != NULL) | |
907 | + { | |
908 | + cache->framereg = ARM_SP_REGNUM; | |
909 | + cache->framesize = 0; | |
910 | + cache->frameoffset = 0; | |
911 | + } | |
912 | + | |
913 | + /* Check for Thumb epilogue. */ | |
914 | + if (arm_pc_is_thumb (prev_pc)) | |
915 | + /* Not yet implemented. */ | |
916 | + return 0; | |
917 | + | |
918 | + if (target_read_memory (prev_pc, buf, 4) != 0) | |
919 | + return 0; | |
920 | + insn = extract_unsigned_integer (buf, 4); | |
921 | + | |
922 | + if (insn == 0xe12fff1e) /* bx lr */ | |
923 | + /* If this is a return, we have no frame left and no saved | |
924 | + registers. */ | |
925 | + return 1; | |
926 | + | |
927 | + return 0; | |
928 | +} | |
929 | + | |
891 | 930 | static struct arm_prologue_cache * |
892 | 931 | arm_make_prologue_cache (struct frame_info *next_frame) |
893 | 932 | { |
@@ -898,7 +937,8 @@ arm_make_prologue_cache (struct frame_info *next_frame) | ||
898 | 937 | cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); |
899 | 938 | cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); |
900 | 939 | |
901 | - arm_scan_prologue (next_frame, cache); | |
940 | + if (arm_scan_epilogue (next_frame, cache) == 0) | |
941 | + arm_scan_prologue (next_frame, cache); | |
902 | 942 | |
903 | 943 | unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg); |
904 | 944 | if (unwound_fp == 0) |
@@ -995,6 +1035,15 @@ arm_prologue_unwind_sniffer (struct frame_info *next_frame) | ||
995 | 1035 | return &arm_prologue_unwind; |
996 | 1036 | } |
997 | 1037 | |
1038 | +static const struct frame_unwind * | |
1039 | +arm_epilogue_unwind_sniffer (struct frame_info *next_frame) | |
1040 | +{ | |
1041 | + if (arm_scan_epilogue (next_frame, NULL)) | |
1042 | + return &arm_prologue_unwind; | |
1043 | + else | |
1044 | + return NULL; | |
1045 | +} | |
1046 | + | |
998 | 1047 | static struct arm_prologue_cache * |
999 | 1048 | arm_make_stub_cache (struct frame_info *next_frame) |
1000 | 1049 | { |
@@ -2996,6 +3045,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) | ||
2996 | 3045 | |
2997 | 3046 | /* Add some default predicates. */ |
2998 | 3047 | frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer); |
3048 | + frame_unwind_append_sniffer (gdbarch, arm_epilogue_unwind_sniffer); | |
2999 | 3049 | frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer); |
3000 | 3050 | frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer); |
3001 | 3051 |
@@ -7534,6 +7534,13 @@ breakpoint_clear_ignore_counts (void) | ||
7534 | 7534 | b->ignore_count = 0; |
7535 | 7535 | } |
7536 | 7536 | |
7537 | +void | |
7538 | +breakpoint_silence (struct breakpoint *b) | |
7539 | +{ | |
7540 | + /* Silence the breakpoint. */ | |
7541 | + b->silent = 1; | |
7542 | +} | |
7543 | + | |
7537 | 7544 | /* Command to set ignore-count of breakpoint N to COUNT. */ |
7538 | 7545 | |
7539 | 7546 | static void |
@@ -850,4 +850,7 @@ extern int deprecated_exception_catchpoints_are_fragile; | ||
850 | 850 | reinitialized -- e.g. when program is re-run. */ |
851 | 851 | extern int deprecated_exception_support_initialized; |
852 | 852 | |
853 | +/* Tell a breakpoint to be quiet. */ | |
854 | +extern void breakpoint_silence (struct breakpoint *); | |
855 | + | |
853 | 856 | #endif /* !defined (BREAKPOINT_H) */ |
@@ -127,6 +127,7 @@ Copyright (C) 1988-2006 Free Software Foundation, Inc. | ||
127 | 127 | * Commands:: @value{GDBN} commands |
128 | 128 | * Running:: Running programs under @value{GDBN} |
129 | 129 | * Stopping:: Stopping and continuing |
130 | +* Reverse Execution:: Running programs backward | |
130 | 131 | * Stack:: Examining the stack |
131 | 132 | * Source:: Examining source files |
132 | 133 | * Data:: Examining data |
@@ -4387,6 +4388,109 @@ Display the current scheduler locking mode. | ||
4387 | 4388 | @end table |
4388 | 4389 | |
4389 | 4390 | |
4391 | +@node Reverse Execution | |
4392 | +@chapter Running programs backward | |
4393 | + | |
4394 | +When you are debugging a program, it is not unusual to realize that | |
4395 | +you have gone too far, and some event of interest has already happened. | |
4396 | +If the target environment supports it, @value{GDBN} can allow you to | |
4397 | +``rewind'' the program by running it backward. | |
4398 | + | |
4399 | +A target environment that supports reverse execution should be able | |
4400 | +to ``undo'' the changes in machine state that have taken place as the | |
4401 | +program was executing normally. Variables, registers etc. should | |
4402 | +revert to their previous values. Obviously this requires a great | |
4403 | +deal of sophistication on the part of the target environment; not | |
4404 | +all target environments can support reverse execution. | |
4405 | + | |
4406 | +When a program is executed in reverse, the instructions that | |
4407 | +have most recently been executed are ``un-executed'', in reverse | |
4408 | +order. The program counter runs backward, following the previous | |
4409 | +thread of execution in reverse. As each instruction is ``un-executed'', | |
4410 | +the values of memory and/or registers that were changed by that | |
4411 | +instruction are reverted to their previous states. After executing | |
4412 | +a piece of source code in reverse, all side effects of that code | |
4413 | +should be ``undone'', and all variables should be returned to their | |
4414 | +prior values. | |
4415 | + | |
4416 | +Assuming you are debugging in a target environment that supports | |
4417 | +reverse execution, @value{GDBN} provides the following commands. | |
4418 | + | |
4419 | +@table @code | |
4420 | +@kindex reverse-continue | |
4421 | +@kindex rc @r{(@code{reverse-continue})} | |
4422 | +@item reverse-continue @r{[}@var{ignore-count}@r{]} | |
4423 | +@itemx rc @r{[}@var{ignore-count}@r{]} | |
4424 | +Beginning at the point where your program last stopped, start executing | |
4425 | +in reverse. Reverse execution will stop for breakpoints and synchronous | |
4426 | +exceptions (signals), just like normal execution. Behavior of | |
4427 | +asynchronous signals depends on the target environment. | |
4428 | + | |
4429 | +@kindex reverse-step | |
4430 | +@kindex rs @r{(@code{step})} | |
4431 | +@item reverse-step @r{[}@var{count}@r{]} | |
4432 | +Run the program backward until control reaches the start of a | |
4433 | +different source line; then stop it, and return control to @value{GDBN}. | |
4434 | + | |
4435 | +Like the @code{step} command, @code{reverse-step} will only stop | |
4436 | +at the beginning of a source line. It ``un-executes'' the previously | |
4437 | +executed source line. If the previous source line included calls to | |
4438 | +debuggable functions, @code{reverse-step} will step (backward) into | |
4439 | +the called function, stopping at the beginning of the @emph{last} | |
4440 | +statement in the called function (typically a return statement). | |
4441 | + | |
4442 | +Also, as with the @code{step} command, if non-debuggable functions are | |
4443 | +called, @code{reverse-step} will run thru them backward without stopping. | |
4444 | + | |
4445 | +@kindex reverse-stepi | |
4446 | +@kindex rsi @r{(@code{reverse-stepi})} | |
4447 | +@item reverse-stepi @r{[}@var{count}@r{]} | |
4448 | +Reverse-execute one machine instruction. Note that the instruction | |
4449 | +to be reverse-executed is @emph{not} the one pointed to by the program | |
4450 | +counter, but the instruction executed prior to that one. For instance, | |
4451 | +if the last instruction was a jump, @code{reverse-stepi} will take you | |
4452 | +back from the destination of the jump to the jump instruction itself. | |
4453 | + | |
4454 | +@kindex reverse-next | |
4455 | +@kindex rn @r{(@code{reverse-next})} | |
4456 | +@item reverse-next @r{[}@var{count}@r{]} | |
4457 | +Run backward to the beginning of the previous line executed in | |
4458 | +the current (innermost) stack frame. If the line contains function | |
4459 | +calls, they will be ``un-executed'' without stopping. Starting from | |
4460 | +the first line of a function, @code{reverse-next} will take you back | |
4461 | +to the caller of that function, @emph{before} the function was called. | |
4462 | + | |
4463 | +@kindex reverse-nexti | |
4464 | +@kindex rni @r{(@code{reverse-nexti})} | |
4465 | +@item reverse-nexti @r{[}@var{count}@r{]} | |
4466 | +Like @code{nexti}, @code{reverse-nexti} executes a single instruction | |
4467 | +in reverse, except that called functions are ``un-executed'' atomically. | |
4468 | +That is, if the previously executed instruction was a return from | |
4469 | +another instruction, @code{reverse-nexti} will continue to execute | |
4470 | +in reverse until the call to that function (from the current stack | |
4471 | +frame) is reached. | |
4472 | + | |
4473 | +@kindex reverse-finish | |
4474 | +@item reverse-finish | |
4475 | +Just as the @code{finish} command takes you to the point where the | |
4476 | +current function returns, @code{reverse-finish} takes you to the point | |
4477 | +where it was called. Instead of ending up at the end of the current | |
4478 | +function invocation, you end up at the beginning. | |
4479 | + | |
4480 | +@item set exec-direction | |
4481 | +Set the direction of target execution. | |
4482 | +@itemx set exec-direction reverse | |
4483 | +@cindex execute forward or backward in time | |
4484 | +@value{GDBN} will perform all execution commands in reverse, until the | |
4485 | +exec-direction mode is changed to ``forward''. Affected commands include | |
4486 | +@code{step, stepi, next, nexti, continue, and finish}. The @code{return} | |
4487 | +command cannot be used in reverse mode. | |
4488 | +@item set exec-direction forward | |
4489 | +@value{GDBN} will perform all execution commands in the normal fashion. | |
4490 | +This is the default. | |
4491 | +@end table | |
4492 | + | |
4493 | + | |
4390 | 4494 | @node Stack |
4391 | 4495 | @chapter Examining the Stack |
4392 | 4496 |
@@ -780,7 +780,7 @@ You must use a pointer to function type variable. Command ignored."), arg_name); | ||
780 | 780 | signal. Further execution of the FUNCTION is not |
781 | 781 | allowed. */ |
782 | 782 | |
783 | - if (unwind_on_signal_p) | |
783 | + if (unwind_on_signal_p || 1 /* FIXME restoring state */) | |
784 | 784 | { |
785 | 785 | /* The user wants the context restored. */ |
786 | 786 |
@@ -819,6 +819,12 @@ Evaluation of the expression containing the function (%s) will be abandoned."), | ||
819 | 819 | } |
820 | 820 | } |
821 | 821 | |
822 | + if (!stop_stack_dummy && 1 /* FIXME restoring state */) | |
823 | + { | |
824 | + error (_("\ | |
825 | +The program being debugged stopped while in a function called from GDB.\n\ | |
826 | +GDB has restored the context to what it was before the call.")); | |
827 | + } | |
822 | 828 | if (!stop_stack_dummy) |
823 | 829 | { |
824 | 830 | /* We hit a breakpoint inside the FUNCTION. */ |
@@ -1266,6 +1266,8 @@ finish_command_continuation (struct continuation_arg *arg) | ||
1266 | 1266 | /* "finish": Set a temporary breakpoint at the place the selected |
1267 | 1267 | frame will return to, then continue. */ |
1268 | 1268 | |
1269 | +static void finish_backwards (struct symbol *); | |
1270 | + | |
1269 | 1271 | static void |
1270 | 1272 | finish_command (char *arg, int from_tty) |
1271 | 1273 | { |
@@ -1306,16 +1308,6 @@ finish_command (char *arg, int from_tty) | ||
1306 | 1308 | |
1307 | 1309 | clear_proceed_status (); |
1308 | 1310 | |
1309 | - sal = find_pc_line (get_frame_pc (frame), 0); | |
1310 | - sal.pc = get_frame_pc (frame); | |
1311 | - | |
1312 | - breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish); | |
1313 | - | |
1314 | - if (!target_can_async_p ()) | |
1315 | - old_chain = make_cleanup_delete_breakpoint (breakpoint); | |
1316 | - else | |
1317 | - old_chain = make_exec_cleanup_delete_breakpoint (breakpoint); | |
1318 | - | |
1319 | 1311 | /* Find the function we will return from. */ |
1320 | 1312 | |
1321 | 1313 | function = find_pc_function (get_frame_pc (get_selected_frame (NULL))); |
@@ -1324,10 +1316,31 @@ finish_command (char *arg, int from_tty) | ||
1324 | 1316 | source. */ |
1325 | 1317 | if (from_tty) |
1326 | 1318 | { |
1327 | - printf_filtered (_("Run till exit from ")); | |
1319 | + if (target_get_execution_direction () == EXEC_REVERSE) | |
1320 | + printf_filtered ("Run back to call of "); | |
1321 | + else | |
1322 | + printf_filtered ("Run till exit from "); | |
1323 | + | |
1328 | 1324 | print_stack_frame (get_selected_frame (NULL), 1, LOCATION); |
1329 | 1325 | } |
1330 | 1326 | |
1327 | + if (target_get_execution_direction () == EXEC_REVERSE) | |
1328 | + { | |
1329 | + /* Split off at this point. */ | |
1330 | + finish_backwards (function); | |
1331 | + return; | |
1332 | + } | |
1333 | + | |
1334 | + sal = find_pc_line (get_frame_pc (frame), 0); | |
1335 | + sal.pc = get_frame_pc (frame); | |
1336 | + | |
1337 | + breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish); | |
1338 | + | |
1339 | + if (!target_can_async_p ()) | |
1340 | + old_chain = make_cleanup_delete_breakpoint (breakpoint); | |
1341 | + else | |
1342 | + old_chain = make_exec_cleanup_delete_breakpoint (breakpoint); | |
1343 | + | |
1331 | 1344 | /* If running asynchronously and the target support asynchronous |
1332 | 1345 | execution, set things up for the rest of the finish command to be |
1333 | 1346 | completed later on, when gdb has detected that the target has |
@@ -1384,6 +1397,66 @@ finish_command (char *arg, int from_tty) | ||
1384 | 1397 | do_cleanups (old_chain); |
1385 | 1398 | } |
1386 | 1399 | } |
1400 | + | |
1401 | +static void | |
1402 | +finish_backwards (struct symbol *function) | |
1403 | +{ | |
1404 | + struct symtab_and_line sal; | |
1405 | + struct breakpoint *breakpoint; | |
1406 | + struct cleanup *old_chain; | |
1407 | + CORE_ADDR func_addr; | |
1408 | + int back_up; | |
1409 | + | |
1410 | + if (find_pc_partial_function (get_frame_pc (get_current_frame ()), | |
1411 | + NULL, &func_addr, NULL) == 0) | |
1412 | + internal_error (__FILE__, __LINE__, | |
1413 | + "Finish: couldn't find function."); | |
1414 | + | |
1415 | + sal = find_pc_line (func_addr, 0); | |
1416 | + | |
1417 | + /* Let's cheat and not worry about async until later. */ | |
1418 | + | |
1419 | + /* We don't need a return value. */ | |
1420 | + proceed_to_finish = 0; | |
1421 | + /* Special case: if we're sitting at the function entry point, | |
1422 | + then all we need to do is take a reverse singlestep. We | |
1423 | + don't need to set a breakpoint, and indeed it would do us | |
1424 | + no good to do so. | |
1425 | + | |
1426 | + Note that this can only happen at frame #0, since there's | |
1427 | + no way that a function up the stack can have a return address | |
1428 | + that's equal to its entry point. */ | |
1429 | + | |
1430 | + if (sal.pc != read_pc ()) | |
1431 | + { | |
1432 | + /* Set breakpoint and continue. */ | |
1433 | + breakpoint = | |
1434 | + set_momentary_breakpoint (sal, | |
1435 | + get_frame_id (get_selected_frame (NULL)), | |
1436 | + bp_breakpoint); | |
1437 | + /* Tell the breakpoint to keep quiet. We won't be done | |
1438 | + until we've done another reverse single-step. */ | |
1439 | + breakpoint_silence (breakpoint); | |
1440 | + old_chain = make_cleanup_delete_breakpoint (breakpoint); | |
1441 | + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); | |
1442 | + /* We will be stopped when proceed returns. */ | |
1443 | + back_up = bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL; | |
1444 | + do_cleanups (old_chain); | |
1445 | + } | |
1446 | + else | |
1447 | + back_up = 1; | |
1448 | + if (back_up) | |
1449 | + { | |
1450 | + /* If in fact we hit the step-resume breakpoint (and not | |
1451 | + some other breakpoint), then we're almost there -- | |
1452 | + we just need to back up by one more single-step. */ | |
1453 | + /* (Kludgy way of letting wait_for_inferior know...) */ | |
1454 | + step_range_start = step_range_end = 1; | |
1455 | + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); | |
1456 | + } | |
1457 | + return; | |
1458 | +} | |
1459 | + | |
1387 | 1460 | |
1388 | 1461 | |
1389 | 1462 | static void |
@@ -899,7 +899,9 @@ enum inferior_stop_reason | ||
899 | 899 | /* Inferior exited. */ |
900 | 900 | EXITED, |
901 | 901 | /* Inferior received signal, and user asked to be notified. */ |
902 | - SIGNAL_RECEIVED | |
902 | + SIGNAL_RECEIVED, | |
903 | + /* Reverse execution -- target ran out of history info. */ | |
904 | + NO_HISTORY | |
903 | 905 | }; |
904 | 906 | |
905 | 907 | /* This structure contains what used to be local variables in |
@@ -1517,6 +1519,12 @@ handle_inferior_event (struct execution_control_state *ecs) | ||
1517 | 1519 | stop_signal = ecs->ws.value.sig; |
1518 | 1520 | break; |
1519 | 1521 | |
1522 | + case TARGET_WAITKIND_NO_HISTORY: | |
1523 | + /* Reverse execution: target ran out of history info. */ | |
1524 | + print_stop_reason (NO_HISTORY, 0); | |
1525 | + stop_stepping (ecs); | |
1526 | + return; | |
1527 | + | |
1520 | 1528 | /* We had an event in the inferior, but we are not interested |
1521 | 1529 | in handling it at this level. The lower layers have already |
1522 | 1530 | done what needs to be done, if anything. |
@@ -2182,6 +2190,17 @@ process_event_stop_test: | ||
2182 | 2190 | keep_going (ecs); |
2183 | 2191 | return; |
2184 | 2192 | } |
2193 | + if (stop_pc == ecs->stop_func_start && | |
2194 | + target_get_execution_direction () == EXEC_REVERSE) | |
2195 | + { | |
2196 | + /* We are stepping over a function call in reverse, and | |
2197 | + just hit the step-resume breakpoint at the start | |
2198 | + address of the function. Go back to single-stepping, | |
2199 | + which should take us back to the function call. */ | |
2200 | + ecs->another_trap = 1; | |
2201 | + keep_going (ecs); | |
2202 | + return; | |
2203 | + } | |
2185 | 2204 | break; |
2186 | 2205 | |
2187 | 2206 | case BPSTAT_WHAT_THROUGH_SIGTRAMP: |
@@ -2365,7 +2384,22 @@ process_event_stop_test: | ||
2365 | 2384 | fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n", |
2366 | 2385 | paddr_nz (step_range_start), |
2367 | 2386 | paddr_nz (step_range_end)); |
2368 | - keep_going (ecs); | |
2387 | + | |
2388 | + /* When stepping backward, stop at beginning of line range | |
2389 | + (unles it's the function entry point, in which case | |
2390 | + keep going back to the call point). */ | |
2391 | + if (stop_pc == step_range_start && | |
2392 | + stop_pc != ecs->stop_func_start && | |
2393 | + target_get_execution_direction () == EXEC_REVERSE) | |
2394 | + { | |
2395 | + stop_step = 1; | |
2396 | + print_stop_reason (END_STEPPING_RANGE, 0); | |
2397 | + stop_stepping (ecs); | |
2398 | + } | |
2399 | + else | |
2400 | + { | |
2401 | + keep_going (ecs); | |
2402 | + } | |
2369 | 2403 | return; |
2370 | 2404 | } |
2371 | 2405 |
@@ -2454,10 +2488,31 @@ process_event_stop_test: | ||
2454 | 2488 | |
2455 | 2489 | if (step_over_calls == STEP_OVER_ALL) |
2456 | 2490 | { |
2457 | - /* We're doing a "next", set a breakpoint at callee's return | |
2458 | - address (the address at which the caller will | |
2459 | - resume). */ | |
2460 | - insert_step_resume_breakpoint_at_caller (get_current_frame ()); | |
2491 | + /* We're doing a "next". | |
2492 | + | |
2493 | + Normal (forward) execution: set a breakpoint at the | |
2494 | + callee's return address (the address at which the caller | |
2495 | + will resume). | |
2496 | + | |
2497 | + Reverse (backward) execution. set the step-resume | |
2498 | + breakpoint at the start of the function that we just | |
2499 | + stepped into (backwards), and continue to there. When we | |
2500 | + get there, we'll need to single-step back to the | |
2501 | + caller. */ | |
2502 | + | |
2503 | + if (target_get_execution_direction () == EXEC_REVERSE) | |
2504 | + { | |
2505 | + /* FIXME: I'm not sure if we've handled the frame for | |
2506 | + recursion. */ | |
2507 | + | |
2508 | + struct symtab_and_line sr_sal; | |
2509 | + init_sal (&sr_sal); | |
2510 | + sr_sal.pc = ecs->stop_func_start; | |
2511 | + insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id); | |
2512 | + } | |
2513 | + else | |
2514 | + insert_step_resume_breakpoint_at_caller (get_current_frame ()); | |
2515 | + | |
2461 | 2516 | keep_going (ecs); |
2462 | 2517 | return; |
2463 | 2518 | } |
@@ -2518,9 +2573,22 @@ process_event_stop_test: | ||
2518 | 2573 | return; |
2519 | 2574 | } |
2520 | 2575 | |
2521 | - /* Set a breakpoint at callee's return address (the address at | |
2522 | - which the caller will resume). */ | |
2523 | - insert_step_resume_breakpoint_at_caller (get_current_frame ()); | |
2576 | + if (target_get_execution_direction () == EXEC_REVERSE) | |
2577 | + { | |
2578 | + /* Set a breakpoint at callee's start address. | |
2579 | + From there we can step once and be back in the caller. */ | |
2580 | + /* FIXME: I'm not sure we've handled the frame for recursion. */ | |
2581 | + struct symtab_and_line sr_sal; | |
2582 | + init_sal (&sr_sal); | |
2583 | + sr_sal.pc = ecs->stop_func_start; | |
2584 | + insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id); | |
2585 | + } | |
2586 | + else | |
2587 | + { | |
2588 | + /* Set a breakpoint at callee's return address (the address | |
2589 | + at which the caller will resume). */ | |
2590 | + insert_step_resume_breakpoint_at_caller (get_current_frame ()); | |
2591 | + } | |
2524 | 2592 | keep_going (ecs); |
2525 | 2593 | return; |
2526 | 2594 | } |
@@ -2649,17 +2717,38 @@ process_event_stop_test: | ||
2649 | 2717 | |
2650 | 2718 | if (ecs->stop_func_end && ecs->sal.end >= ecs->stop_func_end) |
2651 | 2719 | { |
2652 | - /* If this is the last line of the function, don't keep stepping | |
2653 | - (it would probably step us out of the function). | |
2654 | - This is particularly necessary for a one-line function, | |
2655 | - in which after skipping the prologue we better stop even though | |
2656 | - we will be in mid-line. */ | |
2657 | - if (debug_infrun) | |
2658 | - fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different function\n"); | |
2659 | - stop_step = 1; | |
2660 | - print_stop_reason (END_STEPPING_RANGE, 0); | |
2661 | - stop_stepping (ecs); | |
2662 | - return; | |
2720 | + if (target_get_execution_direction () != EXEC_REVERSE) | |
2721 | + { | |
2722 | + /* If this is the last line of the function, don't keep | |
2723 | + stepping (it would probably step us out of the function). | |
2724 | + This is particularly necessary for a one-line function, | |
2725 | + in which after skipping the prologue we better stop even | |
2726 | + though we will be in mid-line. */ | |
2727 | + if (debug_infrun) | |
2728 | + fprintf_unfiltered (gdb_stdlog, | |
2729 | + "infrun: stepped to a different function\n"); | |
2730 | + stop_step = 1; | |
2731 | + print_stop_reason (END_STEPPING_RANGE, 0); | |
2732 | + stop_stepping (ecs); | |
2733 | + return; | |
2734 | + } | |
2735 | + else | |
2736 | + { | |
2737 | + /* If we stepped backward into the last line of a function, | |
2738 | + then we've presumably stepped thru a return. We want to | |
2739 | + keep stepping backward until we reach the beginning of | |
2740 | + the new line. */ | |
2741 | + step_range_start = ecs->sal.pc; | |
2742 | + step_range_end = ecs->sal.end; | |
2743 | + step_frame_id = get_frame_id (get_current_frame ()); | |
2744 | + ecs->current_line = ecs->sal.line; | |
2745 | + ecs->current_symtab = ecs->sal.symtab; | |
2746 | + /* Adjust for prologue, in case of a one-line function. */ | |
2747 | + if (in_prologue (step_range_start, ecs->stop_func_start)) | |
2748 | + step_range_start = SKIP_PROLOGUE (step_range_start); | |
2749 | + keep_going (ecs); | |
2750 | + return; | |
2751 | + } | |
2663 | 2752 | } |
2664 | 2753 | step_range_start = ecs->sal.pc; |
2665 | 2754 | step_range_end = ecs->sal.end; |
@@ -2722,6 +2811,28 @@ step_into_function (struct execution_control_state *ecs) | ||
2722 | 2811 | if (s && s->language != language_asm) |
2723 | 2812 | ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start); |
2724 | 2813 | |
2814 | + if (target_get_execution_direction () == EXEC_REVERSE) | |
2815 | + { | |
2816 | + ecs->sal = find_pc_line (stop_pc, 0); | |
2817 | + | |
2818 | + /* OK, we're just gonna keep stepping here. */ | |
2819 | + if (ecs->sal.pc == stop_pc) | |
2820 | + { | |
2821 | + /* We're there already. Just stop stepping now. */ | |
2822 | + stop_step = 1; | |
2823 | + print_stop_reason (END_STEPPING_RANGE, 0); | |
2824 | + stop_stepping (ecs); | |
2825 | + return; | |
2826 | + } | |
2827 | + /* Else just reset the step range and keep going. | |
2828 | + No step-resume breakpoint, they don't work for | |
2829 | + epilogues, which can have multiple entry paths. */ | |
2830 | + step_range_start = ecs->sal.pc; | |
2831 | + step_range_end = ecs->sal.end; | |
2832 | + keep_going (ecs); | |
2833 | + return; | |
2834 | + } | |
2835 | + /* else... */ | |
2725 | 2836 | ecs->sal = find_pc_line (ecs->stop_func_start, 0); |
2726 | 2837 | /* Use the step_resume_break to step until the end of the prologue, |
2727 | 2838 | even if that involves jumps (as it seems to on the vax under |
@@ -3042,6 +3153,10 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info) | ||
3042 | 3153 | annotate_signal_string_end (); |
3043 | 3154 | ui_out_text (uiout, ".\n"); |
3044 | 3155 | break; |
3156 | + case NO_HISTORY: | |
3157 | + /* Reverse execution: target ran out of history info. */ | |
3158 | + ui_out_text (uiout, "\nNo more reverse-execution history.\n"); | |
3159 | + break; | |
3045 | 3160 | default: |
3046 | 3161 | internal_error (__FILE__, __LINE__, |
3047 | 3162 | _("print_stop_reason: unrecognized enum value")); |
@@ -3675,6 +3790,7 @@ save_inferior_status (int restore_stack_info) | ||
3675 | 3790 | inf_status->registers = regcache_dup (current_regcache); |
3676 | 3791 | |
3677 | 3792 | inf_status->selected_frame_id = get_frame_id (get_selected_frame (NULL)); |
3793 | + current_target.to_doing_call (1); | |
3678 | 3794 | return inf_status; |
3679 | 3795 | } |
3680 | 3796 |
@@ -3723,6 +3839,8 @@ restore_inferior_status (struct inferior_status *inf_status) | ||
3723 | 3839 | regcache_xfree (stop_registers); |
3724 | 3840 | stop_registers = inf_status->stop_registers; |
3725 | 3841 | |
3842 | + current_target.to_doing_call (0); | |
3843 | + | |
3726 | 3844 | /* The inferior can be gone if the user types "print exit(0)" |
3727 | 3845 | (and perhaps other times). */ |
3728 | 3846 | if (target_has_execution) |
@@ -3770,6 +3888,7 @@ make_cleanup_restore_inferior_status (struct inferior_status *inf_status) | ||
3770 | 3888 | void |
3771 | 3889 | discard_inferior_status (struct inferior_status *inf_status) |
3772 | 3890 | { |
3891 | + warning (_("Discarding inferior status")); | |
3773 | 3892 | /* See save_inferior_status for info on stop_bpstat. */ |
3774 | 3893 | bpstat_clear (&inf_status->stop_bpstat); |
3775 | 3894 | regcache_xfree (inf_status->registers); |
@@ -2851,7 +2851,15 @@ remote_resume (ptid_t ptid, int step, enum target_signal siggnal) | ||
2851 | 2851 | set_thread (pid, 0); /* Run this thread. */ |
2852 | 2852 | |
2853 | 2853 | buf = rs->buf; |
2854 | - if (siggnal != TARGET_SIGNAL_0) | |
2854 | + if (target_get_execution_direction () == EXEC_REVERSE) | |
2855 | + { | |
2856 | + /* We don't pass signals to the target in reverse exec mode. */ | |
2857 | + if (info_verbose && siggnal != TARGET_SIGNAL_0) | |
2858 | + warning (" - Can't pass signal %d to target in reverse: ignored.\n", | |
2859 | + siggnal); | |
2860 | + strcpy (buf, step ? "bs" : "bc"); | |
2861 | + } | |
2862 | + else if (siggnal != TARGET_SIGNAL_0) | |
2855 | 2863 | { |
2856 | 2864 | buf[0] = step ? 'S' : 'C'; |
2857 | 2865 | buf[1] = tohex (((int) siggnal >> 4) & 0xf); |
@@ -3125,6 +3133,11 @@ remote_wait (ptid_t ptid, struct target_waitstatus *status) | ||
3125 | 3133 | switch (buf[0]) |
3126 | 3134 | { |
3127 | 3135 | case 'E': /* Error of some sort. */ |
3136 | + if (buf[1] == '0' && buf[2] == '6') | |
3137 | + { | |
3138 | + status->kind = TARGET_WAITKIND_NO_HISTORY; | |
3139 | + goto got_status; | |
3140 | + } | |
3128 | 3141 | warning (_("Remote failure reply: %s"), buf); |
3129 | 3142 | continue; |
3130 | 3143 | case 'F': /* File-I/O request. */ |
@@ -6110,6 +6123,47 @@ remote_read_description (struct target_ops *target) | ||
6110 | 6123 | return NULL; |
6111 | 6124 | } |
6112 | 6125 | |
6126 | +/* Reverse execution. | |
6127 | + FIXME: set up as a capability. */ | |
6128 | +static enum exec_direction_kind remote_execdir = EXEC_FORWARD; | |
6129 | + | |
6130 | +static enum exec_direction_kind remote_get_execdir (void) | |
6131 | +{ | |
6132 | + if (remote_debug && info_verbose) | |
6133 | + printf_filtered ("remote execdir is %s\n", | |
6134 | + remote_execdir == EXEC_FORWARD ? "forward" : | |
6135 | + remote_execdir == EXEC_REVERSE ? "reverse" : | |
6136 | + "unknown"); | |
6137 | + return remote_execdir; | |
6138 | +} | |
6139 | + | |
6140 | +static int remote_set_execdir (enum exec_direction_kind dir) | |
6141 | +{ | |
6142 | + if (remote_debug && info_verbose) | |
6143 | + printf_filtered ("Set remote execdir: %s\n", | |
6144 | + dir == EXEC_FORWARD ? "forward" : | |
6145 | + dir == EXEC_REVERSE ? "reverse" : | |
6146 | + "bad direction"); | |
6147 | + | |
6148 | + /* FIXME: check target for capability. */ | |
6149 | + if (dir == EXEC_FORWARD || dir == EXEC_REVERSE) | |
6150 | + return (remote_execdir = dir); | |
6151 | + else | |
6152 | + return EXEC_ERROR; | |
6153 | +} | |
6154 | + | |
6155 | +static void | |
6156 | +remote_doing_call (int starting) | |
6157 | +{ | |
6158 | + struct remote_state *rs = get_remote_state (); | |
6159 | + | |
6160 | + if (starting) | |
6161 | + strcpy (rs->buf, "QStartCall"); | |
6162 | + else | |
6163 | + strcpy (rs->buf, "QEndCall"); | |
6164 | + remote_send (&rs->buf, &rs->buf_size); | |
6165 | +} | |
6166 | + | |
6113 | 6167 | static void |
6114 | 6168 | init_remote_ops (void) |
6115 | 6169 | { |
@@ -6157,11 +6211,14 @@ Specify the serial device it is connected to\n\ | ||
6157 | 6211 | remote_ops.to_has_registers = 1; |
6158 | 6212 | remote_ops.to_has_execution = 1; |
6159 | 6213 | remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */ |
6214 | + remote_ops.to_get_execdir = remote_get_execdir; | |
6215 | + remote_ops.to_set_execdir = remote_set_execdir; | |
6160 | 6216 | remote_ops.to_magic = OPS_MAGIC; |
6161 | 6217 | remote_ops.to_memory_map = remote_memory_map; |
6162 | 6218 | remote_ops.to_flash_erase = remote_flash_erase; |
6163 | 6219 | remote_ops.to_flash_done = remote_flash_done; |
6164 | 6220 | remote_ops.to_read_description = remote_read_description; |
6221 | + remote_ops.to_doing_call = remote_doing_call; | |
6165 | 6222 | } |
6166 | 6223 | |
6167 | 6224 | /* Set up the extended remote vector by making a copy of the standard |
@@ -6294,7 +6351,8 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; | ||
6294 | 6351 | remote_async_ops.to_memory_map = remote_memory_map; |
6295 | 6352 | remote_async_ops.to_flash_erase = remote_flash_erase; |
6296 | 6353 | remote_async_ops.to_flash_done = remote_flash_done; |
6297 | - remote_ops.to_read_description = remote_read_description; | |
6354 | + remote_async_ops.to_read_description = remote_read_description; | |
6355 | + remote_async_ops.to_doing_call = remote_doing_call; | |
6298 | 6356 | } |
6299 | 6357 | |
6300 | 6358 | /* Set up the async extended remote vector by making a copy of the standard |
@@ -0,0 +1,197 @@ | ||
1 | +/* Reverse execution and reverse debugging. | |
2 | + | |
3 | + Copyright (C) 2006 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GDB. | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
20 | + Boston, MA 02110-1301, USA. */ | |
21 | + | |
22 | +#include "defs.h" | |
23 | +#include "gdb_string.h" | |
24 | +#include "target.h" | |
25 | +#include "top.h" | |
26 | +#include "cli/cli-cmds.h" | |
27 | +#include "cli/cli-decode.h" | |
28 | + | |
29 | +/* User interface for reverse debugging: | |
30 | + Set exec-direction / show exec-direction commands | |
31 | + (returns error unles target implements to_set_execdir method). */ | |
32 | + | |
33 | +static const char exec_forward[] = "forward"; | |
34 | +static const char exec_reverse[] = "reverse"; | |
35 | +static const char *exec_direction = exec_forward; | |
36 | +static const char *exec_direction_names[] = { | |
37 | + exec_forward, | |
38 | + exec_reverse, | |
39 | + NULL | |
40 | +}; | |
41 | + | |
42 | +static void | |
43 | +set_exec_direction_func (char *args, int from_tty, | |
44 | + struct cmd_list_element *cmd) | |
45 | +{ | |
46 | + if (target_get_execution_direction () != EXEC_ERROR) | |
47 | + { | |
48 | + enum exec_direction_kind dir = EXEC_ERROR; | |
49 | + | |
50 | + if (!strcmp (exec_direction, exec_forward)) | |
51 | + dir = EXEC_FORWARD; | |
52 | + else if (!strcmp (exec_direction, exec_reverse)) | |
53 | + dir = EXEC_REVERSE; | |
54 | + | |
55 | + if (target_set_execution_direction (dir) != EXEC_ERROR) | |
56 | + return; | |
57 | + } | |
58 | + error (_("Target `%s' does not support execution-direction."), | |
59 | + target_shortname); | |
60 | +} | |
61 | + | |
62 | +static void | |
63 | +show_exec_direction_func (struct ui_file *out, int from_tty, | |
64 | + struct cmd_list_element *cmd, const char *value) | |
65 | +{ | |
66 | + enum exec_direction_kind dir = target_get_execution_direction (); | |
67 | + | |
68 | + switch (dir) { | |
69 | + case EXEC_FORWARD: | |
70 | + fprintf_filtered (out, "Forward.\n"); | |
71 | + break; | |
72 | + case EXEC_REVERSE: | |
73 | + fprintf_filtered (out, "Reverse.\n"); | |
74 | + break; | |
75 | + case EXEC_ERROR: | |
76 | + default: | |
77 | + error (_("Target `%s' does not support execution-direction."), | |
78 | + target_shortname); | |
79 | + break; | |
80 | + } | |
81 | +} | |
82 | + | |
83 | +/* User interface: | |
84 | + reverse-step, reverse-next etc. | |
85 | + (returns error unles target implements to_set_execdir method). */ | |
86 | + | |
87 | +static void execdir_default (void *notused) | |
88 | +{ | |
89 | + /* Return execution direction to default state. */ | |
90 | + target_set_execution_direction (EXEC_FORWARD); | |
91 | +} | |
92 | + | |
93 | +static void | |
94 | +exec_reverse_once (char *cmd, char *args, int from_tty) | |
95 | +{ | |
96 | + /* String buffer for command consing. */ | |
97 | + char reverse_command[512]; | |
98 | + enum exec_direction_kind dir = target_get_execution_direction (); | |
99 | + | |
100 | + if (dir == EXEC_ERROR) | |
101 | + error (_("Target %s does not support this command."), target_shortname); | |
102 | + | |
103 | + if (dir == EXEC_REVERSE) | |
104 | + error (_("Already in reverse mode. Use '%s' or 'set exec-dir forward'."), | |
105 | + cmd); | |
106 | + | |
107 | + if (target_set_execution_direction (EXEC_REVERSE) == EXEC_ERROR) | |
108 | + error (_("Target %s does not support this command."), target_shortname); | |
109 | + | |
110 | + make_cleanup (execdir_default, NULL); | |
111 | + sprintf (reverse_command, "%s %s", cmd, args ? args : ""); | |
112 | + execute_command (reverse_command, from_tty); | |
113 | +} | |
114 | + | |
115 | +static void | |
116 | +reverse_step (char *args, int from_tty) | |
117 | +{ | |
118 | + exec_reverse_once ("step", args, from_tty); | |
119 | +} | |
120 | + | |
121 | +static void | |
122 | +reverse_stepi (char *args, int from_tty) | |
123 | +{ | |
124 | + exec_reverse_once ("stepi", args, from_tty); | |
125 | +} | |
126 | + | |
127 | +static void | |
128 | +reverse_next (char *args, int from_tty) | |
129 | +{ | |
130 | + exec_reverse_once ("next", args, from_tty); | |
131 | +} | |
132 | + | |
133 | +static void | |
134 | +reverse_nexti (char *args, int from_tty) | |
135 | +{ | |
136 | + exec_reverse_once ("nexti", args, from_tty); | |
137 | +} | |
138 | + | |
139 | +static void | |
140 | +reverse_continue (char *args, int from_tty) | |
141 | +{ | |
142 | + exec_reverse_once ("continue", args, from_tty); | |
143 | +} | |
144 | + | |
145 | +static void | |
146 | +reverse_finish (char *args, int from_tty) | |
147 | +{ | |
148 | + exec_reverse_once ("finish", args, from_tty); | |
149 | +} | |
150 | + | |
151 | +void | |
152 | +_initialize_reverse (void) | |
153 | +{ | |
154 | + add_setshow_enum_cmd ("exec-direction", class_run, exec_direction_names, | |
155 | + &exec_direction, "Set direction of execution.\n\ | |
156 | +Options are 'forward' or 'reverse'.", | |
157 | + "Show direction of execution (forward/reverse).", | |
158 | + "Tells gdb whether to execute forward or backward.", | |
159 | + set_exec_direction_func, show_exec_direction_func, | |
160 | + &setlist, &showlist); | |
161 | + | |
162 | + add_com ("reverse-step", class_run, reverse_step, _("\ | |
163 | +Step program backward until it reaches the beginning of another source line.\n\ | |
164 | +Argument N means do this N times (or till program stops for another reason).") | |
165 | + ); | |
166 | + add_com_alias ("rs", "reverse-step", class_alias, 1); | |
167 | + | |
168 | + add_com ("reverse-next", class_run, reverse_next, _("\ | |
169 | +Step program backward, proceeding through subroutine calls.\n\ | |
170 | +Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\ | |
171 | +when they do, the call is treated as one instruction.\n\ | |
172 | +Argument N means do this N times (or till program stops for another reason).") | |
173 | + ); | |
174 | + add_com_alias ("rn", "reverse-next", class_alias, 1); | |
175 | + | |
176 | + add_com ("reverse-stepi", class_run, reverse_stepi, _("\ | |
177 | +Step backward exactly one instruction.\n\ | |
178 | +Argument N means do this N times (or till program stops for another reason).") | |
179 | + ); | |
180 | + add_com_alias ("rsi", "reverse-stepi", class_alias, 0); | |
181 | + | |
182 | + add_com ("reverse-nexti", class_run, reverse_nexti, _("\ | |
183 | +Step backward one instruction, but proceed through called subroutines.\n\ | |
184 | +Argument N means do this N times (or till program stops for another reason).") | |
185 | + ); | |
186 | + add_com_alias ("rni", "reverse-nexti", class_alias, 0); | |
187 | + | |
188 | + add_com ("reverse-continue", class_run, reverse_continue, _("\ | |
189 | +Continue program being debugged, running in reverse.\n\ | |
190 | +If proceeding from breakpoint, a number N may be used as an argument,\n\ | |
191 | +which means to set the ignore count of that breakpoint to N - 1 (so that\n\ | |
192 | +the breakpoint won't break until the Nth time it is reached).")); | |
193 | + add_com_alias ("rc", "reverse-continue", class_alias, 0); | |
194 | + | |
195 | + add_com ("reverse-finish", class_run, reverse_finish, _("\ | |
196 | +Execute backward until just before selected stack frame is called.")); | |
197 | +} |
@@ -466,6 +466,9 @@ update_current_target (void) | ||
466 | 466 | INHERIT (to_find_memory_regions, t); |
467 | 467 | INHERIT (to_make_corefile_notes, t); |
468 | 468 | INHERIT (to_get_thread_local_address, t); |
469 | + INHERIT (to_get_execdir, t); | |
470 | + INHERIT (to_set_execdir, t); | |
471 | + INHERIT (to_doing_call, t); | |
469 | 472 | /* Do not inherit to_read_description. */ |
470 | 473 | INHERIT (to_magic, t); |
471 | 474 | /* Do not inherit to_memory_map. */ |
@@ -644,6 +647,9 @@ update_current_target (void) | ||
644 | 647 | de_fault (to_async, |
645 | 648 | (void (*) (void (*) (enum inferior_event_type, void*), void*)) |
646 | 649 | tcomplain); |
650 | + de_fault (to_doing_call, | |
651 | + (void (*) (int)) | |
652 | + target_ignore); | |
647 | 653 | current_target.to_read_description = NULL; |
648 | 654 | #undef de_fault |
649 | 655 |
@@ -131,7 +131,11 @@ enum target_waitkind | ||
131 | 131 | inferior, rather than being stuck in the remote_async_wait() |
132 | 132 | function. This way the event loop is responsive to other events, |
133 | 133 | like for instance the user typing. */ |
134 | - TARGET_WAITKIND_IGNORE | |
134 | + TARGET_WAITKIND_IGNORE, | |
135 | + | |
136 | + /* The target has run out of history information, | |
137 | + and cannot run backward any further. */ | |
138 | + TARGET_WAITKIND_NO_HISTORY | |
135 | 139 | }; |
136 | 140 | |
137 | 141 | struct target_waitstatus |
@@ -150,6 +154,14 @@ struct target_waitstatus | ||
150 | 154 | value; |
151 | 155 | }; |
152 | 156 | |
157 | +/* Reverse execution. */ | |
158 | +enum exec_direction_kind | |
159 | + { | |
160 | + EXEC_FORWARD, | |
161 | + EXEC_REVERSE, | |
162 | + EXEC_ERROR | |
163 | + }; | |
164 | + | |
153 | 165 | /* Possible types of events that the inferior handler will have to |
154 | 166 | deal with. */ |
155 | 167 | enum inferior_event_type |
@@ -500,6 +512,13 @@ struct target_ops | ||
500 | 512 | was available. */ |
501 | 513 | const struct target_desc *(*to_read_description) (struct target_ops *ops); |
502 | 514 | |
515 | + /* Set execution direction (forward/reverse). */ | |
516 | + int (*to_set_execdir) (enum exec_direction_kind); | |
517 | + /* Get execution direction (forward/reverse). */ | |
518 | + enum exec_direction_kind (*to_get_execdir) (void); | |
519 | + | |
520 | + void (*to_doing_call) (int starting); | |
521 | + | |
503 | 522 | int to_magic; |
504 | 523 | /* Need sub-structure for target machine related rather than comm related? |
505 | 524 | */ |
@@ -1194,6 +1213,18 @@ extern int target_stopped_data_address_p (struct target_ops *); | ||
1194 | 1213 | #define target_stopped_data_address_p(CURRENT_TARGET) (1) |
1195 | 1214 | #endif |
1196 | 1215 | |
1216 | +/* Forward/reverse execution direction. | |
1217 | + These will only be implemented by a target that supports reverse execution. | |
1218 | +*/ | |
1219 | +#define target_get_execution_direction() \ | |
1220 | + (current_target.to_get_execdir ? \ | |
1221 | + (*current_target.to_get_execdir) () : EXEC_ERROR) | |
1222 | + | |
1223 | +#define target_set_execution_direction(DIR) \ | |
1224 | + (current_target.to_set_execdir ? \ | |
1225 | + (*current_target.to_set_execdir) (DIR) : EXEC_ERROR) | |
1226 | + | |
1227 | + | |
1197 | 1228 | extern const struct target_desc *target_read_description (struct target_ops *); |
1198 | 1229 | |
1199 | 1230 | /* Routines for maintenance of the target structures... |