GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
call-stack.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1995-2018 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 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 Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include "call-stack.h"
28 #include "defun.h"
29 #include "interpreter.h"
30 #include "oct-map.h"
31 #include "ov.h"
32 #include "ov-fcn.h"
33 #include "ov-fcn-handle.h"
34 #include "ov-usr-fcn.h"
35 #include "pager.h"
36 #include "variables.h"
37 
38 // Use static fields for the best efficiency.
39 // NOTE: C++0x will allow these two to be merged into one.
40 static const char *bt_fieldnames[] =
41  { "file", "name", "line", "column", "scope", "context", nullptr };
43 
44 namespace octave
45 {
48  {
49  return m_fcn ? m_fcn->fcn_file_name () : "";
50  }
51 
53  call_stack::stack_frame::fcn_name (bool print_subfn) const
54  {
56 
57  if (m_fcn)
58  {
59  std::string parent_fcn_name = m_fcn->parent_fcn_name ();
60 
61  if (print_subfn && ! parent_fcn_name.empty ())
62  retval = parent_fcn_name + '>';
63 
64  if (m_fcn->is_anonymous_function ())
66  else
67  retval += m_fcn->name ();
68  }
69  else
70  retval = "<unknown>";
71 
72  return retval;
73  }
74 
75  bool
77  {
78  if (this->line () != rhs.line ())
79  return false;
80  else if (this->column () != rhs.column ())
81  return false;
82  else if (this->fcn_file_name () != rhs.fcn_file_name ())
83  return false;
84  else if (this->fcn_name () != rhs.fcn_name ())
85  return false;
86  else
87  return true;
88  }
89 
91  : cs (), curr_frame (0), m_max_stack_depth (1024), m_interpreter (interp)
92  {
94 
95  push (nullptr, symtab.top_scope (), 0);
96  }
97 
98  int
100  {
101  int retval = -1;
102 
103  if (! cs.empty ())
104  {
105  const stack_frame& elt = cs[curr_frame];
106  retval = elt.m_line;
107  }
108 
109  return retval;
110  }
111 
112  int
114  {
115  int retval = -1;
116 
117  if (! cs.empty ())
118  {
119  const stack_frame& elt = cs[curr_frame];
120  retval = elt.m_column;
121  }
122 
123  return retval;
124  }
125 
126  size_t
128  {
129  size_t retval = 0;
130 
131  curr_user_frame = 0;
132 
133  // Look for the caller of dbstack.
134  size_t xframe = cs[curr_frame].m_prev;
135 
136  bool found = false;
137 
138  size_t k = cs.size ();
139 
140  for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
141  {
142  octave_function *f = (*p).m_fcn;
143 
144  if (--k == xframe)
145  found = true;
146 
147  if (f && f->is_user_code ())
148  {
149  if (! found)
150  curr_user_frame++;
151 
152  retval++;
153  }
154  }
155 
156  // We counted how many user frames were not the one, in reverse.
157  // Now set curr_user_frame to be the index in the other direction.
158  curr_user_frame = retval - curr_user_frame - 1;
159 
160  return retval;
161  }
162 
164  call_stack::caller_user_code (size_t nskip) const
165  {
166  octave_user_code *retval = nullptr;
167 
168  const_iterator p = cs.end ();
169 
170  while (p != cs.begin ())
171  {
172  const stack_frame& elt = *(--p);
173 
174  octave_function *f = elt.m_fcn;
175 
176  if (f && f->is_user_code ())
177  {
178  if (nskip > 0)
179  nskip--;
180  else
181  {
182  retval = dynamic_cast<octave_user_code *> (f);
183  break;
184  }
185  }
186  }
187 
188  return retval;
189  }
190 
191  int
193  {
194  int retval = -1;
195 
196  const_iterator p = cs.end ();
197 
198  while (p != cs.begin ())
199  {
200  const stack_frame& elt = *(--p);
201 
202  octave_function *f = elt.m_fcn;
203 
204  if (f && f->is_user_code ())
205  {
206  if (elt.m_line > 0)
207  {
208  retval = elt.m_line;
209  break;
210  }
211  }
212  }
213 
214  return retval;
215  }
216 
217  int
219  {
220  int retval = -1;
221 
222  const_iterator p = cs.end ();
223 
224  while (p != cs.begin ())
225  {
226  const stack_frame& elt = *(--p);
227 
228  octave_function *f = elt.m_fcn;
229 
230  if (f && f->is_user_code ())
231  {
232  if (elt.m_column)
233  {
234  retval = elt.m_column;
235  break;
236  }
237  }
238  }
239 
240  return retval;
241  }
242 
245  {
246  octave_user_code *retval = nullptr;
247 
248  // This should never happen...
249  if (curr_frame == 0)
250  return retval;
251 
252  // Start looking with the caller of the calling debug function.
253  size_t i = cs[curr_frame].m_prev;
254 
255  while (i != 0)
256  {
257  const stack_frame& elt = cs[i--];
258 
259  octave_function *f = elt.m_fcn;
260 
261  if (f && f->is_user_code ())
262  {
263  retval = dynamic_cast<octave_user_code *> (f);
264  break;
265  }
266  }
267 
268  return retval;
269  }
270 
271  int
273  {
274  int retval = -1;
275 
276  // This should never happen...
277  if (curr_frame == 0)
278  return retval;
279 
280  // Start looking with the caller of the calling debug function.
281  size_t i = cs[curr_frame].m_prev;
282 
283  while (i != 0)
284  {
285  const stack_frame& elt = cs[i--];
286 
287  octave_function *f = elt.m_fcn;
288 
289  if (f && f->is_user_code ())
290  {
291  if (elt.m_line)
292  {
293  retval = elt.m_line;
294  break;
295  }
296  }
297  }
298 
299  return retval;
300  }
301 
302  int
304  {
305  int retval = -1;
306 
307  // This should never happen...
308  if (curr_frame == 0)
309  return retval;
310 
311  // Start looking with the caller of the calling debug function.
312  size_t i = cs[curr_frame].m_prev;
313 
314  while (i != 0)
315  {
316  const stack_frame& elt = cs[i--];
317 
318  octave_function *f = elt.m_fcn;
319 
320  if (f && f->is_user_code ())
321  {
322  if (elt.m_column)
323  {
324  retval = elt.m_column;
325  break;
326  }
327  }
328  }
329 
330  return retval;
331  }
332 
333  bool
335  {
336  bool retval = true;
337 
338  const_iterator p = cs.end ();
339 
340  while (p != cs.begin ())
341  {
342  const stack_frame& elt = *(--p);
343 
344  octave_function *f = elt.m_fcn;
345 
346  if (f && ! f->is_user_script ())
347  {
348  retval = false;
349  break;
350  }
351  }
352 
353  return retval;
354  }
355 
356  void
358  {
360 
361  push (fcn, symtab.current_scope (), symtab.current_context ());
362  }
363 
364  void
367  {
368  size_t prev_frame = curr_frame;
369  curr_frame = cs.size ();
370 
371  // m_max_stack_depth should never be less than zero.
372  if (curr_frame > static_cast<size_t> (m_max_stack_depth))
373  error ("max_stack_depth exceeded");
374 
375  cs.push_back (stack_frame (fcn, scope, context, prev_frame));
376 
378 
379  symtab.set_scope_and_context (scope, context);
380  }
381 
382  bool
384  {
385  bool retval = false;
386 
387  if (n < cs.size ())
388  {
389  retval = true;
390 
391  curr_frame = n;
392 
393  const stack_frame& elt = cs[n];
394 
396 
397  symtab.set_scope_and_context (elt.m_scope, elt.m_context);
398 
399  if (verbose)
400  octave_stdout << "stopped in " << elt.fcn_name ()
401  << " at line " << elt.m_line
402  << " column " << elt.m_column
403  << " [" << elt.fcn_file_name () << "] "
404  << "[context = " << elt.m_context << "])"
405  << std::endl;
406  }
407 
408  return retval;
409  }
410 
411  bool
413  {
414  bool retval = false;
415 
416  int incr = 0;
417 
418  if (nskip < 0)
419  incr = -1;
420  else if (nskip > 0)
421  incr = 1;
422 
423  // Start looking with the caller of dbup/dbdown/keyboard.
424  size_t xframe = cs[curr_frame].m_prev;
425 
426  while (true)
427  {
428  if ((incr < 0 && xframe == 0) || (incr > 0 && xframe == cs.size () - 1))
429  break;
430 
431  xframe += incr;
432 
433  const stack_frame& elt = cs[xframe];
434 
435  octave_function *f = elt.m_fcn;
436 
437  if (xframe == 0 || (f && f->is_user_code ()))
438  {
439  if (nskip > 0)
440  nskip--;
441  else if (nskip < 0)
442  nskip++;
443 
444  if (nskip == 0)
445  {
446  curr_frame = xframe;
447  cs[cs.size () - 1].m_prev = curr_frame;
448 
450 
451  symtab.set_scope_and_context (elt.m_scope, elt.m_context);
452 
453  if (verbose)
454  {
455  std::ostringstream buf;
456 
457  if (f)
458  buf << "stopped in " << elt.fcn_name ()
459  << " at line " << elt.m_line
460  << " [" << elt.fcn_file_name () << "] "
461  << std::endl;
462  else
463  buf << "at top level" << std::endl;
464 
465  octave_stdout << buf.str ();
466  }
467 
468  retval = true;
469  break;
470  }
471  }
472  else if (incr == 0) // Break out of infinite loop by choosing an incr.
473  incr = -1;
474 
475  // There is no need to set scope and context here. That will
476  // happen when the dbup/dbdown/keyboard frame is popped and we
477  // jump to the new "prev" frame set above.
478  }
479 
480  return retval;
481  }
482 
483  void
485  {
486  size_t xframe = curr_frame;
487 
488  bool skipped = false;
489 
490  while (xframe != 0)
491  {
492  xframe = cs[xframe].m_prev;
493 
494  const stack_frame& elt = cs[xframe];
495 
496  octave_function *f = elt.m_fcn;
497 
498  if (elt.m_scope == cs[0].m_scope || (f && f->is_user_code ()))
499  {
500  if (! skipped)
501  // We found the current user code frame, so skip it.
502  skipped = true;
503  else
504  {
505  // We found the caller user code frame.
506  stack_frame tmp (elt);
507  tmp.m_prev = curr_frame;
508 
509  curr_frame = cs.size ();
510 
511  cs.push_back (tmp);
512 
514 
515  symtab.set_scope_and_context (tmp.m_scope, tmp.m_context);
516 
517  break;
518  }
519  }
520  }
521  }
522 
523  void
525  {
526  stack_frame tmp (cs[0]);
527  tmp.m_prev = curr_frame;
528 
529  curr_frame = cs.size ();
530 
531  cs.push_back (tmp);
532 
534 
535  symtab.set_scope_and_context (tmp.m_scope, tmp.m_context);
536  }
537 
538  std::list<call_stack::stack_frame>
540  octave_idx_type& curr_user_frame) const
541  {
542  std::list<call_stack::stack_frame> retval;
543 
544  size_t user_code_frames = num_user_code_frames (curr_user_frame);
545 
546  size_t nframes = (nskip <= user_code_frames ? user_code_frames - nskip : 0);
547 
548  // Our list is reversed.
549  curr_user_frame = nframes - curr_user_frame - 1;
550 
551  if (nframes > 0)
552  {
553  for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
554  {
555  const stack_frame& elt = *p;
556 
557  octave_function *f = elt.m_fcn;
558 
559  if (f && f->is_user_code ())
560  {
561  if (nskip > 0)
562  nskip--;
563  else
564  retval.push_back (elt);
565  }
566  }
567  }
568 
569  return retval;
570  }
571 
572  octave_map
573  call_stack::backtrace (size_t nskip, octave_idx_type& curr_user_frame,
574  bool print_subfn) const
575  {
576  std::list<call_stack::stack_frame> frames
577  = backtrace_frames (nskip, curr_user_frame);
578 
579  size_t nframes = frames.size ();
580 
581  octave_map retval (dim_vector (nframes, 1), bt_fields);
582 
583  Cell& file = retval.contents (0);
584  Cell& name = retval.contents (1);
585  Cell& line = retval.contents (2);
586  Cell& column = retval.contents (3);
587  Cell& context = retval.contents (5);
588 
589  octave_idx_type k = 0;
590 
591  for (const auto& frm : frames)
592  {
593  context(k) = frm.m_context;
594  file(k) = frm.fcn_file_name ();
595  name(k) = frm.fcn_name (print_subfn);
596  line(k) = frm.m_line;
597  column(k) = frm.m_column;
598 
599  k++;
600  }
601 
602  return retval;
603  }
604 
605  octave_map
606  call_stack::backtrace (size_t nskip)
607  {
608  octave_idx_type curr_user_frame = -1;
609 
610  return backtrace (nskip, curr_user_frame, true);
611  }
612 
613  octave_map
615  {
616  return octave_map (dim_vector (0, 1), bt_fields);
617  }
618 
619  void
621  {
622  if (cs.size () > 1)
623  {
624  const stack_frame& elt = cs.back ();
625  curr_frame = elt.m_prev;
626  cs.pop_back ();
627  const stack_frame& new_elt = cs[curr_frame];
628 
630 
631  symtab.set_scope_and_context (new_elt.m_scope, new_elt.m_context);
632  }
633  }
634 
637  {
639  "max_stack_depth", 0);
640  }
641 }
642 
643 DEFMETHOD (max_stack_depth, interp, args, nargout,
644  doc: /* -*- texinfo -*-
645 @deftypefn {} {@var{val} =} max_stack_depth ()
646 @deftypefnx {} {@var{old_val} =} max_stack_depth (@var{new_val})
647 @deftypefnx {} {} max_stack_depth (@var{new_val}, "local")
648 Query or set the internal limit on the number of times a function may
649 be called recursively.
650 
651 If the limit is exceeded, an error message is printed and control returns to
652 the top level.
653 
654 When called from inside a function with the @qcode{"local"} option, the
655 variable is changed locally for the function and any subroutines it calls.
656 The original variable value is restored when exiting the function.
657 
658 @seealso{max_recursion_depth}
659 @end deftypefn */)
660 {
661  octave::call_stack& cs = interp.get_call_stack ();
662 
663  return cs.max_stack_depth (args, nargout);
664 }
665 
666 /*
667 %!test
668 %! orig_val = max_stack_depth ();
669 %! old_val = max_stack_depth (2*orig_val);
670 %! assert (orig_val, old_val);
671 %! assert (max_stack_depth (), 2*orig_val);
672 %! max_stack_depth (orig_val);
673 %! assert (max_stack_depth (), orig_val);
674 
675 %!error (max_stack_depth (1, 2))
676 */
677 
void goto_caller_frame(void)
Definition: call-stack.cc:484
symbol_scope top_scope(void)
Definition: symtab.h:75
Definition: Cell.h:37
OCTAVE_EXPORT octave_value_list column
Definition: sparse.cc:123
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
is already an absolute the name is checked against the file system instead of Octave s loadpath In this if otherwise an empty string is returned If the first argument is a cell array of search each directory of the loadpath for element of the cell array and return the first that matches If the second optional argument return a cell array containing the list of all files that have the same name in the path If no files are found
Definition: utils.cc:305
static const std::string anonymous
Definition: ov-fcn-handle.h:55
symbol_record::context_id current_context(void) const
Definition: symtab.h:87
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:135
int debug_user_code_line(void) const
Definition: call-stack.cc:272
octave_user_code * debug_user_code(void) const
Definition: call-stack.cc:244
int debug_user_code_column(void) const
Definition: call-stack.cc:303
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE * f
symbol_scope current_scope(void)
Definition: symtab.h:77
std::string fcn_file_name(void) const
Definition: call-stack.cc:47
bool all_scripts(void) const
Definition: call-stack.cc:334
for large enough k
Definition: lu.cc:617
octave_map backtrace(size_t nskip, octave_idx_type &curr_user_frame, bool print_subfn=true) const
Definition: call-stack.cc:573
octave_map empty_backtrace(void) const
Definition: call-stack.cc:614
bool goto_frame_relative(int n, bool verbose=false)
Definition: call-stack.cc:412
void error(const char *fmt,...)
Definition: error.cc:578
octave_user_code * caller_user_code(size_t nskip=0) const
Definition: call-stack.cc:164
int caller_user_code_line(void) const
Definition: call-stack.cc:192
std::deque< stack_frame >::const_reverse_iterator const_reverse_iterator
Definition: call-stack.h:92
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:79
void push(void)
Definition: call-stack.h:181
virtual std::string fcn_file_name(void) const
Definition: ov-fcn.h:74
octave_function * fcn
Definition: ov-class.cc:1754
octave::call_stack & cs
Definition: ov-class.cc:1752
bool verbose
Definition: load-save.cc:667
nd deftypefn *std::string name
Definition: sysdep.cc:647
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:997
call_stack(interpreter &interp)
Definition: call-stack.cc:90
std::deque< stack_frame >::const_iterator const_iterator
Definition: call-stack.h:89
bool goto_frame(size_t n=0, bool verbose=false)
Definition: call-stack.cc:383
static const octave_fields bt_fields(bt_fieldnames)
void set_scope_and_context(const symbol_scope &sid, symbol_record::context_id context)
Definition: symtab.h:97
double tmp
Definition: data.cc:6252
void goto_base_frame(void)
Definition: call-stack.cc:524
octave_value retval
Definition: data.cc:6246
static const char * bt_fieldnames[]
Definition: call-stack.cc:40
std::string fcn_name(bool print_subfn=true) const
Definition: call-stack.cc:53
end deftypefn *return set_internal_variable(Vsvd_driver, args, nargout, "svd_driver", driver_names)
symbol_table & get_symbol_table(void)
Definition: interpreter.h:169
octave_value max_stack_depth(const octave_value_list &args, int nargout)
Definition: call-stack.cc:636
#define octave_stdout
Definition: pager.h:174
int current_line(void) const
Definition: call-stack.cc:99
std::list< call_stack::stack_frame > backtrace_frames(size_t nskip, octave_idx_type &curr_user_frame) const
Definition: call-stack.cc:539
p
Definition: lu.cc:138
std::deque< stack_frame > cs
Definition: call-stack.h:262
int current_column(void) const
Definition: call-stack.cc:113
symbol_record::context_id m_context
Definition: call-stack.h:84
for i
Definition: data.cc:5264
bool operator==(const stack_frame &rhs) const
Definition: call-stack.cc:76
int caller_user_code_column(void) const
Definition: call-stack.cc:218
size_t num_user_code_frames(octave_idx_type &curr_user_frame) const
Definition: call-stack.cc:127
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
interpreter & m_interpreter
Definition: call-stack.h:268