Mercurial > vim
comparison src/ex_cmds2.c @ 7605:8fc60af6dbf5 v7.4.1102
commit https://github.com/vim/vim/commit/f1f60f859cdbb2638b3662ccf7b1d179865fe7dc
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Jan 16 15:40:53 2016 +0100
patch 7.4.1102
Problem: Debugger has no stack backtrace support.
Solution: Add "backtrace", "frame", "up" and "down" commands. (Alberto
Fanjul, closes https://github.com/vim/vim/issues/433)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 16 Jan 2016 15:45:04 +0100 |
parents | 15eefe1b0dad |
children | b4384c581806 |
comparison
equal
deleted
inserted
replaced
7604:09a1aca8d980 | 7605:8fc60af6dbf5 |
---|---|
66 #endif | 66 #endif |
67 | 67 |
68 #if defined(FEAT_EVAL) || defined(PROTO) | 68 #if defined(FEAT_EVAL) || defined(PROTO) |
69 static int debug_greedy = FALSE; /* batch mode debugging: don't save | 69 static int debug_greedy = FALSE; /* batch mode debugging: don't save |
70 and restore typeahead. */ | 70 and restore typeahead. */ |
71 static int get_maxbacktrace_level(void); | |
72 static void do_setdebugtracelevel(char_u *arg); | |
73 static void do_checkbacktracelevel(void); | |
74 static void do_showbacktrace(char_u *cmd); | |
71 | 75 |
72 /* | 76 /* |
73 * do_debug(): Debug mode. | 77 * do_debug(): Debug mode. |
74 * Repeatedly get Ex commands, until told to continue normal execution. | 78 * Repeatedly get Ex commands, until told to continue normal execution. |
75 */ | 79 */ |
99 #define CMD_NEXT 2 | 103 #define CMD_NEXT 2 |
100 #define CMD_STEP 3 | 104 #define CMD_STEP 3 |
101 #define CMD_FINISH 4 | 105 #define CMD_FINISH 4 |
102 #define CMD_QUIT 5 | 106 #define CMD_QUIT 5 |
103 #define CMD_INTERRUPT 6 | 107 #define CMD_INTERRUPT 6 |
108 #define CMD_BACKTRACE 7 | |
109 #define CMD_FRAME 8 | |
110 #define CMD_UP 9 | |
111 #define CMD_DOWN 10 | |
104 | 112 |
105 #ifdef ALWAYS_USE_GUI | 113 #ifdef ALWAYS_USE_GUI |
106 /* Can't do this when there is no terminal for input/output. */ | 114 /* Can't do this when there is no terminal for input/output. */ |
107 if (!gui.in_use) | 115 if (!gui.in_use) |
108 { | 116 { |
176 # ifdef FEAT_EX_EXTRA | 184 # ifdef FEAT_EX_EXTRA |
177 ex_normal_busy = save_ex_normal_busy; | 185 ex_normal_busy = save_ex_normal_busy; |
178 # endif | 186 # endif |
179 | 187 |
180 cmdline_row = msg_row; | 188 cmdline_row = msg_row; |
189 msg_starthere(); | |
181 if (cmdline != NULL) | 190 if (cmdline != NULL) |
182 { | 191 { |
183 /* If this is a debug command, set "last_cmd". | 192 /* If this is a debug command, set "last_cmd". |
184 * If not, reset "last_cmd". | 193 * If not, reset "last_cmd". |
185 * For a blank line use previous command. */ | 194 * For a blank line use previous command. */ |
195 tail = "ext"; | 204 tail = "ext"; |
196 break; | 205 break; |
197 case 's': last_cmd = CMD_STEP; | 206 case 's': last_cmd = CMD_STEP; |
198 tail = "tep"; | 207 tail = "tep"; |
199 break; | 208 break; |
200 case 'f': last_cmd = CMD_FINISH; | 209 case 'f': |
201 tail = "inish"; | 210 last_cmd = 0; |
211 if (p[1] == 'r') | |
212 { | |
213 last_cmd = CMD_FRAME; | |
214 tail = "rame"; | |
215 } | |
216 else | |
217 { | |
218 last_cmd = CMD_FINISH; | |
219 tail = "inish"; | |
220 } | |
202 break; | 221 break; |
203 case 'q': last_cmd = CMD_QUIT; | 222 case 'q': last_cmd = CMD_QUIT; |
204 tail = "uit"; | 223 tail = "uit"; |
205 break; | 224 break; |
206 case 'i': last_cmd = CMD_INTERRUPT; | 225 case 'i': last_cmd = CMD_INTERRUPT; |
207 tail = "nterrupt"; | 226 tail = "nterrupt"; |
227 break; | |
228 case 'b': last_cmd = CMD_BACKTRACE; | |
229 if (p[1] == 't') | |
230 tail = "t"; | |
231 else | |
232 tail = "acktrace"; | |
233 break; | |
234 case 'w': last_cmd = CMD_BACKTRACE; | |
235 tail = "here"; | |
236 break; | |
237 case 'u': last_cmd = CMD_UP; | |
238 tail = "p"; | |
239 break; | |
240 case 'd': last_cmd = CMD_DOWN; | |
241 tail = "own"; | |
208 break; | 242 break; |
209 default: last_cmd = 0; | 243 default: last_cmd = 0; |
210 } | 244 } |
211 if (last_cmd != 0) | 245 if (last_cmd != 0) |
212 { | 246 { |
215 while (*p != NUL && *p == *tail) | 249 while (*p != NUL && *p == *tail) |
216 { | 250 { |
217 ++p; | 251 ++p; |
218 ++tail; | 252 ++tail; |
219 } | 253 } |
220 if (ASCII_ISALPHA(*p)) | 254 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) |
221 last_cmd = 0; | 255 last_cmd = 0; |
222 } | 256 } |
223 } | 257 } |
224 | 258 |
225 if (last_cmd != 0) | 259 if (last_cmd != 0) |
248 got_int = TRUE; | 282 got_int = TRUE; |
249 debug_break_level = 9999; | 283 debug_break_level = 9999; |
250 /* Do not repeat ">interrupt" cmd, continue stepping. */ | 284 /* Do not repeat ">interrupt" cmd, continue stepping. */ |
251 last_cmd = CMD_STEP; | 285 last_cmd = CMD_STEP; |
252 break; | 286 break; |
287 case CMD_BACKTRACE: | |
288 do_showbacktrace(cmd); | |
289 continue; | |
290 case CMD_FRAME: | |
291 if (*p == NUL) | |
292 { | |
293 do_showbacktrace(cmd); | |
294 } | |
295 else | |
296 { | |
297 p = skipwhite(p); | |
298 do_setdebugtracelevel(p); | |
299 } | |
300 continue; | |
301 case CMD_UP: | |
302 debug_backtrace_level++; | |
303 do_checkbacktracelevel(); | |
304 continue; | |
305 case CMD_DOWN: | |
306 debug_backtrace_level--; | |
307 do_checkbacktracelevel(); | |
308 continue; | |
253 } | 309 } |
310 /* Going out reset backtrace_level */ | |
311 debug_backtrace_level = 0; | |
254 break; | 312 break; |
255 } | 313 } |
256 | 314 |
257 /* don't debug this command */ | 315 /* don't debug this command */ |
258 n = debug_break_level; | 316 n = debug_break_level; |
281 redir_off = save_redir_off; | 339 redir_off = save_redir_off; |
282 | 340 |
283 /* Only print the message again when typing a command before coming back | 341 /* Only print the message again when typing a command before coming back |
284 * here. */ | 342 * here. */ |
285 debug_did_msg = TRUE; | 343 debug_did_msg = TRUE; |
344 } | |
345 | |
346 static int | |
347 get_maxbacktrace_level(void) | |
348 { | |
349 char *p, *q; | |
350 int maxbacktrace = 1; | |
351 | |
352 maxbacktrace = 0; | |
353 if (sourcing_name != NULL) | |
354 { | |
355 p = (char *)sourcing_name; | |
356 while ((q = strstr(p, "..")) != NULL) | |
357 { | |
358 p = q + 2; | |
359 maxbacktrace++; | |
360 } | |
361 } | |
362 return maxbacktrace; | |
363 } | |
364 | |
365 static void | |
366 do_setdebugtracelevel(char_u *arg) | |
367 { | |
368 int level; | |
369 | |
370 level = atoi((char *)arg); | |
371 if (*arg == '+' || level < 0) | |
372 debug_backtrace_level += level; | |
373 else | |
374 debug_backtrace_level = level; | |
375 | |
376 do_checkbacktracelevel(); | |
377 } | |
378 | |
379 static void | |
380 do_checkbacktracelevel(void) | |
381 { | |
382 if (debug_backtrace_level < 0) | |
383 { | |
384 debug_backtrace_level = 0; | |
385 MSG(_("frame is zero")); | |
386 } | |
387 else | |
388 { | |
389 int max = get_maxbacktrace_level(); | |
390 | |
391 if (debug_backtrace_level > max) | |
392 { | |
393 debug_backtrace_level = max; | |
394 smsg((char_u *)_("frame at highest level: %d"), max); | |
395 } | |
396 } | |
397 } | |
398 | |
399 static void | |
400 do_showbacktrace(char_u *cmd) | |
401 { | |
402 char *cur; | |
403 char *next; | |
404 int i = 0; | |
405 int max = get_maxbacktrace_level(); | |
406 | |
407 if (sourcing_name != NULL) | |
408 { | |
409 cur = (char *)sourcing_name; | |
410 while (!got_int) | |
411 { | |
412 next = strstr(cur, ".."); | |
413 if (next != NULL) | |
414 *next = NUL; | |
415 if (i == max - debug_backtrace_level) | |
416 smsg((char_u *)"->%d %s", max - i, cur); | |
417 else | |
418 smsg((char_u *)" %d %s", max - i, cur); | |
419 ++i; | |
420 if (next == NULL) | |
421 break; | |
422 *next = '.'; | |
423 cur = next + 2; | |
424 } | |
425 } | |
426 if (sourcing_lnum != 0) | |
427 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd); | |
428 else | |
429 smsg((char_u *)_("cmd: %s"), cmd); | |
286 } | 430 } |
287 | 431 |
288 /* | 432 /* |
289 * ":debug". | 433 * ":debug". |
290 */ | 434 */ |