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 {