GDB (API)
|
00001 /* Reverse execution and reverse debugging. 00002 00003 Copyright (C) 2006-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "gdb_string.h" 00022 #include "target.h" 00023 #include "top.h" 00024 #include "cli/cli-cmds.h" 00025 #include "cli/cli-decode.h" 00026 #include "cli/cli-utils.h" 00027 #include "inferior.h" 00028 #include "regcache.h" 00029 00030 /* User interface: 00031 reverse-step, reverse-next etc. */ 00032 00033 static void 00034 exec_direction_default (void *notused) 00035 { 00036 /* Return execution direction to default state. */ 00037 execution_direction = EXEC_FORWARD; 00038 } 00039 00040 /* exec_reverse_once -- accepts an arbitrary gdb command (string), 00041 and executes it with exec-direction set to 'reverse'. 00042 00043 Used to implement reverse-next etc. commands. */ 00044 00045 static void 00046 exec_reverse_once (char *cmd, char *args, int from_tty) 00047 { 00048 char *reverse_command; 00049 enum exec_direction_kind dir = execution_direction; 00050 struct cleanup *old_chain; 00051 00052 if (dir == EXEC_REVERSE) 00053 error (_("Already in reverse mode. Use '%s' or 'set exec-dir forward'."), 00054 cmd); 00055 00056 if (!target_can_execute_reverse) 00057 error (_("Target %s does not support this command."), target_shortname); 00058 00059 reverse_command = xstrprintf ("%s %s", cmd, args ? args : ""); 00060 old_chain = make_cleanup (exec_direction_default, NULL); 00061 make_cleanup (xfree, reverse_command); 00062 execution_direction = EXEC_REVERSE; 00063 execute_command (reverse_command, from_tty); 00064 do_cleanups (old_chain); 00065 } 00066 00067 static void 00068 reverse_step (char *args, int from_tty) 00069 { 00070 exec_reverse_once ("step", args, from_tty); 00071 } 00072 00073 static void 00074 reverse_stepi (char *args, int from_tty) 00075 { 00076 exec_reverse_once ("stepi", args, from_tty); 00077 } 00078 00079 static void 00080 reverse_next (char *args, int from_tty) 00081 { 00082 exec_reverse_once ("next", args, from_tty); 00083 } 00084 00085 static void 00086 reverse_nexti (char *args, int from_tty) 00087 { 00088 exec_reverse_once ("nexti", args, from_tty); 00089 } 00090 00091 static void 00092 reverse_continue (char *args, int from_tty) 00093 { 00094 exec_reverse_once ("continue", args, from_tty); 00095 } 00096 00097 static void 00098 reverse_finish (char *args, int from_tty) 00099 { 00100 exec_reverse_once ("finish", args, from_tty); 00101 } 00102 00103 /* Data structures for a bookmark list. */ 00104 00105 struct bookmark { 00106 struct bookmark *next; 00107 int number; 00108 CORE_ADDR pc; 00109 struct symtab_and_line sal; 00110 gdb_byte *opaque_data; 00111 }; 00112 00113 static struct bookmark *bookmark_chain; 00114 static int bookmark_count; 00115 00116 #define ALL_BOOKMARKS(B) for ((B) = bookmark_chain; (B); (B) = (B)->next) 00117 00118 #define ALL_BOOKMARKS_SAFE(B,TMP) \ 00119 for ((B) = bookmark_chain; \ 00120 (B) ? ((TMP) = (B)->next, 1) : 0; \ 00121 (B) = (TMP)) 00122 00123 /* save_bookmark_command -- implement "bookmark" command. 00124 Call target method to get a bookmark identifier. 00125 Insert bookmark identifier into list. 00126 00127 Identifier will be a malloc string (gdb_byte *). 00128 Up to us to free it as required. */ 00129 00130 static void 00131 save_bookmark_command (char *args, int from_tty) 00132 { 00133 /* Get target's idea of a bookmark. */ 00134 gdb_byte *bookmark_id = target_get_bookmark (args, from_tty); 00135 struct bookmark *b, *b1; 00136 struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ()); 00137 00138 /* CR should not cause another identical bookmark. */ 00139 dont_repeat (); 00140 00141 if (bookmark_id == NULL) 00142 error (_("target_get_bookmark failed.")); 00143 00144 /* Set up a bookmark struct. */ 00145 b = xcalloc (1, sizeof (struct bookmark)); 00146 b->number = ++bookmark_count; 00147 init_sal (&b->sal); 00148 b->pc = regcache_read_pc (get_current_regcache ()); 00149 b->sal = find_pc_line (b->pc, 0); 00150 b->sal.pspace = get_frame_program_space (get_current_frame ()); 00151 b->opaque_data = bookmark_id; 00152 b->next = NULL; 00153 00154 /* Add this bookmark to the end of the chain, so that a list 00155 of bookmarks will come out in order of increasing numbers. */ 00156 00157 b1 = bookmark_chain; 00158 if (b1 == 0) 00159 bookmark_chain = b; 00160 else 00161 { 00162 while (b1->next) 00163 b1 = b1->next; 00164 b1->next = b; 00165 } 00166 printf_filtered (_("Saved bookmark %d at %s\n"), b->number, 00167 paddress (gdbarch, b->sal.pc)); 00168 } 00169 00170 /* Implement "delete bookmark" command. */ 00171 00172 static int 00173 delete_one_bookmark (int num) 00174 { 00175 struct bookmark *b1, *b; 00176 00177 /* Find bookmark with corresponding number. */ 00178 ALL_BOOKMARKS (b) 00179 if (b->number == num) 00180 break; 00181 00182 /* Special case, first item in list. */ 00183 if (b == bookmark_chain) 00184 bookmark_chain = b->next; 00185 00186 /* Find bookmark preceding "marked" one, so we can unlink. */ 00187 if (b) 00188 { 00189 ALL_BOOKMARKS (b1) 00190 if (b1->next == b) 00191 { 00192 /* Found designated bookmark. Unlink and delete. */ 00193 b1->next = b->next; 00194 break; 00195 } 00196 xfree (b->opaque_data); 00197 xfree (b); 00198 return 1; /* success */ 00199 } 00200 return 0; /* failure */ 00201 } 00202 00203 static void 00204 delete_all_bookmarks (void) 00205 { 00206 struct bookmark *b, *b1; 00207 00208 ALL_BOOKMARKS_SAFE (b, b1) 00209 { 00210 xfree (b->opaque_data); 00211 xfree (b); 00212 } 00213 bookmark_chain = NULL; 00214 } 00215 00216 static void 00217 delete_bookmark_command (char *args, int from_tty) 00218 { 00219 int num; 00220 struct get_number_or_range_state state; 00221 00222 if (bookmark_chain == NULL) 00223 { 00224 warning (_("No bookmarks.")); 00225 return; 00226 } 00227 00228 if (args == NULL || args[0] == '\0') 00229 { 00230 if (from_tty && !query (_("Delete all bookmarks? "))) 00231 return; 00232 delete_all_bookmarks (); 00233 return; 00234 } 00235 00236 init_number_or_range (&state, args); 00237 while (!state.finished) 00238 { 00239 num = get_number_or_range (&state); 00240 if (!delete_one_bookmark (num)) 00241 /* Not found. */ 00242 warning (_("No bookmark #%d."), num); 00243 } 00244 } 00245 00246 /* Implement "goto-bookmark" command. */ 00247 00248 static void 00249 goto_bookmark_command (char *args, int from_tty) 00250 { 00251 struct bookmark *b; 00252 unsigned long num; 00253 00254 if (args == NULL || args[0] == '\0') 00255 error (_("Command requires an argument.")); 00256 00257 if (strncmp (args, "start", strlen ("start")) == 0 00258 || strncmp (args, "begin", strlen ("begin")) == 0 00259 || strncmp (args, "end", strlen ("end")) == 0) 00260 { 00261 /* Special case. Give target opportunity to handle. */ 00262 target_goto_bookmark ((gdb_byte *) args, from_tty); 00263 return; 00264 } 00265 00266 if (args[0] == '\'' || args[0] == '\"') 00267 { 00268 /* Special case -- quoted string. Pass on to target. */ 00269 if (args[strlen (args) - 1] != args[0]) 00270 error (_("Unbalanced quotes: %s"), args); 00271 target_goto_bookmark ((gdb_byte *) args, from_tty); 00272 return; 00273 } 00274 00275 /* General case. Bookmark identified by bookmark number. */ 00276 num = get_number (&args); 00277 ALL_BOOKMARKS (b) 00278 if (b->number == num) 00279 break; 00280 00281 if (b) 00282 { 00283 /* Found. Send to target method. */ 00284 target_goto_bookmark (b->opaque_data, from_tty); 00285 return; 00286 } 00287 /* Not found. */ 00288 error (_("goto-bookmark: no bookmark found for '%s'."), args); 00289 } 00290 00291 static int 00292 bookmark_1 (int bnum) 00293 { 00294 struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ()); 00295 struct bookmark *b; 00296 int matched = 0; 00297 00298 ALL_BOOKMARKS (b) 00299 { 00300 if (bnum == -1 || bnum == b->number) 00301 { 00302 printf_filtered (" %d %s '%s'\n", 00303 b->number, 00304 paddress (gdbarch, b->pc), 00305 b->opaque_data); 00306 matched++; 00307 } 00308 } 00309 00310 if (bnum > 0 && matched == 0) 00311 printf_filtered ("No bookmark #%d\n", bnum); 00312 00313 return matched; 00314 } 00315 00316 /* Implement "info bookmarks" command. */ 00317 00318 static void 00319 bookmarks_info (char *args, int from_tty) 00320 { 00321 int bnum = -1; 00322 00323 if (!bookmark_chain) 00324 printf_filtered (_("No bookmarks.\n")); 00325 else if (args == NULL || *args == '\0') 00326 bookmark_1 (-1); 00327 else 00328 { 00329 struct get_number_or_range_state state; 00330 00331 init_number_or_range (&state, args); 00332 while (!state.finished) 00333 { 00334 bnum = get_number_or_range (&state); 00335 bookmark_1 (bnum); 00336 } 00337 } 00338 } 00339 00340 00341 /* Provide a prototype to silence -Wmissing-prototypes. */ 00342 extern initialize_file_ftype _initialize_reverse; 00343 00344 void 00345 _initialize_reverse (void) 00346 { 00347 add_com ("reverse-step", class_run, reverse_step, _("\ 00348 Step program backward until it reaches the beginning of another source line.\n\ 00349 Argument N means do this N times (or till program stops for another reason).") 00350 ); 00351 add_com_alias ("rs", "reverse-step", class_alias, 1); 00352 00353 add_com ("reverse-next", class_run, reverse_next, _("\ 00354 Step program backward, proceeding through subroutine calls.\n\ 00355 Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\ 00356 when they do, the call is treated as one instruction.\n\ 00357 Argument N means do this N times (or till program stops for another reason).") 00358 ); 00359 add_com_alias ("rn", "reverse-next", class_alias, 1); 00360 00361 add_com ("reverse-stepi", class_run, reverse_stepi, _("\ 00362 Step backward exactly one instruction.\n\ 00363 Argument N means do this N times (or till program stops for another reason).") 00364 ); 00365 add_com_alias ("rsi", "reverse-stepi", class_alias, 0); 00366 00367 add_com ("reverse-nexti", class_run, reverse_nexti, _("\ 00368 Step backward one instruction, but proceed through called subroutines.\n\ 00369 Argument N means do this N times (or till program stops for another reason).") 00370 ); 00371 add_com_alias ("rni", "reverse-nexti", class_alias, 0); 00372 00373 add_com ("reverse-continue", class_run, reverse_continue, _("\ 00374 Continue program being debugged but run it in reverse.\n\ 00375 If proceeding from breakpoint, a number N may be used as an argument,\n\ 00376 which means to set the ignore count of that breakpoint to N - 1 (so that\n\ 00377 the breakpoint won't break until the Nth time it is reached).")); 00378 add_com_alias ("rc", "reverse-continue", class_alias, 0); 00379 00380 add_com ("reverse-finish", class_run, reverse_finish, _("\ 00381 Execute backward until just before selected stack frame is called.")); 00382 00383 add_com ("bookmark", class_bookmark, save_bookmark_command, _("\ 00384 Set a bookmark in the program's execution history.\n\ 00385 A bookmark represents a point in the execution history \n\ 00386 that can be returned to at a later point in the debug session.")); 00387 add_info ("bookmarks", bookmarks_info, _("\ 00388 Status of user-settable bookmarks.\n\ 00389 Bookmarks are user-settable markers representing a point in the \n\ 00390 execution history that can be returned to later in the same debug \n\ 00391 session.")); 00392 add_cmd ("bookmark", class_bookmark, delete_bookmark_command, _("\ 00393 Delete a bookmark from the bookmark list.\n\ 00394 Argument is a bookmark number or numbers,\n\ 00395 or no argument to delete all bookmarks.\n"), 00396 &deletelist); 00397 add_com ("goto-bookmark", class_bookmark, goto_bookmark_command, _("\ 00398 Go to an earlier-bookmarked point in the program's execution history.\n\ 00399 Argument is the bookmark number of a bookmark saved earlier by using \n\ 00400 the 'bookmark' command, or the special arguments:\n\ 00401 start (beginning of recording)\n\ 00402 end (end of recording)\n")); 00403 }