changeset 33060:50e19b01e111

make dblist and dbtype follow debugger stack frame pointer (bug #65330) * utils.h, utils.cc (display_file_lines): New function. * pt-eval.h, pt-eval.cc (tree_evaluator::debug_list, tree_evaluator::debug_type): New functions. * stack-frame.h, stack-frame.cc (stack_frame::debug_where): New alias for display_stopped_in_message. (stack_frame::debug_list, stack_frame::debug_list): New functions. * debug.cc (do_dbtype): Delete static function. (Fdbtype): Decode arguments and forward to either display_file_lines or tree_evaluator::debug_type. (Fdblist): Decode arguments and forward to tree_evaluator::debug_list.
author John W. Eaton <jwe@octave.org>
date Tue, 20 Feb 2024 15:04:18 -0500
parents 7ca23b98c04f
children 3bb4422bd982 406c7ef068af
files libinterp/corefcn/debug.cc libinterp/corefcn/stack-frame.cc libinterp/corefcn/stack-frame.h libinterp/corefcn/utils.cc libinterp/corefcn/utils.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h
diffstat 7 files changed, 130 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/debug.cc	Tue Feb 20 10:45:34 2024 -0800
+++ b/libinterp/corefcn/debug.cc	Tue Feb 20 15:04:18 2024 -0500
@@ -592,37 +592,6 @@
   return ovl ();
 }
 
-static void
-do_dbtype (std::ostream& os, const std::string& name, int start, int end)
-{
-  std::string ff = octave::fcn_file_in_path (name);
-
-  if (ff.empty ())
-    os << "dbtype: unknown function " << name << "\n";
-  else
-    {
-      std::ifstream fs = octave::sys::ifstream (ff.c_str (), std::ios::in);
-
-      if (! fs)
-        os << "dbtype: unable to open '" << ff << "' for reading!\n";
-      else
-        {
-          int line = 1;
-          std::string text;
-
-          while (std::getline (fs, text) && line <= end)
-            {
-              if (line >= start)
-                os << line << "\t" << text << "\n";
-
-              line++;
-            }
-        }
-    }
-
-  os.flush ();
-}
-
 DEFMETHOD (dbtype, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {} dbtype
@@ -647,23 +616,17 @@
 @seealso{dblist, dbwhere, dbstatus, dbstop}
 @end deftypefn */)
 {
-  octave_user_code *dbg_fcn;
-
   string_vector argv = args.make_argv ("dbtype");
 
-  octave::tree_evaluator& tw = interp.get_evaluator ();
+  // Empty means current function on call stack.
+  std::string fcn_name;
+
+  int start = 0;
+  int end = std::numeric_limits<int>::max ();
 
   switch (args.length ())
     {
     case 0:  // dbtype
-      dbg_fcn = tw.get_user_code ();
-
-      if (! dbg_fcn)
-        error ("dbtype: must be inside a user function to give no arguments to dbtype\n");
-
-      do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
-                 0, std::numeric_limits<int>::max ());
-
       break;
 
     case 1:  // (dbtype start:end) || (dbtype fcn) || (dbtype lineno)
@@ -674,54 +637,34 @@
 
         if (ind != std::string::npos)  // (dbtype start:end)
           {
-            dbg_fcn = tw.get_user_code ();
-
-            if (dbg_fcn)
-              {
-                std::string start_str = arg.substr (0, ind);
-                std::string end_str = arg.substr (ind + 1);
+            std::string start_str = arg.substr (0, ind);
+            std::string end_str = arg.substr (ind + 1);
 
-                int start, end;
-                start = atoi (start_str.c_str ());
-                if (end_str == "end")
-                  end = std::numeric_limits<int>::max ();
-                else
-                  end = atoi (end_str.c_str ());
+            start = atoi (start_str.c_str ());
+            if (end_str == "end")
+              end = std::numeric_limits<int>::max ();
+            else
+              end = atoi (end_str.c_str ());
 
-                if (std::min (start, end) <= 0)
-                  error ("dbtype: start and end lines must be >= 1\n");
+            if (std::min (start, end) <= 0)
+              error ("dbtype: start and end lines must be >= 1\n");
 
-                if (start > end)
-                  error ("dbtype: start line must be less than end line\n");
-
-                do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
-                           start, end);
-              }
+            if (start > end)
+              error ("dbtype: start line must be less than end line\n");
           }
         else  // (dbtype fcn) || (dbtype lineno)
           {
             int line = atoi (arg.c_str ());
 
             if (line == 0)  // (dbtype fcn)
-              {
-                dbg_fcn = tw.get_user_code (arg);
-
-                if (! dbg_fcn)
-                  error ("dbtype: function <%s> not found\n", arg.c_str ());
-
-                do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
-                           0, std::numeric_limits<int>::max ());
-              }
+              fcn_name = arg;
             else  // (dbtype lineno)
               {
                 if (line <= 0)
                   error ("dbtype: start and end lines must be >= 1\n");
 
-                dbg_fcn = tw.get_user_code ();
-
-                if (dbg_fcn)
-                  do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
-                             line, line);
+                start = line;
+                end = line;
               }
           }
       }
@@ -729,13 +672,9 @@
 
     case 2:  // (dbtype fcn start:end) || (dbtype fcn start)
       {
-        dbg_fcn = tw.get_user_code (argv[1]);
-
-        if (! dbg_fcn)
-          error ("dbtype: function <%s> not found\n", argv[1].c_str ());
+        fcn_name = argv[1];
 
         std::string arg = argv[2];
-        int start, end;
         std::size_t ind = arg.find (':');
 
         if (ind != std::string::npos)
@@ -760,8 +699,6 @@
 
         if (start > end)
           error ("dbtype: start line must be less than end line\n");
-
-        do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (), start, end);
       }
       break;
 
@@ -769,6 +706,22 @@
       error ("dbtype: expecting zero, one, or two arguments\n");
     }
 
+  if (fcn_name.empty ())
+    {
+      octave::tree_evaluator& tw = interp.get_evaluator ();
+
+      tw.debug_type (octave_stdout, start, end);
+    }
+  else
+    {
+      std::string file_name = octave::fcn_file_in_path (fcn_name);
+
+      if (file_name.empty ())
+        error ("dbtype: unknown function '%s'", fcn_name.c_str ());
+
+      octave::display_file_lines (octave_stdout, file_name, start, end, -1, "", "dbtype");
+    }
+
   return ovl ();
 }
 
@@ -785,7 +738,12 @@
 {
   int n = 10;
 
-  if (args.length () == 1)
+  int numel = args.length ();
+
+  if (numel > 1)
+    print_usage ();
+
+  if (numel == 1)
     {
       octave_value arg = args(0);
 
@@ -804,44 +762,7 @@
 
   octave::tree_evaluator& tw = interp.get_evaluator ();
 
-  octave_user_code *dbg_fcn = tw.get_user_code ();
-
-  if (! dbg_fcn)
-    error ("dblist: must be inside a user function to use dblist\n");
-
-  bool have_file = true;
-
-  std::string name = dbg_fcn->fcn_file_name ();
-
-  if (name.empty ())
-    {
-      have_file = false;
-      name = dbg_fcn->name ();
-    }
-
-  int l = tw.debug_user_code_line ();
-
-  if (l > 0)
-    {
-      if (have_file)
-        {
-          int l_min = std::max (l - n/2, 0);
-          int l_max = l + n/2;
-          do_dbtype (octave_stdout, name, l_min, l-1);
-
-          std::string line = dbg_fcn->get_code_line (l);
-
-          if (! line.empty ())
-            octave_stdout << l << "-->\t" << line << std::endl;
-
-          do_dbtype (octave_stdout, name, l+1, l_max);
-        }
-    }
-  else
-    {
-      octave_stdout << "dblist: unable to determine source code line"
-                    << std::endl;
-    }
+  tw.debug_list (octave_stdout, n);
 
   return ovl ();
 }
--- a/libinterp/corefcn/stack-frame.cc	Tue Feb 20 10:45:34 2024 -0800
+++ b/libinterp/corefcn/stack-frame.cc	Tue Feb 20 15:04:18 2024 -0500
@@ -30,6 +30,7 @@
 #include <iostream>
 
 #include "lo-regexp.h"
+#include "lo-sysdep.h"
 #include "str-vec.h"
 
 #include "defun.h"
@@ -48,6 +49,7 @@
 #include "syminfo.h"
 #include "symrec.h"
 #include "symscope.h"
+#include "utils.h"
 #include "variables.h"
 
 OCTAVE_BEGIN_NAMESPACE(octave)
@@ -1483,6 +1485,24 @@
 }
 
 void
+stack_frame::debug_list (std::ostream& os, int num_lines) const
+{
+  std::string file_name = fcn_file_name ();
+
+  int target_line = line ();
+  int start = std::max (target_line - num_lines/2, 0);
+  int end = target_line + num_lines/2;
+
+  display_file_lines (os, fcn_file_name (), start, end, target_line, "-->", "dblist");
+}
+
+void
+stack_frame::debug_type (std::ostream& os, int start_line, int end_line) const
+{
+  display_file_lines (os, fcn_file_name (), start_line, end_line, -1, "", "dbtype");
+}
+
+void
 stack_frame::display (bool follow) const
 {
   std::ostream& os = octave_stdout;
--- a/libinterp/corefcn/stack-frame.h	Tue Feb 20 10:45:34 2024 -0800
+++ b/libinterp/corefcn/stack-frame.h	Tue Feb 20 15:04:18 2024 -0500
@@ -561,6 +561,15 @@
 
   void display_stopped_in_message (std::ostream& os) const;
 
+  void debug_where (std::ostream& os) const
+  {
+    display_stopped_in_message (os);
+  }
+
+  void debug_list (std::ostream& os, int num_lines) const;
+
+  void debug_type (std::ostream& os, int start_line, int end_line) const;
+
   virtual void mark_scope (const symbol_record&, scope_flags) = 0;
 
   virtual void display (bool follow = true) const;
--- a/libinterp/corefcn/utils.cc	Tue Feb 20 10:45:34 2024 -0800
+++ b/libinterp/corefcn/utils.cc	Tue Feb 20 15:04:18 2024 -0500
@@ -803,6 +803,35 @@
   return retval;
 }
 
+void
+display_file_lines (std::ostream& os, const std::string& file_name, int start, int end, int target_line, const std::string& marker, const std::string& who)
+{
+  std::ifstream fs = octave::sys::ifstream (file_name.c_str (), std::ios::in);
+
+  if (! fs)
+    os << who << ": unable to open '" << file_name << "' for reading!\n";
+  else
+    {
+      int line_num = 1;
+      std::string text;
+
+      while (std::getline (fs, text) && line_num <= end)
+        {
+          if (line_num >= start)
+            {
+              os << line_num;
+
+              if (line_num == target_line)
+                os << marker;
+
+              os << "\t" << text << "\n";
+            }
+
+          line_num++;
+        }
+    }
+}
+
 // Replace backslash escapes in a string with the real values.
 
 std::string
--- a/libinterp/corefcn/utils.h	Tue Feb 20 10:45:34 2024 -0800
+++ b/libinterp/corefcn/utils.h	Tue Feb 20 15:04:18 2024 -0500
@@ -135,6 +135,9 @@
 
 extern OCTINTERP_API std::string fcn_file_in_path (const std::string&);
 
+extern OCTINTERP_API void
+display_file_lines (std::ostream& os, const std::string& file_name, int start, int end, int target_line, const std::string& marker, const std::string& who);
+
 extern OCTINTERP_API std::string do_string_escapes (const std::string& s);
 
 extern OCTINTERP_API const char * undo_string_escape (char c);
--- a/libinterp/parse-tree/pt-eval.cc	Tue Feb 20 10:45:34 2024 -0800
+++ b/libinterp/parse-tree/pt-eval.cc	Tue Feb 20 15:04:18 2024 -0500
@@ -2549,6 +2549,28 @@
   frm->display_stopped_in_message (os);
 }
 
+void
+tree_evaluator::debug_list (std::ostream& os, int num_lines) const
+{
+  std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame ();
+
+  if (! (frm->is_user_script_frame () || frm->is_user_fcn_frame ()))
+    error ("dblist: must be inside a user function or script to use dblist\n");
+
+  frm->debug_list (os, num_lines);
+}
+
+void
+tree_evaluator::debug_type (std::ostream& os, int start_line, int end_line) const
+{
+  std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame ();
+
+  if (! (frm->is_user_script_frame () || frm->is_user_fcn_frame ()))
+    error ("dbtype: must be inside a user function or script to use dbtype\n");
+
+  frm->debug_type (os, start_line, end_line);
+}
+
 octave_user_code *
 tree_evaluator::current_user_code () const
 {
--- a/libinterp/parse-tree/pt-eval.h	Tue Feb 20 10:45:34 2024 -0800
+++ b/libinterp/parse-tree/pt-eval.h	Tue Feb 20 15:04:18 2024 -0500
@@ -466,6 +466,10 @@
 
   void debug_where (std::ostream& os) const;
 
+  void debug_list (std::ostream& os, int num_lines) const;
+
+  void debug_type (std::ostream& os, int start_line, int end_line) const;
+
   octave_user_code * current_user_code () const;
 
   unwind_protect * curr_fcn_unwind_protect_frame ();