Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Matthieu Longo <matthieu.longo@arm.com>
To: <gdb-patches@sourceware.org>, Tom Tromey <tom@tromey.com>
Cc: Matthieu Longo <matthieu.longo@arm.com>
Subject: [PATCH v1 2/4] gdb/python: eval_python_command returns both exit code and result
Date: Thu, 9 Apr 2026 11:51:53 +0100	[thread overview]
Message-ID: <20260409105155.1416274-3-matthieu.longo@arm.com> (raw)
In-Reply-To: <20260409105155.1416274-1-matthieu.longo@arm.com>

A previous commit [1] centralized the Python code evaluation in the
helper function eval_python_command(). However, a missed case in
varobj_set_visualizer() requires both the exit code and the result
of the evaluation.

This patch updates eval_python_command() to return both values and
adjusts existing callers accordingly. It also replaces the use of
PyRun_String() in varobj_set_visualizer() with a call to
eval_python_command().

[1]: 264a8a2236e8aa64b333a69e42a55ff8c0844f6e

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
---
 gdb/python/py-gdb-readline.c |  3 +-
 gdb/python/python-internal.h |  4 +--
 gdb/python/python.c          | 54 +++++++++++++++++++-----------------
 gdb/varobj.c                 | 12 ++------
 4 files changed, 35 insertions(+), 38 deletions(-)

diff --git a/gdb/python/py-gdb-readline.c b/gdb/python/py-gdb-readline.c
index e8e2c23547c..eedeb659c18 100644
--- a/gdb/python/py-gdb-readline.c
+++ b/gdb/python/py-gdb-readline.c
@@ -114,7 +114,8 @@ class GdbRemoveReadlineFinder(MetaPathFinder):\n\
 \n\
 sys.meta_path.insert(2, GdbRemoveReadlineFinder())\n\
 ";
-  if (eval_python_command (code, Py_file_input) == 0)
+  auto [ret, _] = eval_python_command (code, Py_file_input);
+  if (ret == 0)
     PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
 
   return 0;
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 37bc37691fe..ca70ca57fd2 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -1337,7 +1337,7 @@ class gdbpy_memoizing_registry_storage
   gdb::unordered_map<val_type *, obj_type *> m_objects;
 };
 
-extern int eval_python_command (const char *command, int start_symbol,
-				const char *filename = nullptr);
+extern std::pair<int, gdbpy_ref<>> eval_python_command
+  (const char *command, int start_symbol, const char *filename = nullptr);
 
 #endif /* GDB_PYTHON_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 4182c699cb5..85bd88cd243 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -299,42 +299,40 @@ gdbpy_check_quit_flag (const struct extension_language_defn *extlang)
    NULL means that this is evaluating a string, not the contents of a
    file.  */
 
-int
+std::pair<int, gdbpy_ref<>>
 eval_python_command (const char *command, int start_symbol,
 		     const char *filename)
 {
-  PyObject *m, *d;
-
-  m = PyImport_AddModule ("__main__");
-  if (m == NULL)
-    return -1;
+  gdbpy_borrowed_ref<> mainmod = PyImport_AddModule ("__main__");
+  if (mainmod == nullptr)
+    return std::make_pair(-1, nullptr);
 
-  d = PyModule_GetDict (m);
-  if (d == NULL)
-    return -1;
+  gdbpy_borrowed_ref<> globals = PyModule_GetDict (mainmod);
+  if (globals == nullptr)
+    return std::make_pair(-1, nullptr);
 
   bool file_set = false;
   if (filename != nullptr)
     {
       gdbpy_ref<> file = host_string_to_python_string ("__file__");
       if (file == nullptr)
-	return -1;
+	return std::make_pair(-1, nullptr);
 
       /* PyDict_GetItemWithError returns a borrowed reference.  */
-      PyObject *found = PyDict_GetItemWithError (d, file.get ());
+      PyObject *found = PyDict_GetItemWithError (globals, file.get ());
       if (found == nullptr)
 	{
 	  if (PyErr_Occurred ())
-	    return -1;
+	    return std::make_pair(-1, nullptr);
 
 	  gdbpy_ref<> filename_obj = host_string_to_python_string (filename);
 	  if (filename_obj == nullptr)
-	    return -1;
+	    return std::make_pair(-1, nullptr);
 
-	  if (PyDict_SetItem (d, file.get (), filename_obj.get ()) < 0)
-	    return -1;
-	  if (PyDict_SetItemString (d, "__cached__", Py_None) < 0)
-	    return -1;
+	  if (PyDict_SetItem (globals, file.get (), filename_obj.get ()) < 0)
+	    return std::make_pair(-1, nullptr);
+	  if (PyDict_SetItemString (globals, "__cached__", Py_None) < 0)
+	    return std::make_pair(-1, nullptr);
 
 	  file_set = true;
 	}
@@ -348,9 +346,10 @@ eval_python_command (const char *command, int start_symbol,
 				      start_symbol));
 
   int result = -1;
+  gdbpy_ref<> eval_result;
   if (code != nullptr)
     {
-      gdbpy_ref<> eval_result (PyEval_EvalCode (code.get (), d, d));
+      eval_result.reset (PyEval_EvalCode (code.get (), globals, globals));
       if (eval_result != nullptr)
 	result = 0;
     }
@@ -365,16 +364,16 @@ eval_python_command (const char *command, int start_symbol,
 
       /* CPython also just ignores errors here.  These should be
 	 expected to be exceedingly rare anyway.  */
-      if (PyDict_DelItemString (d, "__file__") < 0)
+      if (PyDict_DelItemString (globals, "__file__") < 0)
 	PyErr_Clear ();
-      if (PyDict_DelItemString (d, "__cached__") < 0)
+      if (PyDict_DelItemString (globals, "__cached__") < 0)
 	PyErr_Clear ();
 
       if (save_error.has_value ())
 	save_error->restore ();
     }
 
-  return result;
+  return std::make_pair(result, eval_result);
 }
 
 /* Implementation of the gdb "python-interactive" command.  */
@@ -395,7 +394,8 @@ python_interactive_command (const char *arg, int from_tty)
     {
       std::string script = std::string (arg) + "\n";
       /* Py_single_input causes the result to be displayed.  */
-      err = eval_python_command (script.c_str (), Py_single_input);
+      std::tie (err, std::ignore)
+	= eval_python_command (script.c_str (), Py_single_input);
     }
   else
     {
@@ -424,7 +424,9 @@ static int
 python_run_simple_file (FILE *file, const char *filename)
 {
   std::string contents = read_remainder_of_file (file);
-  return eval_python_command (contents.c_str (), Py_file_input, filename);
+  auto [ret, _]
+    = eval_python_command (contents.c_str (), Py_file_input, filename);
+  return ret;
 }
 
 /* Given a command_line, return a command string suitable for passing
@@ -457,7 +459,7 @@ gdbpy_eval_from_control_command (const struct extension_language_defn *extlang,
   gdbpy_enter enter_py;
 
   std::string script = compute_python_string (cmd->body_list_0.get ());
-  int ret = eval_python_command (script.c_str (), Py_file_input);
+  auto [ret, _] = eval_python_command (script.c_str (), Py_file_input);
   if (ret != 0)
     gdbpy_handle_exception ();
 }
@@ -474,7 +476,7 @@ python_command (const char *arg, int from_tty)
   arg = skip_spaces (arg);
   if (arg && *arg)
     {
-      int ret = eval_python_command (arg, Py_file_input);
+      auto [ret, _] = eval_python_command (arg, Py_file_input);
       if (ret != 0)
 	gdbpy_handle_exception ();
     }
@@ -1848,7 +1850,7 @@ gdbpy_execute_objfile_script (const struct extension_language_defn *extlang,
   scoped_restore restire_current_objfile
     = make_scoped_restore (&gdbpy_current_objfile, objfile);
 
-  int ret = eval_python_command (script, Py_file_input);
+  auto [ret, _] = eval_python_command (script, Py_file_input);
   if (ret != 0)
     gdbpy_print_stack ();
 }
diff --git a/gdb/varobj.c b/gdb/varobj.c
index edd94ea4963..b20fc78eb28 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -1365,20 +1365,14 @@ void
 varobj_set_visualizer (struct varobj *var, const char *visualizer)
 {
 #if HAVE_PYTHON
-  PyObject *mainmod;
-
   if (!gdb_python_initialized)
     return;
 
   gdbpy_enter_varobj enter_py (var);
 
-  mainmod = PyImport_AddModule ("__main__");
-  gdbpy_ref<> globals
-    = gdbpy_ref<>::new_reference (PyModule_GetDict (mainmod));
-  gdbpy_ref<> constructor (PyRun_String (visualizer, Py_eval_input,
-					 globals.get (), globals.get ()));
-
-  if (constructor == NULL)
+  auto [ret_code, constructor]
+    = eval_python_command (visualizer, Py_eval_input);
+  if (ret_code != 0 || constructor == nullptr)
     {
       gdbpy_print_stack ();
       error (_("Could not evaluate visualizer expression: %s"), visualizer);
-- 
2.53.0


  parent reply	other threads:[~2026-04-09 10:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-09 10:51 [PATCH v1 0/4] gdb/python: more fixes again for Python limited C API support Matthieu Longo
2026-04-09 10:51 ` [PATCH v1 1/4] gdb/python: add gdbpy_borrowed_ref Matthieu Longo
2026-04-09 10:51 ` Matthieu Longo [this message]
2026-04-09 10:51 ` [PATCH v1 3/4] gdb/python: migrate Python initialization to use the new config API (PEP 741) Matthieu Longo
2026-04-09 10:51 ` [PATCH v1 4/4] gdb/python: work around missing symbols not yet part of Python limited API Matthieu Longo
2026-04-15  9:18 ` [PATCH v1 0/4] gdb/python: more fixes again for Python limited C API support Matthieu Longo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260409105155.1416274-3-matthieu.longo@arm.com \
    --to=matthieu.longo@arm.com \
    --cc=gdb-patches@sourceware.org \
    --cc=tom@tromey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox