Mercurial > octave-nkf
comparison libinterp/corefcn/toplev.cc @ 19449:972abb60c30f
emit stack trace immediately at point of error
* error.cc (pr_where): Get stack trace info in list of frames
instead of octave_map.
(error_2): Always display stack trace here, not just when entering
debug mode.
* toplev.h, toplev.cc (octave_call_stack::stack_frame): Rename from
octave_call_stack::call_stack_elt. Change all uses.
Declare as class instead of struct. Make data privave.
(stack_frame::line, stack_frame::column, stack_frame::fcn_file_name,
stack_frame::fcn_name): New methods.
(octave_call_stack::backtrace): Allow calling with zero or one arg.
(octave_call_stack::backtrace_frames,
octave_call_stack::do_backtrace_frames): New methods.x
(octave_call_stack::backtrace_error_message,
octave_call_stack::do_backtrace_error_message): Delete.
* ov-oncleanup.cc (octave_oncleanup::~octave_oncleanup):
Don't print stack trace here.
* ov-usr-fcn.cc (octave_user_script::do_multi_index_op,
octave_user_fcn::do_multi_index_op): Don't print stack trace here.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sun, 21 Dec 2014 17:49:28 -0500 |
parents | 03067dab10ca |
children | db92e7e28e1f |
comparison
equal
deleted
inserted
replaced
19448:a2a79462b7b8 | 19449:972abb60c30f |
---|---|
102 // TRUE means we've processed all the init code and we are good to go. | 102 // TRUE means we've processed all the init code and we are good to go. |
103 bool octave_initialized = false; | 103 bool octave_initialized = false; |
104 | 104 |
105 octave_call_stack *octave_call_stack::instance = 0; | 105 octave_call_stack *octave_call_stack::instance = 0; |
106 | 106 |
107 std::string | |
108 octave_call_stack::stack_frame::fcn_file_name (void) const | |
109 { | |
110 return m_fcn ? m_fcn->fcn_file_name () : std::string (); | |
111 } | |
112 | |
113 std::string | |
114 octave_call_stack::stack_frame::fcn_name (bool print_subfn) const | |
115 { | |
116 std::string retval; | |
117 | |
118 if (m_fcn) | |
119 { | |
120 std::string parent_fcn_name = m_fcn->parent_fcn_name (); | |
121 | |
122 if (print_subfn && ! parent_fcn_name.empty ()) | |
123 retval = parent_fcn_name + Vfilemarker; | |
124 | |
125 retval += m_fcn->name (); | |
126 } | |
127 else | |
128 retval = "<unknown>"; | |
129 | |
130 return retval; | |
131 } | |
132 | |
107 void | 133 void |
108 octave_call_stack::create_instance (void) | 134 octave_call_stack::create_instance (void) |
109 { | 135 { |
110 instance = new octave_call_stack (); | 136 instance = new octave_call_stack (); |
111 | 137 |
122 { | 148 { |
123 int retval = -1; | 149 int retval = -1; |
124 | 150 |
125 if (! cs.empty ()) | 151 if (! cs.empty ()) |
126 { | 152 { |
127 const call_stack_elt& elt = cs[curr_frame]; | 153 const stack_frame& elt = cs[curr_frame]; |
128 retval = elt.line; | 154 retval = elt.m_line; |
129 } | 155 } |
130 | 156 |
131 return retval; | 157 return retval; |
132 } | 158 } |
133 | 159 |
136 { | 162 { |
137 int retval = -1; | 163 int retval = -1; |
138 | 164 |
139 if (! cs.empty ()) | 165 if (! cs.empty ()) |
140 { | 166 { |
141 const call_stack_elt& elt = cs[curr_frame]; | 167 const stack_frame& elt = cs[curr_frame]; |
142 retval = elt.column; | 168 retval = elt.m_column; |
143 } | 169 } |
144 | 170 |
145 return retval; | 171 return retval; |
146 } | 172 } |
147 | 173 |
152 | 178 |
153 const_iterator p = cs.end (); | 179 const_iterator p = cs.end (); |
154 | 180 |
155 while (p != cs.begin ()) | 181 while (p != cs.begin ()) |
156 { | 182 { |
157 const call_stack_elt& elt = *(--p); | 183 const stack_frame& elt = *(--p); |
158 | 184 |
159 octave_function *f = elt.fcn; | 185 octave_function *f = elt.m_fcn; |
160 | 186 |
161 if (f && f->is_user_code ()) | 187 if (f && f->is_user_code ()) |
162 { | 188 { |
163 if (elt.line > 0) | 189 if (elt.m_line > 0) |
164 { | 190 { |
165 retval = elt.line; | 191 retval = elt.m_line; |
166 break; | 192 break; |
167 } | 193 } |
168 } | 194 } |
169 } | 195 } |
170 | 196 |
178 | 204 |
179 const_iterator p = cs.end (); | 205 const_iterator p = cs.end (); |
180 | 206 |
181 while (p != cs.begin ()) | 207 while (p != cs.begin ()) |
182 { | 208 { |
183 const call_stack_elt& elt = *(--p); | 209 const stack_frame& elt = *(--p); |
184 | 210 |
185 octave_function *f = elt.fcn; | 211 octave_function *f = elt.m_fcn; |
186 | 212 |
187 if (f && f->is_user_code ()) | 213 if (f && f->is_user_code ()) |
188 { | 214 { |
189 if (elt.column) | 215 if (elt.m_column) |
190 { | 216 { |
191 retval = elt.column; | 217 retval = elt.m_column; |
192 break; | 218 break; |
193 } | 219 } |
194 } | 220 } |
195 } | 221 } |
196 | 222 |
204 size_t retval = 0; | 230 size_t retval = 0; |
205 | 231 |
206 curr_user_frame = 0; | 232 curr_user_frame = 0; |
207 | 233 |
208 // Look for the caller of dbstack. | 234 // Look for the caller of dbstack. |
209 size_t frame = cs[curr_frame].prev; | 235 size_t xframe = cs[curr_frame].m_prev; |
210 | 236 |
211 bool found = false; | 237 bool found = false; |
212 | 238 |
213 size_t k = cs.size (); | 239 size_t k = cs.size (); |
214 | 240 |
215 for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++) | 241 for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++) |
216 { | 242 { |
217 octave_function *f = (*p).fcn; | 243 octave_function *f = (*p).m_fcn; |
218 | 244 |
219 if (--k == frame) | 245 if (--k == xframe) |
220 found = true; | 246 found = true; |
221 | 247 |
222 if (f && f->is_user_code ()) | 248 if (f && f->is_user_code ()) |
223 { | 249 { |
224 if (! found) | 250 if (! found) |
242 | 268 |
243 const_iterator p = cs.end (); | 269 const_iterator p = cs.end (); |
244 | 270 |
245 while (p != cs.begin ()) | 271 while (p != cs.begin ()) |
246 { | 272 { |
247 const call_stack_elt& elt = *(--p); | 273 const stack_frame& elt = *(--p); |
248 | 274 |
249 octave_function *f = elt.fcn; | 275 octave_function *f = elt.m_fcn; |
250 | 276 |
251 if (f && f->is_user_code ()) | 277 if (f && f->is_user_code ()) |
252 { | 278 { |
253 if (nskip > 0) | 279 if (nskip > 0) |
254 nskip--; | 280 nskip--; |
270 | 296 |
271 const_iterator p = cs.end (); | 297 const_iterator p = cs.end (); |
272 | 298 |
273 while (p != cs.begin ()) | 299 while (p != cs.begin ()) |
274 { | 300 { |
275 const call_stack_elt& elt = *(--p); | 301 const stack_frame& elt = *(--p); |
276 | 302 |
277 octave_function *f = elt.fcn; | 303 octave_function *f = elt.m_fcn; |
278 | 304 |
279 if (f && ! f->is_user_script ()) | 305 if (f && ! f->is_user_script ()) |
280 { | 306 { |
281 retval = false; | 307 retval = false; |
282 break; | 308 break; |
297 octave_call_stack::empty_backtrace (void) | 323 octave_call_stack::empty_backtrace (void) |
298 { | 324 { |
299 return octave_map (dim_vector (0, 1), bt_fields); | 325 return octave_map (dim_vector (0, 1), bt_fields); |
300 } | 326 } |
301 | 327 |
328 std::list<octave_call_stack::stack_frame> | |
329 octave_call_stack::do_backtrace_frames (size_t nskip, | |
330 octave_idx_type& curr_user_frame) const | |
331 { | |
332 std::list<octave_call_stack::stack_frame> retval; | |
333 | |
334 size_t user_code_frames = do_num_user_code_frames (curr_user_frame); | |
335 | |
336 size_t nframes = nskip <= user_code_frames ? user_code_frames - nskip : 0; | |
337 | |
338 // Our list is reversed. | |
339 curr_user_frame = nframes - curr_user_frame - 1; | |
340 | |
341 if (nframes > 0) | |
342 { | |
343 for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++) | |
344 { | |
345 const stack_frame& elt = *p; | |
346 | |
347 octave_function *f = elt.m_fcn; | |
348 | |
349 if (f && f->is_user_code ()) | |
350 { | |
351 if (nskip > 0) | |
352 nskip--; | |
353 else | |
354 retval.push_back (elt); | |
355 } | |
356 } | |
357 } | |
358 | |
359 return retval; | |
360 } | |
361 | |
302 octave_map | 362 octave_map |
303 octave_call_stack::do_backtrace (size_t nskip, | 363 octave_call_stack::do_backtrace (size_t nskip, |
304 octave_idx_type& curr_user_frame, | 364 octave_idx_type& curr_user_frame, |
305 bool print_subfn) const | 365 bool print_subfn) const |
306 { | 366 { |
307 size_t user_code_frames = do_num_user_code_frames (curr_user_frame); | 367 std::list<octave_call_stack::stack_frame> frames |
308 | 368 = do_backtrace_frames (nskip, curr_user_frame); |
309 size_t nframes = nskip <= user_code_frames ? user_code_frames - nskip : 0; | 369 |
310 | 370 size_t nframes = frames.size (); |
311 // Our list is reversed. | 371 |
312 curr_user_frame = nframes - curr_user_frame - 1; | |
313 | |
314 octave_map retval (dim_vector (nframes, 1), bt_fields); | 372 octave_map retval (dim_vector (nframes, 1), bt_fields); |
315 | 373 |
316 Cell& file = retval.contents (0); | 374 Cell& file = retval.contents (0); |
317 Cell& name = retval.contents (1); | 375 Cell& name = retval.contents (1); |
318 Cell& line = retval.contents (2); | 376 Cell& line = retval.contents (2); |
319 Cell& column = retval.contents (3); | 377 Cell& column = retval.contents (3); |
320 Cell& scope = retval.contents (4); | 378 Cell& scope = retval.contents (4); |
321 Cell& context = retval.contents (5); | 379 Cell& context = retval.contents (5); |
322 | 380 |
323 if (nframes > 0) | 381 octave_idx_type k = 0; |
324 { | 382 |
325 int k = 0; | 383 for (std::list<octave_call_stack::stack_frame>::const_iterator p = frames.begin (); |
326 | 384 p != frames.end (); p++) |
327 for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++) | 385 { |
328 { | 386 const stack_frame& elt = *p; |
329 const call_stack_elt& elt = *p; | 387 |
330 | 388 scope(k) = elt.m_scope; |
331 octave_function *f = elt.fcn; | 389 context(k) = elt.m_context; |
332 | 390 file(k) = elt.fcn_file_name (); |
333 if (f && f->is_user_code ()) | 391 name(k) = elt.fcn_name (print_subfn); |
334 { | 392 line(k) = elt.m_line; |
335 if (nskip > 0) | 393 column(k) = elt.m_column; |
336 nskip--; | 394 |
337 else | 395 k++; |
338 { | |
339 scope(k) = elt.scope; | |
340 context(k) = elt.context; | |
341 | |
342 file(k) = f->fcn_file_name (); | |
343 std::string parent_fcn_name = f->parent_fcn_name (); | |
344 if (! print_subfn || parent_fcn_name == std::string ()) | |
345 name(k) = f->name (); | |
346 else | |
347 name(k) = f->parent_fcn_name () + Vfilemarker + f->name (); | |
348 | |
349 line(k) = elt.line; | |
350 column(k) = elt.column; | |
351 | |
352 k++; | |
353 } | |
354 } | |
355 } | |
356 } | 396 } |
357 | 397 |
358 return retval; | 398 return retval; |
359 } | 399 } |
360 | 400 |
367 { | 407 { |
368 retval = true; | 408 retval = true; |
369 | 409 |
370 curr_frame = n; | 410 curr_frame = n; |
371 | 411 |
372 const call_stack_elt& elt = cs[n]; | 412 const stack_frame& elt = cs[n]; |
373 | 413 |
374 symbol_table::set_scope_and_context (elt.scope, elt.context); | 414 symbol_table::set_scope_and_context (elt.m_scope, elt.m_context); |
375 | 415 |
376 if (verbose) | 416 if (verbose) |
377 { | 417 octave_stdout << "stopped in " << elt.fcn_name () |
378 octave_function *f = elt.fcn; | 418 << " at line " << elt.m_line |
379 std::string nm = f ? f->name () : std::string ("<unknown>"); | 419 << " column " << elt.m_column |
380 | 420 << " (" << elt.m_scope << "[" << elt.m_context << "])" |
381 octave_stdout << "stopped in " << nm | 421 << std::endl; |
382 << " at line " << elt.line | |
383 << " column " << elt.column | |
384 << " (" << elt.scope << "[" << elt.context << "])" | |
385 << std::endl; | |
386 } | |
387 } | 422 } |
388 | 423 |
389 return retval; | 424 return retval; |
390 } | 425 } |
391 | 426 |
400 incr = -1; | 435 incr = -1; |
401 else if (nskip > 0) | 436 else if (nskip > 0) |
402 incr = 1; | 437 incr = 1; |
403 | 438 |
404 // Start looking with the caller of dbup/dbdown/keyboard. | 439 // Start looking with the caller of dbup/dbdown/keyboard. |
405 size_t frame = cs[curr_frame].prev; | 440 size_t xframe = cs[curr_frame].m_prev; |
406 | 441 |
407 while (true) | 442 while (true) |
408 { | 443 { |
409 if ((incr < 0 && frame == 0) || (incr > 0 && frame == cs.size () - 1)) | 444 if ((incr < 0 && xframe == 0) || (incr > 0 && xframe == cs.size () - 1)) |
410 break; | 445 break; |
411 | 446 |
412 frame += incr; | 447 xframe += incr; |
413 | 448 |
414 const call_stack_elt& elt = cs[frame]; | 449 const stack_frame& elt = cs[xframe]; |
415 | 450 |
416 octave_function *f = elt.fcn; | 451 octave_function *f = elt.m_fcn; |
417 | 452 |
418 if (frame == 0 || (f && f->is_user_code ())) | 453 if (xframe == 0 || (f && f->is_user_code ())) |
419 { | 454 { |
420 if (nskip > 0) | 455 if (nskip > 0) |
421 nskip--; | 456 nskip--; |
422 else if (nskip < 0) | 457 else if (nskip < 0) |
423 nskip++; | 458 nskip++; |
424 | 459 |
425 if (nskip == 0) | 460 if (nskip == 0) |
426 { | 461 { |
427 curr_frame = frame; | 462 curr_frame = xframe; |
428 cs[cs.size () - 1].prev = curr_frame; | 463 cs[cs.size () - 1].m_prev = curr_frame; |
429 | 464 |
430 symbol_table::set_scope_and_context (elt.scope, elt.context); | 465 symbol_table::set_scope_and_context (elt.m_scope, elt.m_context); |
431 | 466 |
432 if (verbose) | 467 if (verbose) |
433 { | 468 { |
434 std::ostringstream buf; | 469 std::ostringstream buf; |
435 | 470 |
436 if (f) | 471 if (f) |
437 buf << "stopped in " << f->name () | 472 buf << "stopped in " << f->name () |
438 << " at line " << elt.line << std::endl; | 473 << " at line " << elt.m_line << std::endl; |
439 else | 474 else |
440 buf << "at top level" << std::endl; | 475 buf << "at top level" << std::endl; |
441 | 476 |
442 octave_stdout << buf.str (); | 477 octave_stdout << buf.str (); |
443 } | 478 } |
458 } | 493 } |
459 | 494 |
460 void | 495 void |
461 octave_call_stack::do_goto_caller_frame (void) | 496 octave_call_stack::do_goto_caller_frame (void) |
462 { | 497 { |
463 size_t frame = curr_frame; | 498 size_t xframe = curr_frame; |
464 | 499 |
465 bool skipped = false; | 500 bool skipped = false; |
466 | 501 |
467 while (frame != 0) | 502 while (xframe != 0) |
468 { | 503 { |
469 frame = cs[frame].prev; | 504 xframe = cs[xframe].m_prev; |
470 | 505 |
471 const call_stack_elt& elt = cs[frame]; | 506 const stack_frame& elt = cs[xframe]; |
472 | 507 |
473 octave_function *f = elt.fcn; | 508 octave_function *f = elt.m_fcn; |
474 | 509 |
475 if (elt.scope == cs[0].scope || (f && f->is_user_code ())) | 510 if (elt.m_scope == cs[0].m_scope || (f && f->is_user_code ())) |
476 { | 511 { |
477 if (! skipped) | 512 if (! skipped) |
478 // We found the current user code frame, so skip it. | 513 // We found the current user code frame, so skip it. |
479 skipped = true; | 514 skipped = true; |
480 else | 515 else |
481 { | 516 { |
482 // We found the caller user code frame. | 517 // We found the caller user code frame. |
483 call_stack_elt tmp (elt); | 518 stack_frame tmp (elt); |
484 tmp.prev = curr_frame; | 519 tmp.m_prev = curr_frame; |
485 | 520 |
486 curr_frame = cs.size (); | 521 curr_frame = cs.size (); |
487 | 522 |
488 cs.push_back (tmp); | 523 cs.push_back (tmp); |
489 | 524 |
490 symbol_table::set_scope_and_context (tmp.scope, tmp.context); | 525 symbol_table::set_scope_and_context (tmp.m_scope, tmp.m_context); |
491 | 526 |
492 break; | 527 break; |
493 } | 528 } |
494 } | 529 } |
495 } | 530 } |
496 } | 531 } |
497 | 532 |
498 void | 533 void |
499 octave_call_stack::do_goto_base_frame (void) | 534 octave_call_stack::do_goto_base_frame (void) |
500 { | 535 { |
501 call_stack_elt tmp (cs[0]); | 536 stack_frame tmp (cs[0]); |
502 tmp.prev = curr_frame; | 537 tmp.m_prev = curr_frame; |
503 | 538 |
504 curr_frame = cs.size (); | 539 curr_frame = cs.size (); |
505 | 540 |
506 cs.push_back (tmp); | 541 cs.push_back (tmp); |
507 | 542 |
508 symbol_table::set_scope_and_context (tmp.scope, tmp.context); | 543 symbol_table::set_scope_and_context (tmp.m_scope, tmp.m_context); |
509 } | |
510 | |
511 void | |
512 octave_call_stack::do_backtrace_error_message (void) const | |
513 { | |
514 if (error_state > 0) | |
515 { | |
516 error_state = -1; | |
517 | |
518 error ("called from:"); | |
519 } | |
520 | |
521 if (! cs.empty ()) | |
522 { | |
523 const call_stack_elt& elt = cs.back (); | |
524 | |
525 octave_function *fcn = elt.fcn; | |
526 | |
527 std::string fcn_name = "?unknown?"; | |
528 | |
529 if (fcn) | |
530 { | |
531 fcn_name = fcn->fcn_file_name (); | |
532 | |
533 if (fcn_name.empty ()) | |
534 fcn_name = fcn->name (); | |
535 } | |
536 | |
537 error (" %s at line %d, column %d", | |
538 fcn_name.c_str (), elt.line, elt.column); | |
539 } | |
540 } | 544 } |
541 | 545 |
542 void | 546 void |
543 recover_from_exception (void) | 547 recover_from_exception (void) |
544 { | 548 { |