GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
call-stack.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1995-2017 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 the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 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 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include "singleton-cleanup.h"
28 
29 #include "call-stack.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 
37 
40 {
41  return m_fcn ? m_fcn->fcn_file_name () : "";
42 }
43 
46 {
48 
49  if (m_fcn)
50  {
51  std::string parent_fcn_name = m_fcn->parent_fcn_name ();
52 
53  if (print_subfn && ! parent_fcn_name.empty ())
54  retval = parent_fcn_name + Vfilemarker;
55 
56  if (m_fcn->is_anonymous_function ())
58  else
59  retval += m_fcn->name ();
60  }
61  else
62  retval = "<unknown>";
63 
64  return retval;
65 }
66 
67 bool
69 {
70  if (this->line () != rhs.line ())
71  return false;
72  else if (this->column () != rhs.column ())
73  return false;
74  else if (this->fcn_file_name () != rhs.fcn_file_name ())
75  return false;
76  else if (this->fcn_name () != rhs.fcn_name ())
77  return false;
78  else
79  return true;
80 }
81 
82 void
84 {
85  instance = new octave_call_stack ();
86 
87  if (instance)
88  {
90 
92  }
93 }
94 
95 int
97 {
98  int retval = -1;
99 
100  if (! cs.empty ())
101  {
102  const stack_frame& elt = cs[curr_frame];
103  retval = elt.m_line;
104  }
105 
106  return retval;
107 }
108 
109 int
111 {
112  int retval = -1;
113 
114  if (! cs.empty ())
115  {
116  const stack_frame& elt = cs[curr_frame];
117  retval = elt.m_column;
118  }
119 
120  return retval;
121 }
122 
123 size_t
125  (octave_idx_type& curr_user_frame) const
126 {
127  size_t retval = 0;
128 
129  curr_user_frame = 0;
130 
131  // Look for the caller of dbstack.
132  size_t xframe = cs[curr_frame].m_prev;
133 
134  bool found = false;
135 
136  size_t k = cs.size ();
137 
138  for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
139  {
140  octave_function *f = (*p).m_fcn;
141 
142  if (--k == xframe)
143  found = true;
144 
145  if (f && f->is_user_code ())
146  {
147  if (! found)
148  curr_user_frame++;
149 
150  retval++;
151  }
152  }
153 
154  // We counted how many user frames were not the one, in reverse.
155  // Now set curr_user_frame to be the index in the other direction.
156  curr_user_frame = retval - curr_user_frame - 1;
157 
158  return retval;
159 }
160 
163 {
165 
166  const_iterator p = cs.end ();
167 
168  while (p != cs.begin ())
169  {
170  const stack_frame& elt = *(--p);
171 
172  octave_function *f = elt.m_fcn;
173 
174  if (f && f->is_user_code ())
175  {
176  if (nskip > 0)
177  nskip--;
178  else
179  {
180  retval = dynamic_cast<octave_user_code *> (f);
181  break;
182  }
183  }
184  }
185 
186  return retval;
187 }
188 
189 int
191 {
192  int retval = -1;
193 
194  const_iterator p = cs.end ();
195 
196  while (p != cs.begin ())
197  {
198  const stack_frame& elt = *(--p);
199 
200  octave_function *f = elt.m_fcn;
201 
202  if (f && f->is_user_code ())
203  {
204  if (elt.m_line > 0)
205  {
206  retval = elt.m_line;
207  break;
208  }
209  }
210  }
211 
212  return retval;
213 }
214 
215 int
217 {
218  int retval = -1;
219 
220  const_iterator p = cs.end ();
221 
222  while (p != cs.begin ())
223  {
224  const stack_frame& elt = *(--p);
225 
226  octave_function *f = elt.m_fcn;
227 
228  if (f && f->is_user_code ())
229  {
230  if (elt.m_column)
231  {
232  retval = elt.m_column;
233  break;
234  }
235  }
236  }
237 
238  return retval;
239 }
240 
243 {
245 
246  // This should never happen...
247  if (curr_frame == 0)
248  return retval;
249 
250  // Start looking with the caller of the calling debug function.
251  size_t i = cs[curr_frame].m_prev;
252 
253  while (i != 0)
254  {
255  const stack_frame& elt = cs[i--];
256 
257  octave_function *f = elt.m_fcn;
258 
259  if (f && f->is_user_code ())
260  {
261  retval = dynamic_cast<octave_user_code *> (f);
262  break;
263  }
264  }
265 
266  return retval;
267 }
268 
269 int
271 {
272  int retval = -1;
273 
274  // This should never happen...
275  if (curr_frame == 0)
276  return retval;
277 
278  // Start looking with the caller of the calling debug function.
279  size_t i = cs[curr_frame].m_prev;
280 
281  while (i != 0)
282  {
283  const stack_frame& elt = cs[i--];
284 
285  octave_function *f = elt.m_fcn;
286 
287  if (f && f->is_user_code ())
288  {
289  if (elt.m_line)
290  {
291  retval = elt.m_line;
292  break;
293  }
294  }
295  }
296 
297  return retval;
298 }
299 
300 int
302 {
303  int retval = -1;
304 
305  // This should never happen...
306  if (curr_frame == 0)
307  return retval;
308 
309  // Start looking with the caller of the calling debug function.
310  size_t i = cs[curr_frame].m_prev;
311 
312  while (i != 0)
313  {
314  const stack_frame& elt = cs[i--];
315 
316  octave_function *f = elt.m_fcn;
317 
318  if (f && f->is_user_code ())
319  {
320  if (elt.m_column)
321  {
322  retval = elt.m_column;
323  break;
324  }
325  }
326  }
327 
328  return retval;
329 }
330 
331 bool
333 {
334  bool retval = true;
335 
336  const_iterator p = cs.end ();
337 
338  while (p != cs.begin ())
339  {
340  const stack_frame& elt = *(--p);
341 
342  octave_function *f = elt.m_fcn;
343 
344  if (f && ! f->is_user_script ())
345  {
346  retval = false;
347  break;
348  }
349  }
350 
351  return retval;
352 }
353 
354 // Use static fields for the best efficiency.
355 // NOTE: C++0x will allow these two to be merged into one.
356 static const char *bt_fieldnames[] = { "file", "name", "line",
357  "column", "scope", "context", 0
358  };
359 static const octave_fields bt_fields (bt_fieldnames);
360 
363 {
364  return octave_map (dim_vector (0, 1), bt_fields);
365 }
366 
367 std::list<octave_call_stack::stack_frame>
369  octave_idx_type& curr_user_frame) const
370 {
371  std::list<octave_call_stack::stack_frame> retval;
372 
373  size_t user_code_frames = do_num_user_code_frames (curr_user_frame);
374 
375  size_t nframes = nskip <= user_code_frames ? user_code_frames - nskip : 0;
376 
377  // Our list is reversed.
378  curr_user_frame = nframes - curr_user_frame - 1;
379 
380  if (nframes > 0)
381  {
382  for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
383  {
384  const stack_frame& elt = *p;
385 
386  octave_function *f = elt.m_fcn;
387 
388  if (f && f->is_user_code ())
389  {
390  if (nskip > 0)
391  nskip--;
392  else
393  retval.push_back (elt);
394  }
395  }
396  }
397 
398  return retval;
399 }
400 
403  octave_idx_type& curr_user_frame,
404  bool print_subfn) const
405 {
406  std::list<octave_call_stack::stack_frame> frames
407  = do_backtrace_frames (nskip, curr_user_frame);
408 
409  size_t nframes = frames.size ();
410 
411  octave_map retval (dim_vector (nframes, 1), bt_fields);
412 
413  Cell& file = retval.contents (0);
414  Cell& name = retval.contents (1);
415  Cell& line = retval.contents (2);
416  Cell& column = retval.contents (3);
417  Cell& scope = retval.contents (4);
418  Cell& context = retval.contents (5);
419 
420  octave_idx_type k = 0;
421 
422  for (std::list<octave_call_stack::stack_frame>::const_iterator p = frames.begin ();
423  p != frames.end (); p++)
424  {
425  const stack_frame& elt = *p;
426 
427  scope(k) = elt.m_scope;
428  context(k) = elt.m_context;
429  file(k) = elt.fcn_file_name ();
430  name(k) = elt.fcn_name (print_subfn);
431  line(k) = elt.m_line;
432  column(k) = elt.m_column;
433 
434  k++;
435  }
436 
437  return retval;
438 }
439 
440 bool
442 {
443  bool retval = false;
444 
445  if (n < cs.size ())
446  {
447  retval = true;
448 
449  curr_frame = n;
450 
451  const stack_frame& elt = cs[n];
452 
454 
455  if (verbose)
456  octave_stdout << "stopped in " << elt.fcn_name ()
457  << " at line " << elt.m_line
458  << " column " << elt.m_column
459  << " [" << elt.fcn_file_name () << "] "
460  << " (scope = " << elt.m_scope
461  << "[context = " << elt.m_context << "])"
462  << std::endl;
463  }
464 
465  return retval;
466 }
467 
468 bool
470 {
471  bool retval = false;
472 
473  int incr = 0;
474 
475  if (nskip < 0)
476  incr = -1;
477  else if (nskip > 0)
478  incr = 1;
479 
480  // Start looking with the caller of dbup/dbdown/keyboard.
481  size_t xframe = cs[curr_frame].m_prev;
482 
483  while (true)
484  {
485  if ((incr < 0 && xframe == 0) || (incr > 0 && xframe == cs.size () - 1))
486  break;
487 
488  xframe += incr;
489 
490  const stack_frame& elt = cs[xframe];
491 
492  octave_function *f = elt.m_fcn;
493 
494  if (xframe == 0 || (f && f->is_user_code ()))
495  {
496  if (nskip > 0)
497  nskip--;
498  else if (nskip < 0)
499  nskip++;
500 
501  if (nskip == 0)
502  {
503  curr_frame = xframe;
504  cs[cs.size () - 1].m_prev = curr_frame;
505 
507 
508  if (verbose)
509  {
510  std::ostringstream buf;
511 
512  if (f)
513  buf << "stopped in " << elt.fcn_name ()
514  << " at line " << elt.m_line
515  << " [" << elt.fcn_file_name () << "] "
516  << std::endl;
517  else
518  buf << "at top level" << std::endl;
519 
520  octave_stdout << buf.str ();
521  }
522 
523  retval = true;
524  break;
525  }
526  }
527  else if (incr == 0) // Break out of infinite loop by choosing an incr.
528  incr = -1;
529 
530  // There is no need to set scope and context here. That will
531  // happen when the dbup/dbdown/keyboard frame is popped and we
532  // jump to the new "prev" frame set above.
533  }
534 
535  return retval;
536 }
537 
538 void
540 {
541  size_t xframe = curr_frame;
542 
543  bool skipped = false;
544 
545  while (xframe != 0)
546  {
547  xframe = cs[xframe].m_prev;
548 
549  const stack_frame& elt = cs[xframe];
550 
551  octave_function *f = elt.m_fcn;
552 
553  if (elt.m_scope == cs[0].m_scope || (f && f->is_user_code ()))
554  {
555  if (! skipped)
556  // We found the current user code frame, so skip it.
557  skipped = true;
558  else
559  {
560  // We found the caller user code frame.
561  stack_frame tmp (elt);
562  tmp.m_prev = curr_frame;
563 
564  curr_frame = cs.size ();
565 
566  cs.push_back (tmp);
567 
569 
570  break;
571  }
572  }
573  }
574 }
575 
576 void
578 {
579  stack_frame tmp (cs[0]);
580  tmp.m_prev = curr_frame;
581 
582  curr_frame = cs.size ();
583 
584  cs.push_back (tmp);
585 
587 }
const Cell & contents(const_iterator p) const
Definition: oct-map.h:313
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:120
static const std::string anonymous
Definition: ov-fcn-handle.h:50
std::string fcn_name(bool print_subfn=true) const
Definition: call-stack.cc:45
void do_push(octave_function *fcn, symbol_table::scope_id scope, symbol_table::context_id context)
Definition: call-stack.h:395
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &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 F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
bool operator==(const stack_frame &rhs) const
Definition: call-stack.cc:68
int do_caller_user_code_column(void) const
Definition: call-stack.cc:216
for large enough k
Definition: lu.cc:606
virtual bool is_user_code(void) const
Definition: ov-base.h:463
std::list< octave_call_stack::stack_frame > do_backtrace_frames(size_t nskip, octave_idx_type &curr_user_frame) const
Definition: call-stack.cc:368
std::string fcn_file_name(void) const
Definition: call-stack.cc:39
bool do_all_scripts(void) const
Definition: call-stack.cc:332
int do_debug_user_code_line(void) const
Definition: call-stack.cc:270
static void create_instance(void)
Definition: call-stack.cc:83
OCTAVE_EXPORT octave_value_list 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:302
static scope_id top_scope(void)
Definition: symtab.h:1161
octave_user_code * do_debug_user_code(void) const
Definition: call-stack.cc:242
bool verbose
Definition: load-save.cc:654
std::deque< stack_frame > cs
Definition: call-stack.h:328
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
static std::string fcn_file_name(const octave_value &fcn)
Definition: symtab.cc:1168
void do_goto_caller_frame(void)
Definition: call-stack.cc:539
std::deque< stack_frame >::const_iterator const_iterator
Definition: call-stack.h:87
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:76
static void add(fptr f)
int do_current_column(void) const
Definition: call-stack.cc:110
bool do_goto_frame(size_t n, bool verbose)
Definition: call-stack.cc:441
int do_caller_user_code_line(void) const
Definition: call-stack.cc:190
static const octave_fields bt_fields(bt_fieldnames)
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
virtual bool is_user_script(void) const
Definition: ov-base.h:459
static const char * bt_fieldnames[]
Definition: call-stack.cc:356
octave_map do_backtrace(size_t nskip, octave_idx_type &curr_user_frame, bool print_subfn) const
Definition: call-stack.cc:402
symbol_table::scope_id m_scope
Definition: call-stack.h:81
octave_call_stack(void)
Definition: call-stack.h:45
size_t do_num_user_code_frames(octave_idx_type &curr_user_frame) const
Definition: call-stack.cc:125
bool do_goto_frame_relative(int n, bool verbose)
Definition: call-stack.cc:469
virtual std::string fcn_file_name(void) const
Definition: ov-fcn.h:64
#define octave_stdout
Definition: pager.h:146
char Vfilemarker
Definition: input.cc:124
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
static octave_map empty_backtrace(void)
Definition: call-stack.cc:362
static octave_call_stack * instance
Definition: call-stack.h:332
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
int do_current_line(void) const
Definition: call-stack.cc:96
octave_user_code * do_caller_user_code(size_t nskip) const
Definition: call-stack.cc:162
std::deque< stack_frame >::const_reverse_iterator const_reverse_iterator
Definition: call-stack.h:90
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:854
int do_debug_user_code_column(void) const
Definition: call-stack.cc:301
static void cleanup_instance(void)
Definition: call-stack.h:334
symbol_table::context_id m_context
Definition: call-stack.h:82
static void set_scope_and_context(scope_id scope, context_id context)
Definition: symtab.h:1193
octave_function * m_fcn
Definition: call-stack.h:78
void do_goto_base_frame(void)
Definition: call-stack.cc:577