mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
372d0a4c96
I tried out making python initialization fail by passing an incorrect PYTHONHOME, and got: ... $ PYTHONHOME=foo ./gdb.sh -q Python path configuration: PYTHONHOME = 'foo' ... Python initialization failed: \ failed to get the Python codec of the filesystem encoding Python not initialized $ ... The relevant part of the code is: ... static void gdbpy_initialize (const struct extension_language_defn *extlang) { if (!do_start_initialization () && py_isinitialized && PyErr_Occurred ()) gdbpy_print_stack (); gdbpy_enter enter_py; ... What happens is: - gdbpy_enter::gdbpy_enter () is called, where we run into: 'if (!gdb_python_initialized) error (_("Python not initialized"));' - the error propagates to gdb's toplevel - gdb print the error and exits. It seems unnecesssary that we exit gdb. We could continue the session without python support. Fix this by: - bailing out of gdbpy_initialize if !do_start_initialization - bailing out of finalize_python if !gdb_python_initialized This gets us instead: ... $ PYTHONHOME=foo gdb -q Python path configuration: PYTHONHOME = 'foo' ... Python initialization failed: \ failed to get the Python codec of the filesystem encoding (gdb) python print (1) Python not initialized (gdb) ... Tested on aarch64-linux. Approved-By: Tom Tromey <tom@tromey.com>
3037 lines
87 KiB
C
3037 lines
87 KiB
C
/* General python/gdb code
|
||
|
||
Copyright (C) 2008-2024 Free Software Foundation, Inc.
|
||
|
||
This file is part of GDB.
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||
|
||
#include "arch-utils.h"
|
||
#include "command.h"
|
||
#include "ui-out.h"
|
||
#include "cli/cli-script.h"
|
||
#include "cli/cli-cmds.h"
|
||
#include "progspace.h"
|
||
#include "objfiles.h"
|
||
#include "value.h"
|
||
#include "language.h"
|
||
#include "gdbsupport/event-loop.h"
|
||
#include "readline/tilde.h"
|
||
#include "python.h"
|
||
#include "extension-priv.h"
|
||
#include "cli/cli-utils.h"
|
||
#include <ctype.h>
|
||
#include "location.h"
|
||
#include "run-on-main-thread.h"
|
||
#include "observable.h"
|
||
#include "build-id.h"
|
||
|
||
#if GDB_SELF_TEST
|
||
#include "gdbsupport/selftest.h"
|
||
#endif
|
||
|
||
/* Declared constants and enum for python stack printing. */
|
||
static const char python_excp_none[] = "none";
|
||
static const char python_excp_full[] = "full";
|
||
static const char python_excp_message[] = "message";
|
||
|
||
/* "set python print-stack" choices. */
|
||
static const char *const python_excp_enums[] =
|
||
{
|
||
python_excp_none,
|
||
python_excp_full,
|
||
python_excp_message,
|
||
NULL
|
||
};
|
||
|
||
/* The exception printing variable. 'full' if we want to print the
|
||
error message and stack, 'none' if we want to print nothing, and
|
||
'message' if we only want to print the error message. 'message' is
|
||
the default. */
|
||
static const char *gdbpy_should_print_stack = python_excp_message;
|
||
|
||
|
||
#ifdef HAVE_PYTHON
|
||
|
||
#include "cli/cli-decode.h"
|
||
#include "charset.h"
|
||
#include "top.h"
|
||
#include "ui.h"
|
||
#include "python-internal.h"
|
||
#include "linespec.h"
|
||
#include "source.h"
|
||
#include "gdbsupport/version.h"
|
||
#include "target.h"
|
||
#include "gdbthread.h"
|
||
#include "interps.h"
|
||
#include "event-top.h"
|
||
#include "py-event.h"
|
||
|
||
/* True if Python has been successfully initialized, false
|
||
otherwise. */
|
||
|
||
int gdb_python_initialized;
|
||
|
||
extern PyMethodDef python_GdbMethods[];
|
||
|
||
PyObject *gdb_module;
|
||
PyObject *gdb_python_module;
|
||
|
||
/* Some string constants we may wish to use. */
|
||
PyObject *gdbpy_to_string_cst;
|
||
PyObject *gdbpy_children_cst;
|
||
PyObject *gdbpy_display_hint_cst;
|
||
PyObject *gdbpy_doc_cst;
|
||
PyObject *gdbpy_enabled_cst;
|
||
PyObject *gdbpy_value_cst;
|
||
|
||
/* The GdbError exception. */
|
||
PyObject *gdbpy_gdberror_exc;
|
||
|
||
/* The `gdb.error' base class. */
|
||
PyObject *gdbpy_gdb_error;
|
||
|
||
/* The `gdb.MemoryError' exception. */
|
||
PyObject *gdbpy_gdb_memory_error;
|
||
|
||
static script_sourcer_func gdbpy_source_script;
|
||
static objfile_script_sourcer_func gdbpy_source_objfile_script;
|
||
static objfile_script_executor_func gdbpy_execute_objfile_script;
|
||
static void gdbpy_initialize (const struct extension_language_defn *);
|
||
static int gdbpy_initialized (const struct extension_language_defn *);
|
||
static void finalize_python (const struct extension_language_defn *);
|
||
static void gdbpy_eval_from_control_command
|
||
(const struct extension_language_defn *, struct command_line *cmd);
|
||
static void gdbpy_start_type_printers (const struct extension_language_defn *,
|
||
struct ext_lang_type_printers *);
|
||
static enum ext_lang_rc gdbpy_apply_type_printers
|
||
(const struct extension_language_defn *,
|
||
const struct ext_lang_type_printers *, struct type *,
|
||
gdb::unique_xmalloc_ptr<char> *);
|
||
static void gdbpy_free_type_printers (const struct extension_language_defn *,
|
||
struct ext_lang_type_printers *);
|
||
static void gdbpy_set_quit_flag (const struct extension_language_defn *);
|
||
static bool gdbpy_check_quit_flag (const struct extension_language_defn *);
|
||
static enum ext_lang_rc gdbpy_before_prompt_hook
|
||
(const struct extension_language_defn *, const char *current_gdb_prompt);
|
||
static std::optional<std::string> gdbpy_colorize
|
||
(const std::string &filename, const std::string &contents);
|
||
static std::optional<std::string> gdbpy_colorize_disasm
|
||
(const std::string &content, gdbarch *gdbarch);
|
||
static ext_lang_missing_file_result gdbpy_handle_missing_debuginfo
|
||
(const struct extension_language_defn *extlang, struct objfile *objfile);
|
||
static ext_lang_missing_file_result gdbpy_find_objfile_from_buildid
|
||
(const struct extension_language_defn *extlang, program_space *pspace,
|
||
const struct bfd_build_id *build_id, const char *missing_filename);
|
||
|
||
/* The interface between gdb proper and loading of python scripts. */
|
||
|
||
static const struct extension_language_script_ops python_extension_script_ops =
|
||
{
|
||
gdbpy_source_script,
|
||
gdbpy_source_objfile_script,
|
||
gdbpy_execute_objfile_script,
|
||
gdbpy_auto_load_enabled
|
||
};
|
||
|
||
/* The interface between gdb proper and python extensions. */
|
||
|
||
static const struct extension_language_ops python_extension_ops =
|
||
{
|
||
gdbpy_initialize,
|
||
gdbpy_initialized,
|
||
finalize_python,
|
||
|
||
gdbpy_eval_from_control_command,
|
||
|
||
gdbpy_start_type_printers,
|
||
gdbpy_apply_type_printers,
|
||
gdbpy_free_type_printers,
|
||
|
||
gdbpy_apply_val_pretty_printer,
|
||
|
||
gdbpy_apply_frame_filter,
|
||
|
||
gdbpy_load_ptwrite_filter,
|
||
|
||
gdbpy_preserve_values,
|
||
|
||
gdbpy_breakpoint_has_cond,
|
||
gdbpy_breakpoint_cond_says_stop,
|
||
|
||
gdbpy_set_quit_flag,
|
||
gdbpy_check_quit_flag,
|
||
|
||
gdbpy_before_prompt_hook,
|
||
|
||
gdbpy_get_matching_xmethod_workers,
|
||
|
||
gdbpy_colorize,
|
||
|
||
gdbpy_colorize_disasm,
|
||
|
||
gdbpy_print_insn,
|
||
|
||
gdbpy_handle_missing_debuginfo,
|
||
gdbpy_find_objfile_from_buildid
|
||
};
|
||
|
||
#endif /* HAVE_PYTHON */
|
||
|
||
/* The main struct describing GDB's interface to the Python
|
||
extension language. */
|
||
const struct extension_language_defn extension_language_python =
|
||
{
|
||
EXT_LANG_PYTHON,
|
||
"python",
|
||
"Python",
|
||
|
||
".py",
|
||
"-gdb.py",
|
||
|
||
python_control,
|
||
|
||
#ifdef HAVE_PYTHON
|
||
&python_extension_script_ops,
|
||
&python_extension_ops
|
||
#else
|
||
NULL,
|
||
NULL
|
||
#endif
|
||
};
|
||
|
||
#ifdef HAVE_PYTHON
|
||
|
||
/* Architecture and language to be used in callbacks from
|
||
the Python interpreter. */
|
||
struct gdbarch *gdbpy_enter::python_gdbarch;
|
||
|
||
gdbpy_enter::gdbpy_enter (struct gdbarch *gdbarch,
|
||
const struct language_defn *language)
|
||
: m_gdbarch (python_gdbarch),
|
||
m_language (language == nullptr ? nullptr : current_language)
|
||
{
|
||
/* We should not ever enter Python unless initialized. */
|
||
if (!gdb_python_initialized)
|
||
error (_("Python not initialized"));
|
||
|
||
m_previous_active = set_active_ext_lang (&extension_language_python);
|
||
|
||
m_state = PyGILState_Ensure ();
|
||
|
||
python_gdbarch = gdbarch;
|
||
if (language != nullptr)
|
||
set_language (language->la_language);
|
||
|
||
/* Save it and ensure ! PyErr_Occurred () afterwards. */
|
||
m_error.emplace ();
|
||
}
|
||
|
||
gdbpy_enter::~gdbpy_enter ()
|
||
{
|
||
/* Leftover Python error is forbidden by Python Exception Handling. */
|
||
if (PyErr_Occurred ())
|
||
{
|
||
/* This order is similar to the one calling error afterwards. */
|
||
gdbpy_print_stack ();
|
||
warning (_("internal error: Unhandled Python exception"));
|
||
}
|
||
|
||
m_error->restore ();
|
||
|
||
python_gdbarch = m_gdbarch;
|
||
if (m_language != nullptr)
|
||
set_language (m_language->la_language);
|
||
|
||
restore_active_ext_lang (m_previous_active);
|
||
PyGILState_Release (m_state);
|
||
}
|
||
|
||
struct gdbarch *
|
||
gdbpy_enter::get_gdbarch ()
|
||
{
|
||
if (python_gdbarch != nullptr)
|
||
return python_gdbarch;
|
||
return get_current_arch ();
|
||
}
|
||
|
||
void
|
||
gdbpy_enter::finalize ()
|
||
{
|
||
python_gdbarch = current_inferior ()->arch ();
|
||
}
|
||
|
||
/* Set the quit flag. */
|
||
|
||
static void
|
||
gdbpy_set_quit_flag (const struct extension_language_defn *extlang)
|
||
{
|
||
PyErr_SetInterrupt ();
|
||
}
|
||
|
||
/* Return true if the quit flag has been set, false otherwise. */
|
||
|
||
static bool
|
||
gdbpy_check_quit_flag (const struct extension_language_defn *extlang)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return false;
|
||
|
||
gdbpy_gil gil;
|
||
return PyOS_InterruptOccurred ();
|
||
}
|
||
|
||
/* Evaluate a Python command like PyRun_SimpleString, but takes a
|
||
Python start symbol, and does not automatically print the stack on
|
||
errors. FILENAME is used to set the file name in error messages;
|
||
NULL means that this is evaluating a string, not the contents of a
|
||
file. */
|
||
|
||
static int
|
||
eval_python_command (const char *command, int start_symbol,
|
||
const char *filename = nullptr)
|
||
{
|
||
PyObject *m, *d;
|
||
|
||
m = PyImport_AddModule ("__main__");
|
||
if (m == NULL)
|
||
return -1;
|
||
|
||
d = PyModule_GetDict (m);
|
||
if (d == NULL)
|
||
return -1;
|
||
|
||
bool file_set = false;
|
||
if (filename != nullptr)
|
||
{
|
||
gdbpy_ref<> file = host_string_to_python_string ("__file__");
|
||
if (file == nullptr)
|
||
return -1;
|
||
|
||
/* PyDict_GetItemWithError returns a borrowed reference. */
|
||
PyObject *found = PyDict_GetItemWithError (d, file.get ());
|
||
if (found == nullptr)
|
||
{
|
||
if (PyErr_Occurred ())
|
||
return -1;
|
||
|
||
gdbpy_ref<> filename_obj = host_string_to_python_string (filename);
|
||
if (filename_obj == nullptr)
|
||
return -1;
|
||
|
||
if (PyDict_SetItem (d, file.get (), filename_obj.get ()) < 0)
|
||
return -1;
|
||
if (PyDict_SetItemString (d, "__cached__", Py_None) < 0)
|
||
return -1;
|
||
|
||
file_set = true;
|
||
}
|
||
}
|
||
|
||
/* Use this API because it is in Python 3.2. */
|
||
gdbpy_ref<> code (Py_CompileStringExFlags (command,
|
||
filename == nullptr
|
||
? "<string>"
|
||
: filename,
|
||
start_symbol,
|
||
nullptr, -1));
|
||
|
||
int result = -1;
|
||
if (code != nullptr)
|
||
{
|
||
gdbpy_ref<> eval_result (PyEval_EvalCode (code.get (), d, d));
|
||
if (eval_result != nullptr)
|
||
result = 0;
|
||
}
|
||
|
||
if (file_set)
|
||
{
|
||
/* If there's already an exception occurring, preserve it and
|
||
restore it before returning from this function. */
|
||
std::optional<gdbpy_err_fetch> save_error;
|
||
if (result < 0)
|
||
save_error.emplace ();
|
||
|
||
/* CPython also just ignores errors here. These should be
|
||
expected to be exceedingly rare anyway. */
|
||
if (PyDict_DelItemString (d, "__file__") < 0)
|
||
PyErr_Clear ();
|
||
if (PyDict_DelItemString (d, "__cached__") < 0)
|
||
PyErr_Clear ();
|
||
|
||
if (save_error.has_value ())
|
||
save_error->restore ();
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* Implementation of the gdb "python-interactive" command. */
|
||
|
||
static void
|
||
python_interactive_command (const char *arg, int from_tty)
|
||
{
|
||
struct ui *ui = current_ui;
|
||
int err;
|
||
|
||
scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0);
|
||
|
||
arg = skip_spaces (arg);
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
if (arg && *arg)
|
||
{
|
||
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);
|
||
}
|
||
else
|
||
{
|
||
err = PyRun_InteractiveLoop (ui->instream, "<stdin>");
|
||
dont_repeat ();
|
||
}
|
||
|
||
if (err)
|
||
gdbpy_handle_exception ();
|
||
}
|
||
|
||
/* Like PyRun_SimpleFile, but if there is an exception, it is not
|
||
automatically displayed. FILE is the Python script to run named
|
||
FILENAME.
|
||
|
||
On Windows hosts few users would build Python themselves (this is no
|
||
trivial task on this platform), and thus use binaries built by
|
||
someone else instead. There may happen situation where the Python
|
||
library and GDB are using two different versions of the C runtime
|
||
library. Python, being built with VC, would use one version of the
|
||
msvcr DLL (Eg. msvcr100.dll), while MinGW uses msvcrt.dll.
|
||
A FILE * from one runtime does not necessarily operate correctly in
|
||
the other runtime. */
|
||
|
||
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);
|
||
}
|
||
|
||
/* Given a command_line, return a command string suitable for passing
|
||
to Python. Lines in the string are separated by newlines. */
|
||
|
||
static std::string
|
||
compute_python_string (struct command_line *l)
|
||
{
|
||
struct command_line *iter;
|
||
std::string script;
|
||
|
||
for (iter = l; iter; iter = iter->next)
|
||
{
|
||
script += iter->line;
|
||
script += '\n';
|
||
}
|
||
return script;
|
||
}
|
||
|
||
/* Take a command line structure representing a 'python' command, and
|
||
evaluate its body using the Python interpreter. */
|
||
|
||
static void
|
||
gdbpy_eval_from_control_command (const struct extension_language_defn *extlang,
|
||
struct command_line *cmd)
|
||
{
|
||
if (cmd->body_list_1 != nullptr)
|
||
error (_("Invalid \"python\" block structure."));
|
||
|
||
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);
|
||
if (ret != 0)
|
||
gdbpy_handle_exception ();
|
||
}
|
||
|
||
/* Implementation of the gdb "python" command. */
|
||
|
||
static void
|
||
python_command (const char *arg, int from_tty)
|
||
{
|
||
gdbpy_enter enter_py;
|
||
|
||
scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0);
|
||
|
||
arg = skip_spaces (arg);
|
||
if (arg && *arg)
|
||
{
|
||
int ret = eval_python_command (arg, Py_file_input);
|
||
if (ret != 0)
|
||
gdbpy_handle_exception ();
|
||
}
|
||
else
|
||
{
|
||
counted_command_line l = get_command_line (python_control, "");
|
||
|
||
execute_control_command_untraced (l.get ());
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/* Transform a gdb parameters's value into a Python value. May return
|
||
NULL (and set a Python exception) on error. Helper function for
|
||
get_parameter. */
|
||
PyObject *
|
||
gdbpy_parameter_value (const setting &var)
|
||
{
|
||
switch (var.type ())
|
||
{
|
||
case var_string:
|
||
case var_string_noescape:
|
||
case var_optional_filename:
|
||
case var_filename:
|
||
case var_enum:
|
||
{
|
||
const char *str;
|
||
if (var.type () == var_enum)
|
||
str = var.get<const char *> ();
|
||
else
|
||
str = var.get<std::string> ().c_str ();
|
||
|
||
return host_string_to_python_string (str).release ();
|
||
}
|
||
|
||
case var_boolean:
|
||
{
|
||
if (var.get<bool> ())
|
||
Py_RETURN_TRUE;
|
||
else
|
||
Py_RETURN_FALSE;
|
||
}
|
||
|
||
case var_auto_boolean:
|
||
{
|
||
enum auto_boolean ab = var.get<enum auto_boolean> ();
|
||
|
||
if (ab == AUTO_BOOLEAN_TRUE)
|
||
Py_RETURN_TRUE;
|
||
else if (ab == AUTO_BOOLEAN_FALSE)
|
||
Py_RETURN_FALSE;
|
||
else
|
||
Py_RETURN_NONE;
|
||
}
|
||
|
||
case var_uinteger:
|
||
case var_integer:
|
||
case var_pinteger:
|
||
{
|
||
LONGEST value
|
||
= (var.type () == var_uinteger
|
||
? static_cast<LONGEST> (var.get<unsigned int> ())
|
||
: static_cast<LONGEST> (var.get<int> ()));
|
||
|
||
if (var.extra_literals () != nullptr)
|
||
for (const literal_def *l = var.extra_literals ();
|
||
l->literal != nullptr;
|
||
l++)
|
||
if (value == l->use)
|
||
{
|
||
if (strcmp (l->literal, "unlimited") == 0)
|
||
{
|
||
/* Compatibility hack for API brokenness. */
|
||
if (var.type () == var_pinteger
|
||
&& l->val.has_value ()
|
||
&& *l->val == -1)
|
||
value = -1;
|
||
else
|
||
Py_RETURN_NONE;
|
||
}
|
||
else if (l->val.has_value ())
|
||
value = *l->val;
|
||
else
|
||
return host_string_to_python_string (l->literal).release ();
|
||
}
|
||
|
||
if (var.type () == var_uinteger)
|
||
return
|
||
gdb_py_object_from_ulongest
|
||
(static_cast<unsigned int> (value)).release ();
|
||
else
|
||
return
|
||
gdb_py_object_from_longest
|
||
(static_cast<int> (value)).release ();
|
||
}
|
||
}
|
||
|
||
return PyErr_Format (PyExc_RuntimeError,
|
||
_("Programmer error: unhandled type."));
|
||
}
|
||
|
||
/* A Python function which returns a gdb parameter's value as a Python
|
||
value. */
|
||
|
||
static PyObject *
|
||
gdbpy_parameter (PyObject *self, PyObject *args)
|
||
{
|
||
struct cmd_list_element *alias, *prefix, *cmd;
|
||
const char *arg;
|
||
int found = -1;
|
||
|
||
if (! PyArg_ParseTuple (args, "s", &arg))
|
||
return NULL;
|
||
|
||
std::string newarg = std::string ("show ") + arg;
|
||
|
||
try
|
||
{
|
||
found = lookup_cmd_composition (newarg.c_str (), &alias, &prefix, &cmd);
|
||
}
|
||
catch (const gdb_exception &ex)
|
||
{
|
||
return gdbpy_handle_gdb_exception (nullptr, ex);
|
||
}
|
||
|
||
if (cmd == CMD_LIST_AMBIGUOUS)
|
||
return PyErr_Format (PyExc_RuntimeError,
|
||
_("Parameter `%s' is ambiguous."), arg);
|
||
else if (!found)
|
||
return PyErr_Format (PyExc_RuntimeError,
|
||
_("Could not find parameter `%s'."), arg);
|
||
|
||
if (!cmd->var.has_value ())
|
||
return PyErr_Format (PyExc_RuntimeError,
|
||
_("`%s' is not a parameter."), arg);
|
||
|
||
return gdbpy_parameter_value (*cmd->var);
|
||
}
|
||
|
||
/* Wrapper for target_charset. */
|
||
|
||
static PyObject *
|
||
gdbpy_target_charset (PyObject *self, PyObject *args)
|
||
{
|
||
const char *cset = target_charset (gdbpy_enter::get_gdbarch ());
|
||
|
||
return PyUnicode_Decode (cset, strlen (cset), host_charset (), NULL);
|
||
}
|
||
|
||
/* Wrapper for target_wide_charset. */
|
||
|
||
static PyObject *
|
||
gdbpy_target_wide_charset (PyObject *self, PyObject *args)
|
||
{
|
||
const char *cset = target_wide_charset (gdbpy_enter::get_gdbarch ());
|
||
|
||
return PyUnicode_Decode (cset, strlen (cset), host_charset (), NULL);
|
||
}
|
||
|
||
/* Implement gdb.host_charset(). */
|
||
|
||
static PyObject *
|
||
gdbpy_host_charset (PyObject *self, PyObject *args)
|
||
{
|
||
const char *cset = host_charset ();
|
||
|
||
return PyUnicode_Decode (cset, strlen (cset), host_charset (), NULL);
|
||
}
|
||
|
||
/* A Python function which evaluates a string using the gdb CLI. */
|
||
|
||
static PyObject *
|
||
execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
|
||
{
|
||
const char *arg;
|
||
PyObject *from_tty_obj = nullptr;
|
||
PyObject *to_string_obj = nullptr;
|
||
static const char *keywords[] = { "command", "from_tty", "to_string",
|
||
nullptr };
|
||
|
||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!", keywords, &arg,
|
||
&PyBool_Type, &from_tty_obj,
|
||
&PyBool_Type, &to_string_obj))
|
||
return nullptr;
|
||
|
||
bool from_tty = false;
|
||
if (from_tty_obj != nullptr)
|
||
{
|
||
int cmp = PyObject_IsTrue (from_tty_obj);
|
||
if (cmp < 0)
|
||
return nullptr;
|
||
from_tty = (cmp != 0);
|
||
}
|
||
|
||
bool to_string = false;
|
||
if (to_string_obj != nullptr)
|
||
{
|
||
int cmp = PyObject_IsTrue (to_string_obj);
|
||
if (cmp < 0)
|
||
return nullptr;
|
||
to_string = (cmp != 0);
|
||
}
|
||
|
||
std::string to_string_res;
|
||
|
||
scoped_restore preventer = prevent_dont_repeat ();
|
||
|
||
/* If the executed command raises an exception, we may have to
|
||
enable stdin and recover the GDB prompt.
|
||
|
||
Stdin should not be re-enabled if it is already blocked because,
|
||
for example, we are running a command in the context of a
|
||
synchronous execution command ("run", "continue", etc.). Like
|
||
this:
|
||
|
||
User runs "continue"
|
||
--> command blocks the prompt
|
||
--> Python API is invoked, e.g. via events
|
||
--> gdb.execute(C) invoked inside Python
|
||
--> command C raises an exception
|
||
|
||
In this case case, GDB would go back to the top "continue" command
|
||
and move on with its normal course of execution. That is, it
|
||
would enable stdin in the way it normally does.
|
||
|
||
Similarly, if the command we are about to execute enables the
|
||
stdin while we are still in the context of a synchronous
|
||
execution command, we would be displaying the prompt too early,
|
||
before the surrounding command completes.
|
||
|
||
For these reasons, we keep the prompt blocked, if it already is. */
|
||
bool prompt_was_blocked = (current_ui->prompt_state == PROMPT_BLOCKED);
|
||
scoped_restore save_prompt_state
|
||
= make_scoped_restore (¤t_ui->keep_prompt_blocked,
|
||
prompt_was_blocked);
|
||
|
||
try
|
||
{
|
||
gdbpy_allow_threads allow_threads;
|
||
|
||
struct interp *interp;
|
||
|
||
std::string arg_copy = arg;
|
||
bool first = true;
|
||
char *save_ptr = nullptr;
|
||
auto reader
|
||
= [&] (std::string &buffer)
|
||
{
|
||
const char *result = strtok_r (first ? &arg_copy[0] : nullptr,
|
||
"\n", &save_ptr);
|
||
first = false;
|
||
return result;
|
||
};
|
||
|
||
counted_command_line lines = read_command_lines_1 (reader, 1, nullptr);
|
||
|
||
{
|
||
scoped_restore save_async = make_scoped_restore (¤t_ui->async,
|
||
0);
|
||
|
||
scoped_restore save_uiout = make_scoped_restore (¤t_uiout);
|
||
|
||
/* Use the console interpreter uiout to have the same print format
|
||
for console or MI. */
|
||
interp = interp_lookup (current_ui, "console");
|
||
current_uiout = interp->interp_ui_out ();
|
||
|
||
if (to_string)
|
||
to_string_res = execute_control_commands_to_string (lines.get (),
|
||
from_tty);
|
||
else
|
||
execute_control_commands (lines.get (), from_tty);
|
||
}
|
||
|
||
/* Do any commands attached to breakpoint we stopped at. */
|
||
bpstat_do_actions ();
|
||
}
|
||
catch (const gdb_exception &except)
|
||
{
|
||
/* If an exception occurred then we won't hit normal_stop (), or have
|
||
an exception reach the top level of the event loop, which are the
|
||
two usual places in which stdin would be re-enabled. So, before we
|
||
convert the exception and continue back in Python, we should
|
||
re-enable stdin here. */
|
||
async_enable_stdin ();
|
||
return gdbpy_handle_gdb_exception (nullptr, except);
|
||
}
|
||
|
||
if (to_string)
|
||
return PyUnicode_FromString (to_string_res.c_str ());
|
||
Py_RETURN_NONE;
|
||
}
|
||
|
||
/* Implementation of Python rbreak command. Take a REGEX and
|
||
optionally a MINSYMS, THROTTLE and SYMTABS keyword and return a
|
||
Python list that contains newly set breakpoints that match that
|
||
criteria. REGEX refers to a GDB format standard regex pattern of
|
||
symbols names to search; MINSYMS is an optional boolean (default
|
||
False) that indicates if the function should search GDB's minimal
|
||
symbols; THROTTLE is an optional integer (default unlimited) that
|
||
indicates the maximum amount of breakpoints allowable before the
|
||
function exits (note, if the throttle bound is passed, no
|
||
breakpoints will be set and a runtime error returned); SYMTABS is
|
||
an optional Python iterable that contains a set of gdb.Symtabs to
|
||
constrain the search within. */
|
||
|
||
static PyObject *
|
||
gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
|
||
{
|
||
char *regex = NULL;
|
||
std::vector<symbol_search> symbols;
|
||
unsigned long count = 0;
|
||
PyObject *symtab_list = NULL;
|
||
PyObject *minsyms_p_obj = NULL;
|
||
int minsyms_p = 0;
|
||
unsigned int throttle = 0;
|
||
static const char *keywords[] = {"regex","minsyms", "throttle",
|
||
"symtabs", NULL};
|
||
|
||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!IO", keywords,
|
||
®ex, &PyBool_Type,
|
||
&minsyms_p_obj, &throttle,
|
||
&symtab_list))
|
||
return NULL;
|
||
|
||
/* Parse minsyms keyword. */
|
||
if (minsyms_p_obj != NULL)
|
||
{
|
||
int cmp = PyObject_IsTrue (minsyms_p_obj);
|
||
if (cmp < 0)
|
||
return NULL;
|
||
minsyms_p = cmp;
|
||
}
|
||
|
||
global_symbol_searcher spec (SEARCH_FUNCTION_DOMAIN, regex);
|
||
|
||
/* The "symtabs" keyword is any Python iterable object that returns
|
||
a gdb.Symtab on each iteration. If specified, iterate through
|
||
the provided gdb.Symtabs and extract their full path. As
|
||
python_string_to_target_string returns a
|
||
gdb::unique_xmalloc_ptr<char> and a vector containing these types
|
||
cannot be coerced to a const char **p[] via the vector.data call,
|
||
release the value from the unique_xmalloc_ptr and place it in a
|
||
simple type symtab_list_type (which holds the vector and a
|
||
destructor that frees the contents of the allocated strings. */
|
||
if (symtab_list != NULL)
|
||
{
|
||
gdbpy_ref<> iter (PyObject_GetIter (symtab_list));
|
||
|
||
if (iter == NULL)
|
||
return NULL;
|
||
|
||
while (true)
|
||
{
|
||
gdbpy_ref<> next (PyIter_Next (iter.get ()));
|
||
|
||
if (next == NULL)
|
||
{
|
||
if (PyErr_Occurred ())
|
||
return NULL;
|
||
break;
|
||
}
|
||
|
||
gdbpy_ref<> obj_name (PyObject_GetAttrString (next.get (),
|
||
"filename"));
|
||
|
||
if (obj_name == NULL)
|
||
return NULL;
|
||
|
||
/* Is the object file still valid? */
|
||
if (obj_name == Py_None)
|
||
continue;
|
||
|
||
gdb::unique_xmalloc_ptr<char> filename =
|
||
python_string_to_target_string (obj_name.get ());
|
||
|
||
if (filename == NULL)
|
||
return NULL;
|
||
|
||
spec.add_filename (std::move (filename));
|
||
}
|
||
}
|
||
|
||
/* The search spec. */
|
||
symbols = spec.search ();
|
||
|
||
/* Count the number of symbols (both symbols and optionally minimal
|
||
symbols) so we can correctly check the throttle limit. */
|
||
for (const symbol_search &p : symbols)
|
||
{
|
||
/* Minimal symbols included? */
|
||
if (minsyms_p)
|
||
{
|
||
if (p.msymbol.minsym != NULL)
|
||
count++;
|
||
}
|
||
|
||
if (p.symbol != NULL)
|
||
count++;
|
||
}
|
||
|
||
/* Check throttle bounds and exit if in excess. */
|
||
if (throttle != 0 && count > throttle)
|
||
{
|
||
PyErr_SetString (PyExc_RuntimeError,
|
||
_("Number of breakpoints exceeds throttled maximum."));
|
||
return NULL;
|
||
}
|
||
|
||
gdbpy_ref<> return_list (PyList_New (0));
|
||
|
||
if (return_list == NULL)
|
||
return NULL;
|
||
|
||
/* Construct full path names for symbols and call the Python
|
||
breakpoint constructor on the resulting names. Be tolerant of
|
||
individual breakpoint failures. */
|
||
for (const symbol_search &p : symbols)
|
||
{
|
||
std::string symbol_name;
|
||
|
||
/* Skipping minimal symbols? */
|
||
if (minsyms_p == 0)
|
||
if (p.msymbol.minsym != NULL)
|
||
continue;
|
||
|
||
if (p.msymbol.minsym == NULL)
|
||
{
|
||
struct symtab *symtab = p.symbol->symtab ();
|
||
const char *fullname = symtab_to_fullname (symtab);
|
||
|
||
symbol_name = fullname;
|
||
symbol_name += ":";
|
||
symbol_name += p.symbol->linkage_name ();
|
||
}
|
||
else
|
||
symbol_name = p.msymbol.minsym->linkage_name ();
|
||
|
||
gdbpy_ref<> argList (Py_BuildValue("(s)", symbol_name.c_str ()));
|
||
gdbpy_ref<> obj (PyObject_CallObject ((PyObject *)
|
||
&breakpoint_object_type,
|
||
argList.get ()));
|
||
|
||
/* Tolerate individual breakpoint failures. */
|
||
if (obj == NULL)
|
||
gdbpy_print_stack ();
|
||
else
|
||
{
|
||
if (PyList_Append (return_list.get (), obj.get ()) == -1)
|
||
return NULL;
|
||
}
|
||
}
|
||
return return_list.release ();
|
||
}
|
||
|
||
/* A Python function which is a wrapper for decode_line_1. */
|
||
|
||
static PyObject *
|
||
gdbpy_decode_line (PyObject *self, PyObject *args)
|
||
{
|
||
const char *arg = NULL;
|
||
gdbpy_ref<> result;
|
||
gdbpy_ref<> unparsed;
|
||
location_spec_up locspec;
|
||
|
||
if (! PyArg_ParseTuple (args, "|s", &arg))
|
||
return NULL;
|
||
|
||
/* Treat a string consisting of just whitespace the same as
|
||
NULL. */
|
||
if (arg != NULL)
|
||
{
|
||
arg = skip_spaces (arg);
|
||
if (*arg == '\0')
|
||
arg = NULL;
|
||
}
|
||
|
||
if (arg != NULL)
|
||
locspec = string_to_location_spec_basic (&arg, current_language,
|
||
symbol_name_match_type::WILD);
|
||
|
||
std::vector<symtab_and_line> decoded_sals;
|
||
symtab_and_line def_sal;
|
||
gdb::array_view<symtab_and_line> sals;
|
||
try
|
||
{
|
||
if (locspec != NULL)
|
||
{
|
||
decoded_sals = decode_line_1 (locspec.get (), 0, NULL, NULL, 0);
|
||
sals = decoded_sals;
|
||
}
|
||
else
|
||
{
|
||
set_default_source_symtab_and_line ();
|
||
def_sal = get_current_source_symtab_and_line (current_program_space);
|
||
sals = def_sal;
|
||
}
|
||
}
|
||
catch (const gdb_exception &ex)
|
||
{
|
||
/* We know this will always throw. */
|
||
return gdbpy_handle_gdb_exception (nullptr, ex);
|
||
}
|
||
|
||
if (!sals.empty ())
|
||
{
|
||
result.reset (PyTuple_New (sals.size ()));
|
||
if (result == NULL)
|
||
return NULL;
|
||
for (size_t i = 0; i < sals.size (); ++i)
|
||
{
|
||
PyObject *obj = symtab_and_line_to_sal_object (sals[i]);
|
||
if (obj == NULL)
|
||
return NULL;
|
||
|
||
PyTuple_SetItem (result.get (), i, obj);
|
||
}
|
||
}
|
||
else
|
||
result = gdbpy_ref<>::new_reference (Py_None);
|
||
|
||
gdbpy_ref<> return_result (PyTuple_New (2));
|
||
if (return_result == NULL)
|
||
return NULL;
|
||
|
||
if (arg != NULL && strlen (arg) > 0)
|
||
{
|
||
unparsed.reset (PyUnicode_FromString (arg));
|
||
if (unparsed == NULL)
|
||
return NULL;
|
||
}
|
||
else
|
||
unparsed = gdbpy_ref<>::new_reference (Py_None);
|
||
|
||
PyTuple_SetItem (return_result.get (), 0, unparsed.release ());
|
||
PyTuple_SetItem (return_result.get (), 1, result.release ());
|
||
|
||
return return_result.release ();
|
||
}
|
||
|
||
/* Parse a string and evaluate it as an expression. */
|
||
static PyObject *
|
||
gdbpy_parse_and_eval (PyObject *self, PyObject *args, PyObject *kw)
|
||
{
|
||
static const char *keywords[] = { "expression", "global_context", nullptr };
|
||
|
||
const char *expr_str;
|
||
PyObject *global_context_obj = nullptr;
|
||
|
||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!", keywords,
|
||
&expr_str,
|
||
&PyBool_Type, &global_context_obj))
|
||
return nullptr;
|
||
|
||
parser_flags flags = 0;
|
||
if (global_context_obj != NULL)
|
||
{
|
||
int cmp = PyObject_IsTrue (global_context_obj);
|
||
if (cmp < 0)
|
||
return nullptr;
|
||
if (cmp)
|
||
flags |= PARSER_LEAVE_BLOCK_ALONE;
|
||
}
|
||
|
||
PyObject *result = nullptr;
|
||
try
|
||
{
|
||
scoped_value_mark free_values;
|
||
struct value *val;
|
||
{
|
||
/* Allow other Python threads to run while we're evaluating
|
||
the expression. This is important because the expression
|
||
could involve inferior calls or otherwise be a lengthy
|
||
calculation. We take care here to re-acquire the GIL here
|
||
before continuing with Python work. */
|
||
gdbpy_allow_threads allow_threads;
|
||
val = parse_and_eval (expr_str, flags);
|
||
}
|
||
result = value_to_value_object (val);
|
||
}
|
||
catch (const gdb_exception &except)
|
||
{
|
||
return gdbpy_handle_gdb_exception (nullptr, except);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* Implementation of gdb.invalidate_cached_frames. */
|
||
|
||
static PyObject *
|
||
gdbpy_invalidate_cached_frames (PyObject *self, PyObject *args)
|
||
{
|
||
reinit_frame_cache ();
|
||
Py_RETURN_NONE;
|
||
}
|
||
|
||
/* Read a file as Python code.
|
||
This is the extension_language_script_ops.script_sourcer "method".
|
||
FILE is the file to load. FILENAME is name of the file FILE.
|
||
This does not throw any errors. If an exception occurs python will print
|
||
the traceback and clear the error indicator. */
|
||
|
||
static void
|
||
gdbpy_source_script (const struct extension_language_defn *extlang,
|
||
FILE *file, const char *filename)
|
||
{
|
||
gdbpy_enter enter_py;
|
||
int result = python_run_simple_file (file, filename);
|
||
if (result != 0)
|
||
gdbpy_handle_exception ();
|
||
}
|
||
|
||
|
||
|
||
/* Posting and handling events. */
|
||
|
||
/* A single event. */
|
||
struct gdbpy_event
|
||
{
|
||
gdbpy_event (gdbpy_ref<> &&func)
|
||
: m_func (func.release ())
|
||
{
|
||
}
|
||
|
||
gdbpy_event (gdbpy_event &&other) noexcept
|
||
: m_func (other.m_func)
|
||
{
|
||
other.m_func = nullptr;
|
||
}
|
||
|
||
gdbpy_event (const gdbpy_event &other)
|
||
: m_func (other.m_func)
|
||
{
|
||
gdbpy_gil gil;
|
||
Py_XINCREF (m_func);
|
||
}
|
||
|
||
~gdbpy_event ()
|
||
{
|
||
gdbpy_gil gil;
|
||
Py_XDECREF (m_func);
|
||
}
|
||
|
||
gdbpy_event &operator= (const gdbpy_event &other) = delete;
|
||
|
||
void operator() ()
|
||
{
|
||
gdbpy_enter enter_py;
|
||
|
||
gdbpy_ref<> call_result (PyObject_CallObject (m_func, NULL));
|
||
if (call_result == NULL)
|
||
gdbpy_print_stack ();
|
||
}
|
||
|
||
private:
|
||
|
||
/* The Python event. This is just a callable object. Note that
|
||
this is not a gdbpy_ref<>, because we have to take particular
|
||
care to only destroy the reference when holding the GIL. */
|
||
PyObject *m_func;
|
||
};
|
||
|
||
/* Submit an event to the gdb thread. */
|
||
static PyObject *
|
||
gdbpy_post_event (PyObject *self, PyObject *args)
|
||
{
|
||
PyObject *func;
|
||
|
||
if (!PyArg_ParseTuple (args, "O", &func))
|
||
return NULL;
|
||
|
||
if (!PyCallable_Check (func))
|
||
{
|
||
PyErr_SetString (PyExc_RuntimeError,
|
||
_("Posted event is not callable"));
|
||
return NULL;
|
||
}
|
||
|
||
gdbpy_ref<> func_ref = gdbpy_ref<>::new_reference (func);
|
||
gdbpy_event event (std::move (func_ref));
|
||
run_on_main_thread (event);
|
||
|
||
Py_RETURN_NONE;
|
||
}
|
||
|
||
/* Interrupt the current operation on the main thread. */
|
||
static PyObject *
|
||
gdbpy_interrupt (PyObject *self, PyObject *args)
|
||
{
|
||
{
|
||
/* Make sure the interrupt isn't delivered immediately somehow.
|
||
This probably is not truly needed, but at the same time it
|
||
seems more clear to be explicit about the intent. */
|
||
gdbpy_allow_threads temporarily_exit_python;
|
||
scoped_disable_cooperative_sigint_handling no_python_sigint;
|
||
|
||
set_quit_flag ();
|
||
}
|
||
|
||
Py_RETURN_NONE;
|
||
}
|
||
|
||
|
||
|
||
/* This is the extension_language_ops.before_prompt "method". */
|
||
|
||
static enum ext_lang_rc
|
||
gdbpy_before_prompt_hook (const struct extension_language_defn *extlang,
|
||
const char *current_gdb_prompt)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return EXT_LANG_RC_NOP;
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
if (!evregpy_no_listeners_p (gdb_py_events.before_prompt)
|
||
&& evpy_emit_event (NULL, gdb_py_events.before_prompt) < 0)
|
||
return EXT_LANG_RC_ERROR;
|
||
|
||
if (gdb_python_module
|
||
&& PyObject_HasAttrString (gdb_python_module, "prompt_hook"))
|
||
{
|
||
gdbpy_ref<> hook (PyObject_GetAttrString (gdb_python_module,
|
||
"prompt_hook"));
|
||
if (hook == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
if (PyCallable_Check (hook.get ()))
|
||
{
|
||
gdbpy_ref<> current_prompt (PyUnicode_FromString (current_gdb_prompt));
|
||
if (current_prompt == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
gdbpy_ref<> result
|
||
(PyObject_CallFunctionObjArgs (hook.get (), current_prompt.get (),
|
||
NULL));
|
||
if (result == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
/* Return type should be None, or a String. If it is None,
|
||
fall through, we will not set a prompt. If it is a
|
||
string, set PROMPT. Anything else, set an exception. */
|
||
if (result != Py_None && !PyUnicode_Check (result.get ()))
|
||
{
|
||
PyErr_Format (PyExc_RuntimeError,
|
||
_("Return from prompt_hook must " \
|
||
"be either a Python string, or None"));
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
if (result != Py_None)
|
||
{
|
||
gdb::unique_xmalloc_ptr<char>
|
||
prompt (python_string_to_host_string (result.get ()));
|
||
|
||
if (prompt == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
set_prompt (prompt.get ());
|
||
return EXT_LANG_RC_OK;
|
||
}
|
||
}
|
||
}
|
||
|
||
return EXT_LANG_RC_NOP;
|
||
}
|
||
|
||
/* This is the extension_language_ops.colorize "method". */
|
||
|
||
static std::optional<std::string>
|
||
gdbpy_colorize (const std::string &filename, const std::string &contents)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return {};
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
gdbpy_ref<> module (PyImport_ImportModule ("gdb.styling"));
|
||
if (module == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
if (!PyObject_HasAttrString (module.get (), "colorize"))
|
||
return {};
|
||
|
||
gdbpy_ref<> hook (PyObject_GetAttrString (module.get (), "colorize"));
|
||
if (hook == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
if (!PyCallable_Check (hook.get ()))
|
||
return {};
|
||
|
||
gdbpy_ref<> fname_arg (PyUnicode_FromString (filename.c_str ()));
|
||
if (fname_arg == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* The pygments library, which is what we currently use for applying
|
||
styling, is happy to take input as a bytes object, and to figure out
|
||
the encoding for itself. This removes the need for us to figure out
|
||
(guess?) at how the content is encoded, which is probably a good
|
||
thing. */
|
||
gdbpy_ref<> contents_arg (PyBytes_FromStringAndSize (contents.c_str (),
|
||
contents.size ()));
|
||
if (contents_arg == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* Calling gdb.colorize passing in the filename (a string), and the file
|
||
contents (a bytes object). This function should return either a bytes
|
||
object, the same contents with styling applied, or None to indicate
|
||
that no styling should be performed. */
|
||
gdbpy_ref<> result (PyObject_CallFunctionObjArgs (hook.get (),
|
||
fname_arg.get (),
|
||
contents_arg.get (),
|
||
nullptr));
|
||
if (result == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
if (result == Py_None)
|
||
return {};
|
||
else if (!PyBytes_Check (result.get ()))
|
||
{
|
||
PyErr_SetString (PyExc_TypeError,
|
||
_("Return value from gdb.colorize should be a bytes object or None."));
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
return std::string (PyBytes_AsString (result.get ()));
|
||
}
|
||
|
||
/* This is the extension_language_ops.colorize_disasm "method". */
|
||
|
||
static std::optional<std::string>
|
||
gdbpy_colorize_disasm (const std::string &content, gdbarch *gdbarch)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return {};
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
gdbpy_ref<> module (PyImport_ImportModule ("gdb.styling"));
|
||
if (module == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
if (!PyObject_HasAttrString (module.get (), "colorize_disasm"))
|
||
return {};
|
||
|
||
gdbpy_ref<> hook (PyObject_GetAttrString (module.get (),
|
||
"colorize_disasm"));
|
||
if (hook == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
if (!PyCallable_Check (hook.get ()))
|
||
return {};
|
||
|
||
gdbpy_ref<> content_arg (PyBytes_FromString (content.c_str ()));
|
||
if (content_arg == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
gdbpy_ref<> gdbarch_arg (gdbarch_to_arch_object (gdbarch));
|
||
if (gdbarch_arg == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
gdbpy_ref<> result (PyObject_CallFunctionObjArgs (hook.get (),
|
||
content_arg.get (),
|
||
gdbarch_arg.get (),
|
||
nullptr));
|
||
if (result == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
if (result == Py_None)
|
||
return {};
|
||
|
||
if (!PyBytes_Check (result.get ()))
|
||
{
|
||
PyErr_SetString (PyExc_TypeError,
|
||
_("Return value from gdb.colorize_disasm should be a bytes object or None."));
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
return std::string (PyBytes_AsString (result.get ()));
|
||
}
|
||
|
||
|
||
|
||
/* Implement gdb.format_address(ADDR,P_SPACE,ARCH). Provide access to
|
||
GDB's print_address function from Python. The returned address will
|
||
have the format '0x..... <symbol+offset>'. */
|
||
|
||
static PyObject *
|
||
gdbpy_format_address (PyObject *self, PyObject *args, PyObject *kw)
|
||
{
|
||
static const char *keywords[] =
|
||
{
|
||
"address", "progspace", "architecture", nullptr
|
||
};
|
||
PyObject *addr_obj = nullptr, *pspace_obj = nullptr, *arch_obj = nullptr;
|
||
CORE_ADDR addr;
|
||
struct gdbarch *gdbarch = nullptr;
|
||
struct program_space *pspace = nullptr;
|
||
|
||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O|OO", keywords,
|
||
&addr_obj, &pspace_obj, &arch_obj))
|
||
return nullptr;
|
||
|
||
if (get_addr_from_python (addr_obj, &addr) < 0)
|
||
return nullptr;
|
||
|
||
/* If the user passed None for progspace or architecture, then we
|
||
consider this to mean "the default". Here we replace references to
|
||
None with nullptr, this means that in the following code we only have
|
||
to handle the nullptr case. These are only borrowed references, so
|
||
no decref is required here. */
|
||
if (pspace_obj == Py_None)
|
||
pspace_obj = nullptr;
|
||
if (arch_obj == Py_None)
|
||
arch_obj = nullptr;
|
||
|
||
if (pspace_obj == nullptr && arch_obj == nullptr)
|
||
{
|
||
/* Grab both of these from the current inferior, and its associated
|
||
default architecture. */
|
||
pspace = current_inferior ()->pspace;
|
||
gdbarch = current_inferior ()->arch ();
|
||
}
|
||
else if (arch_obj == nullptr || pspace_obj == nullptr)
|
||
{
|
||
/* If the user has only given one of program space or architecture,
|
||
then don't use the default for the other. Sure we could use the
|
||
default, but it feels like there's too much scope of mistakes in
|
||
this case, so better to require the user to provide both
|
||
arguments. */
|
||
PyErr_SetString (PyExc_ValueError,
|
||
_("The architecture and progspace arguments must both be supplied"));
|
||
return nullptr;
|
||
}
|
||
else
|
||
{
|
||
/* The user provided an address, program space, and architecture.
|
||
Just check that these objects are valid. */
|
||
if (!gdbpy_is_progspace (pspace_obj))
|
||
{
|
||
PyErr_SetString (PyExc_TypeError,
|
||
_("The progspace argument is not a gdb.Progspace object"));
|
||
return nullptr;
|
||
}
|
||
|
||
pspace = progspace_object_to_program_space (pspace_obj);
|
||
if (pspace == nullptr)
|
||
{
|
||
PyErr_SetString (PyExc_ValueError,
|
||
_("The progspace argument is not valid"));
|
||
return nullptr;
|
||
}
|
||
|
||
if (!gdbpy_is_architecture (arch_obj))
|
||
{
|
||
PyErr_SetString (PyExc_TypeError,
|
||
_("The architecture argument is not a gdb.Architecture object"));
|
||
return nullptr;
|
||
}
|
||
|
||
/* Architectures are never deleted once created, so gdbarch should
|
||
never come back as nullptr. */
|
||
gdbarch = arch_object_to_gdbarch (arch_obj);
|
||
gdb_assert (gdbarch != nullptr);
|
||
}
|
||
|
||
/* By this point we should know the program space and architecture we are
|
||
going to use. */
|
||
gdb_assert (pspace != nullptr);
|
||
gdb_assert (gdbarch != nullptr);
|
||
|
||
/* Unfortunately print_address relies on the current program space for
|
||
its symbol lookup. Temporarily switch now. */
|
||
scoped_restore_current_program_space restore_progspace;
|
||
set_current_program_space (pspace);
|
||
|
||
/* Format the address, and return it as a string. */
|
||
string_file buf;
|
||
print_address (gdbarch, addr, &buf);
|
||
return PyUnicode_FromString (buf.c_str ());
|
||
}
|
||
|
||
|
||
|
||
/* Printing. */
|
||
|
||
/* A python function to write a single string using gdb's filtered
|
||
output stream . The optional keyword STREAM can be used to write
|
||
to a particular stream. The default stream is to gdb_stdout. */
|
||
|
||
static PyObject *
|
||
gdbpy_write (PyObject *self, PyObject *args, PyObject *kw)
|
||
{
|
||
const char *arg;
|
||
static const char *keywords[] = { "text", "stream", NULL };
|
||
int stream_type = 0;
|
||
|
||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|i", keywords, &arg,
|
||
&stream_type))
|
||
return NULL;
|
||
|
||
try
|
||
{
|
||
switch (stream_type)
|
||
{
|
||
case 1:
|
||
{
|
||
gdb_printf (gdb_stderr, "%s", arg);
|
||
break;
|
||
}
|
||
case 2:
|
||
{
|
||
gdb_printf (gdb_stdlog, "%s", arg);
|
||
break;
|
||
}
|
||
default:
|
||
gdb_printf (gdb_stdout, "%s", arg);
|
||
}
|
||
}
|
||
catch (const gdb_exception &except)
|
||
{
|
||
return gdbpy_handle_gdb_exception (nullptr, except);
|
||
}
|
||
|
||
Py_RETURN_NONE;
|
||
}
|
||
|
||
/* A python function to flush a gdb stream. The optional keyword
|
||
STREAM can be used to flush a particular stream. The default stream
|
||
is gdb_stdout. */
|
||
|
||
static PyObject *
|
||
gdbpy_flush (PyObject *self, PyObject *args, PyObject *kw)
|
||
{
|
||
static const char *keywords[] = { "stream", NULL };
|
||
int stream_type = 0;
|
||
|
||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "|i", keywords,
|
||
&stream_type))
|
||
return NULL;
|
||
|
||
switch (stream_type)
|
||
{
|
||
case 1:
|
||
{
|
||
gdb_flush (gdb_stderr);
|
||
break;
|
||
}
|
||
case 2:
|
||
{
|
||
gdb_flush (gdb_stdlog);
|
||
break;
|
||
}
|
||
default:
|
||
gdb_flush (gdb_stdout);
|
||
}
|
||
|
||
Py_RETURN_NONE;
|
||
}
|
||
|
||
/* Return non-zero if print-stack is not "none". */
|
||
|
||
int
|
||
gdbpy_print_python_errors_p (void)
|
||
{
|
||
return gdbpy_should_print_stack != python_excp_none;
|
||
}
|
||
|
||
/* Print a python exception trace, print just a message, or print
|
||
nothing and clear the python exception, depending on
|
||
gdbpy_should_print_stack. Only call this if a python exception is
|
||
set. */
|
||
void
|
||
gdbpy_print_stack (void)
|
||
{
|
||
|
||
/* Print "none", just clear exception. */
|
||
if (gdbpy_should_print_stack == python_excp_none)
|
||
{
|
||
PyErr_Clear ();
|
||
}
|
||
/* Print "full" message and backtrace. */
|
||
else if (gdbpy_should_print_stack == python_excp_full)
|
||
{
|
||
PyErr_Print ();
|
||
/* PyErr_Print doesn't necessarily end output with a newline.
|
||
This works because Python's stdout/stderr is fed through
|
||
gdb_printf. */
|
||
try
|
||
{
|
||
begin_line ();
|
||
}
|
||
catch (const gdb_exception &except)
|
||
{
|
||
}
|
||
}
|
||
/* Print "message", just error print message. */
|
||
else
|
||
{
|
||
gdbpy_err_fetch fetched_error;
|
||
|
||
gdb::unique_xmalloc_ptr<char> msg = fetched_error.to_string ();
|
||
gdb::unique_xmalloc_ptr<char> type;
|
||
/* Don't compute TYPE if MSG already indicates that there is an
|
||
error. */
|
||
if (msg != NULL)
|
||
type = fetched_error.type_to_string ();
|
||
|
||
try
|
||
{
|
||
if (msg == NULL || type == NULL)
|
||
{
|
||
/* An error occurred computing the string representation of the
|
||
error message. */
|
||
gdb_printf (gdb_stderr,
|
||
_("Error occurred computing Python error "
|
||
"message.\n"));
|
||
PyErr_Clear ();
|
||
}
|
||
else
|
||
gdb_printf (gdb_stderr, "Python Exception %s: %s\n",
|
||
type.get (), msg.get ());
|
||
}
|
||
catch (const gdb_exception &except)
|
||
{
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Like gdbpy_print_stack, but if the exception is a
|
||
KeyboardException, throw a gdb "quit" instead. */
|
||
|
||
void
|
||
gdbpy_print_stack_or_quit ()
|
||
{
|
||
if (PyErr_ExceptionMatches (PyExc_KeyboardInterrupt))
|
||
{
|
||
PyErr_Clear ();
|
||
throw_quit ("Quit");
|
||
}
|
||
gdbpy_print_stack ();
|
||
}
|
||
|
||
|
||
|
||
/* Return a sequence holding all the Progspaces. */
|
||
|
||
static PyObject *
|
||
gdbpy_progspaces (PyObject *unused1, PyObject *unused2)
|
||
{
|
||
gdbpy_ref<> list (PyList_New (0));
|
||
if (list == NULL)
|
||
return NULL;
|
||
|
||
for (struct program_space *ps : program_spaces)
|
||
{
|
||
gdbpy_ref<> item = pspace_to_pspace_object (ps);
|
||
|
||
if (item == NULL || PyList_Append (list.get (), item.get ()) == -1)
|
||
return NULL;
|
||
}
|
||
|
||
return list.release ();
|
||
}
|
||
|
||
/* Return the name of the current language. */
|
||
|
||
static PyObject *
|
||
gdbpy_current_language (PyObject *unused1, PyObject *unused2)
|
||
{
|
||
return host_string_to_python_string (current_language->name ()).release ();
|
||
}
|
||
|
||
|
||
|
||
/* See python.h. */
|
||
struct objfile *gdbpy_current_objfile;
|
||
|
||
/* Set the current objfile to OBJFILE and then read FILE named FILENAME
|
||
as Python code. This does not throw any errors. If an exception
|
||
occurs python will print the traceback and clear the error indicator.
|
||
This is the extension_language_script_ops.objfile_script_sourcer
|
||
"method". */
|
||
|
||
static void
|
||
gdbpy_source_objfile_script (const struct extension_language_defn *extlang,
|
||
struct objfile *objfile, FILE *file,
|
||
const char *filename)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
gdbpy_enter enter_py (objfile->arch ());
|
||
scoped_restore restire_current_objfile
|
||
= make_scoped_restore (&gdbpy_current_objfile, objfile);
|
||
|
||
int result = python_run_simple_file (file, filename);
|
||
if (result != 0)
|
||
gdbpy_print_stack ();
|
||
}
|
||
|
||
/* Set the current objfile to OBJFILE and then execute SCRIPT
|
||
as Python code. This does not throw any errors. If an exception
|
||
occurs python will print the traceback and clear the error indicator.
|
||
This is the extension_language_script_ops.objfile_script_executor
|
||
"method". */
|
||
|
||
static void
|
||
gdbpy_execute_objfile_script (const struct extension_language_defn *extlang,
|
||
struct objfile *objfile, const char *name,
|
||
const char *script)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
gdbpy_enter enter_py (objfile->arch ());
|
||
scoped_restore restire_current_objfile
|
||
= make_scoped_restore (&gdbpy_current_objfile, objfile);
|
||
|
||
int ret = eval_python_command (script, Py_file_input);
|
||
if (ret != 0)
|
||
gdbpy_print_stack ();
|
||
}
|
||
|
||
/* Return the current Objfile, or None if there isn't one. */
|
||
|
||
static PyObject *
|
||
gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2)
|
||
{
|
||
if (! gdbpy_current_objfile)
|
||
Py_RETURN_NONE;
|
||
|
||
return objfile_to_objfile_object (gdbpy_current_objfile).release ();
|
||
}
|
||
|
||
/* Implement the 'handle_missing_debuginfo' hook for Python. GDB has
|
||
failed to find any debug information for OBJFILE. The extension has a
|
||
chance to record this, or even install the required debug information.
|
||
See the description of ext_lang_missing_file_result in extension-priv.h
|
||
for details of the return value. */
|
||
|
||
static ext_lang_missing_file_result
|
||
gdbpy_handle_missing_debuginfo (const struct extension_language_defn *extlang,
|
||
struct objfile *objfile)
|
||
{
|
||
/* Early exit if Python is not initialised. */
|
||
if (!gdb_python_initialized || gdb_python_module == nullptr)
|
||
return {};
|
||
|
||
struct gdbarch *gdbarch = objfile->arch ();
|
||
|
||
gdbpy_enter enter_py (gdbarch);
|
||
|
||
/* Convert OBJFILE into the corresponding Python object. */
|
||
gdbpy_ref<> pyo_objfile = objfile_to_objfile_object (objfile);
|
||
if (pyo_objfile == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* Lookup the helper function within the GDB module. */
|
||
gdbpy_ref<> pyo_handler
|
||
(PyObject_GetAttrString (gdb_python_module, "_handle_missing_debuginfo"));
|
||
if (pyo_handler == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* Call the function, passing in the Python objfile object. */
|
||
gdbpy_ref<> pyo_execute_ret
|
||
(PyObject_CallFunctionObjArgs (pyo_handler.get (), pyo_objfile.get (),
|
||
nullptr));
|
||
if (pyo_execute_ret == nullptr)
|
||
{
|
||
/* If the handler is cancelled due to a Ctrl-C, then propagate
|
||
the Ctrl-C as a GDB exception instead of swallowing it. */
|
||
gdbpy_print_stack_or_quit ();
|
||
return {};
|
||
}
|
||
|
||
/* Parse the result, and convert it back to the C++ object. */
|
||
if (pyo_execute_ret == Py_None)
|
||
return {};
|
||
|
||
if (PyBool_Check (pyo_execute_ret.get ()))
|
||
{
|
||
/* We know the value is a bool, so it must be either Py_True or
|
||
Py_False. Anything else would not get past the above check. */
|
||
bool try_again = pyo_execute_ret.get () == Py_True;
|
||
return ext_lang_missing_file_result (try_again);
|
||
}
|
||
|
||
if (!gdbpy_is_string (pyo_execute_ret.get ()))
|
||
{
|
||
PyErr_SetString (PyExc_ValueError,
|
||
"return value from _handle_missing_debuginfo should "
|
||
"be None, a Bool, or a String");
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
gdb::unique_xmalloc_ptr<char> filename
|
||
= python_string_to_host_string (pyo_execute_ret.get ());
|
||
if (filename == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
return ext_lang_missing_file_result (std::string (filename.get ()));
|
||
}
|
||
|
||
/* Implement the find_objfile_from_buildid hook for Python. PSPACE is the
|
||
program space in which GDB is trying to find an objfile, BUILD_ID is the
|
||
build-id for the missing objfile, and EXPECTED_FILENAME is a non-NULL
|
||
string which can be used (if needed) in messages to the user, and
|
||
represents the file GDB is looking for. */
|
||
|
||
static ext_lang_missing_file_result
|
||
gdbpy_find_objfile_from_buildid (const struct extension_language_defn *extlang,
|
||
program_space *pspace,
|
||
const struct bfd_build_id *build_id,
|
||
const char *missing_filename)
|
||
{
|
||
gdb_assert (pspace != nullptr);
|
||
gdb_assert (build_id != nullptr);
|
||
gdb_assert (missing_filename != nullptr);
|
||
|
||
/* Early exit if Python is not initialised. */
|
||
if (!gdb_python_initialized || gdb_python_module == nullptr)
|
||
return {};
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
/* Convert BUILD_ID into a Python object. */
|
||
std::string hex_form = bin2hex (build_id->data, build_id->size);
|
||
gdbpy_ref<> pyo_buildid = host_string_to_python_string (hex_form.c_str ());
|
||
if (pyo_buildid == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* Convert MISSING_FILENAME to a Python object. */
|
||
gdbpy_ref<> pyo_filename = host_string_to_python_string (missing_filename);
|
||
if (pyo_filename == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* Convert PSPACE to a Python object. */
|
||
gdbpy_ref<> pyo_pspace = pspace_to_pspace_object (pspace);
|
||
if (pyo_pspace == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* Lookup the helper function within the GDB module. */
|
||
gdbpy_ref<> pyo_handler
|
||
(PyObject_GetAttrString (gdb_python_module, "_handle_missing_objfile"));
|
||
if (pyo_handler == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
/* Call the function, passing in the Python objfile object. */
|
||
gdbpy_ref<> pyo_execute_ret
|
||
(PyObject_CallFunctionObjArgs (pyo_handler.get (), pyo_pspace.get (),
|
||
pyo_buildid.get (), pyo_filename.get (),
|
||
nullptr));
|
||
if (pyo_execute_ret == nullptr)
|
||
{
|
||
/* If the handler is cancelled due to a Ctrl-C, then propagate
|
||
the Ctrl-C as a GDB exception instead of swallowing it. */
|
||
gdbpy_print_stack_or_quit ();
|
||
return {};
|
||
}
|
||
|
||
/* Parse the result, and convert it back to the C++ object. */
|
||
if (pyo_execute_ret == Py_None)
|
||
return {};
|
||
|
||
if (PyBool_Check (pyo_execute_ret.get ()))
|
||
{
|
||
/* We know the value is a bool, so it must be either Py_True or
|
||
Py_False. Anything else would not get past the above check. */
|
||
bool try_again = pyo_execute_ret.get () == Py_True;
|
||
return ext_lang_missing_file_result (try_again);
|
||
}
|
||
|
||
if (!gdbpy_is_string (pyo_execute_ret.get ()))
|
||
{
|
||
PyErr_SetString (PyExc_ValueError,
|
||
"return value from _find_objfile_by_buildid should "
|
||
"be None, a bool, or a str");
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
gdb::unique_xmalloc_ptr<char> filename
|
||
= python_string_to_host_string (pyo_execute_ret.get ());
|
||
if (filename == nullptr)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return {};
|
||
}
|
||
|
||
return ext_lang_missing_file_result (std::string (filename.get ()));
|
||
}
|
||
|
||
/* Compute the list of active python type printers and store them in
|
||
EXT_PRINTERS->py_type_printers. The product of this function is used by
|
||
gdbpy_apply_type_printers, and freed by gdbpy_free_type_printers.
|
||
This is the extension_language_ops.start_type_printers "method". */
|
||
|
||
static void
|
||
gdbpy_start_type_printers (const struct extension_language_defn *extlang,
|
||
struct ext_lang_type_printers *ext_printers)
|
||
{
|
||
PyObject *printers_obj = NULL;
|
||
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
gdbpy_ref<> type_module (PyImport_ImportModule ("gdb.types"));
|
||
if (type_module == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return;
|
||
}
|
||
|
||
gdbpy_ref<> func (PyObject_GetAttrString (type_module.get (),
|
||
"get_type_recognizers"));
|
||
if (func == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return;
|
||
}
|
||
|
||
printers_obj = PyObject_CallFunctionObjArgs (func.get (), (char *) NULL);
|
||
if (printers_obj == NULL)
|
||
gdbpy_print_stack ();
|
||
else
|
||
ext_printers->py_type_printers = printers_obj;
|
||
}
|
||
|
||
/* If TYPE is recognized by some type printer, store in *PRETTIED_TYPE
|
||
a newly allocated string holding the type's replacement name, and return
|
||
EXT_LANG_RC_OK.
|
||
If there's a Python error return EXT_LANG_RC_ERROR.
|
||
Otherwise, return EXT_LANG_RC_NOP.
|
||
This is the extension_language_ops.apply_type_printers "method". */
|
||
|
||
static enum ext_lang_rc
|
||
gdbpy_apply_type_printers (const struct extension_language_defn *extlang,
|
||
const struct ext_lang_type_printers *ext_printers,
|
||
struct type *type,
|
||
gdb::unique_xmalloc_ptr<char> *prettied_type)
|
||
{
|
||
PyObject *printers_obj = (PyObject *) ext_printers->py_type_printers;
|
||
gdb::unique_xmalloc_ptr<char> result;
|
||
|
||
if (printers_obj == NULL)
|
||
return EXT_LANG_RC_NOP;
|
||
|
||
if (!gdb_python_initialized)
|
||
return EXT_LANG_RC_NOP;
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
gdbpy_ref<> type_obj (type_to_type_object (type));
|
||
if (type_obj == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
gdbpy_ref<> type_module (PyImport_ImportModule ("gdb.types"));
|
||
if (type_module == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
gdbpy_ref<> func (PyObject_GetAttrString (type_module.get (),
|
||
"apply_type_recognizers"));
|
||
if (func == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
gdbpy_ref<> result_obj (PyObject_CallFunctionObjArgs (func.get (),
|
||
printers_obj,
|
||
type_obj.get (),
|
||
(char *) NULL));
|
||
if (result_obj == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
if (result_obj == Py_None)
|
||
return EXT_LANG_RC_NOP;
|
||
|
||
result = python_string_to_host_string (result_obj.get ());
|
||
if (result == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
return EXT_LANG_RC_ERROR;
|
||
}
|
||
|
||
*prettied_type = std::move (result);
|
||
return EXT_LANG_RC_OK;
|
||
}
|
||
|
||
/* Free the result of start_type_printers.
|
||
This is the extension_language_ops.free_type_printers "method". */
|
||
|
||
static void
|
||
gdbpy_free_type_printers (const struct extension_language_defn *extlang,
|
||
struct ext_lang_type_printers *ext_printers)
|
||
{
|
||
PyObject *printers = (PyObject *) ext_printers->py_type_printers;
|
||
|
||
if (printers == NULL)
|
||
return;
|
||
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
gdbpy_enter enter_py;
|
||
Py_DECREF (printers);
|
||
}
|
||
|
||
#else /* HAVE_PYTHON */
|
||
|
||
/* Dummy implementation of the gdb "python-interactive" and "python"
|
||
command. */
|
||
|
||
static void
|
||
python_interactive_command (const char *arg, int from_tty)
|
||
{
|
||
arg = skip_spaces (arg);
|
||
if (arg && *arg)
|
||
error (_("Python scripting is not supported in this copy of GDB."));
|
||
else
|
||
{
|
||
counted_command_line l = get_command_line (python_control, "");
|
||
|
||
execute_control_command_untraced (l.get ());
|
||
}
|
||
}
|
||
|
||
static void
|
||
python_command (const char *arg, int from_tty)
|
||
{
|
||
python_interactive_command (arg, from_tty);
|
||
}
|
||
|
||
#endif /* HAVE_PYTHON */
|
||
|
||
/* When this is turned on before Python is initialised then Python will
|
||
ignore any environment variables related to Python. This is equivalent
|
||
to passing `-E' to the python program. */
|
||
static bool python_ignore_environment = false;
|
||
|
||
/* Implement 'show python ignore-environment'. */
|
||
|
||
static void
|
||
show_python_ignore_environment (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
gdb_printf (file, _("Python's ignore-environment setting is %s.\n"),
|
||
value);
|
||
}
|
||
|
||
/* Implement 'set python ignore-environment'. This sets Python's internal
|
||
flag no matter when the command is issued, however, if this is used
|
||
after Py_Initialize has been called then most of the environment will
|
||
already have been read. */
|
||
|
||
static void
|
||
set_python_ignore_environment (const char *args, int from_tty,
|
||
struct cmd_list_element *c)
|
||
{
|
||
#ifdef HAVE_PYTHON
|
||
/* Py_IgnoreEnvironmentFlag is deprecated in Python 3.12. Disable
|
||
its usage in Python 3.10 and above since the PyConfig mechanism
|
||
is now (also) used in 3.10 and higher. See do_start_initialization()
|
||
in this file. */
|
||
#if PY_VERSION_HEX < 0x030a0000
|
||
Py_IgnoreEnvironmentFlag = python_ignore_environment ? 1 : 0;
|
||
#endif
|
||
#endif
|
||
}
|
||
|
||
/* When this is turned on before Python is initialised then Python will
|
||
not write `.pyc' files on import of a module. */
|
||
static enum auto_boolean python_dont_write_bytecode = AUTO_BOOLEAN_AUTO;
|
||
|
||
/* Implement 'show python dont-write-bytecode'. */
|
||
|
||
static void
|
||
show_python_dont_write_bytecode (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
if (python_dont_write_bytecode == AUTO_BOOLEAN_AUTO)
|
||
{
|
||
const char *auto_string
|
||
= (python_ignore_environment
|
||
|| getenv ("PYTHONDONTWRITEBYTECODE") == nullptr) ? "off" : "on";
|
||
|
||
gdb_printf (file,
|
||
_("Python's dont-write-bytecode setting is %s (currently %s).\n"),
|
||
value, auto_string);
|
||
}
|
||
else
|
||
gdb_printf (file, _("Python's dont-write-bytecode setting is %s.\n"),
|
||
value);
|
||
}
|
||
|
||
#ifdef HAVE_PYTHON
|
||
/* Return value to assign to PyConfig.write_bytecode or, when
|
||
negated (via !), Py_DontWriteBytecodeFlag. Py_DontWriteBytecodeFlag
|
||
is deprecated in Python 3.12. */
|
||
|
||
static int
|
||
python_write_bytecode ()
|
||
{
|
||
int wbc = 0;
|
||
|
||
if (python_dont_write_bytecode == AUTO_BOOLEAN_AUTO)
|
||
{
|
||
if (python_ignore_environment)
|
||
wbc = 1;
|
||
else
|
||
{
|
||
const char *pdwbc = getenv ("PYTHONDONTWRITEBYTECODE");
|
||
wbc = (pdwbc == nullptr || pdwbc[0] == '\0') ? 1 : 0;
|
||
}
|
||
}
|
||
else
|
||
wbc = python_dont_write_bytecode == AUTO_BOOLEAN_TRUE ? 0 : 1;
|
||
|
||
return wbc;
|
||
}
|
||
#endif /* HAVE_PYTHON */
|
||
|
||
/* Implement 'set python dont-write-bytecode'. This sets Python's internal
|
||
flag no matter when the command is issued, however, if this is used
|
||
after Py_Initialize has been called then many modules could already
|
||
have been imported and their byte code written out. */
|
||
|
||
static void
|
||
set_python_dont_write_bytecode (const char *args, int from_tty,
|
||
struct cmd_list_element *c)
|
||
{
|
||
#ifdef HAVE_PYTHON
|
||
/* Py_DontWriteBytecodeFlag is deprecated in Python 3.12. Disable
|
||
its usage in Python 3.10 and above since the PyConfig mechanism
|
||
is now (also) used in 3.10 and higher. See do_start_initialization()
|
||
in this file. */
|
||
#if PY_VERSION_HEX < 0x030a0000
|
||
Py_DontWriteBytecodeFlag = !python_write_bytecode ();
|
||
#endif
|
||
#endif /* HAVE_PYTHON */
|
||
}
|
||
|
||
|
||
|
||
/* Lists for 'set python' commands. */
|
||
|
||
static struct cmd_list_element *user_set_python_list;
|
||
static struct cmd_list_element *user_show_python_list;
|
||
|
||
/* Initialize the Python code. */
|
||
|
||
#ifdef HAVE_PYTHON
|
||
|
||
/* This is installed as a final cleanup and cleans up the
|
||
interpreter. This lets Python's 'atexit' work. */
|
||
|
||
static void
|
||
finalize_python (const struct extension_language_defn *ignore)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
struct active_ext_lang_state *previous_active;
|
||
|
||
/* We don't use ensure_python_env here because if we ever ran the
|
||
cleanup, gdb would crash -- because the cleanup calls into the
|
||
Python interpreter, which we are about to destroy. It seems
|
||
clearer to make the needed calls explicitly here than to create a
|
||
cleanup and then mysteriously discard it. */
|
||
|
||
/* This is only called as a final cleanup so we can assume the active
|
||
SIGINT handler is gdb's. We still need to tell it to notify Python. */
|
||
previous_active = set_active_ext_lang (&extension_language_python);
|
||
|
||
(void) PyGILState_Ensure ();
|
||
gdbpy_enter::finalize ();
|
||
|
||
/* Call the gdbpy_finalize_* functions from every *.c file. */
|
||
gdbpy_initialize_file::finalize_all ();
|
||
|
||
Py_Finalize ();
|
||
|
||
gdb_python_initialized = false;
|
||
restore_active_ext_lang (previous_active);
|
||
}
|
||
|
||
static struct PyModuleDef python_GdbModuleDef =
|
||
{
|
||
PyModuleDef_HEAD_INIT,
|
||
"_gdb",
|
||
NULL,
|
||
-1,
|
||
python_GdbMethods,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL
|
||
};
|
||
|
||
/* This is called via the PyImport_AppendInittab mechanism called
|
||
during initialization, to make the built-in _gdb module known to
|
||
Python. */
|
||
PyMODINIT_FUNC init__gdb_module (void);
|
||
PyMODINIT_FUNC
|
||
init__gdb_module (void)
|
||
{
|
||
return PyModule_Create (&python_GdbModuleDef);
|
||
}
|
||
|
||
/* Emit a gdb.GdbExitingEvent, return a negative value if there are any
|
||
errors, otherwise, return 0. */
|
||
|
||
static int
|
||
emit_exiting_event (int exit_code)
|
||
{
|
||
if (evregpy_no_listeners_p (gdb_py_events.gdb_exiting))
|
||
return 0;
|
||
|
||
gdbpy_ref<> event_obj = create_event_object (&gdb_exiting_event_object_type);
|
||
if (event_obj == nullptr)
|
||
return -1;
|
||
|
||
gdbpy_ref<> code = gdb_py_object_from_longest (exit_code);
|
||
if (evpy_add_attribute (event_obj.get (), "exit_code", code.get ()) < 0)
|
||
return -1;
|
||
|
||
return evpy_emit_event (event_obj.get (), gdb_py_events.gdb_exiting);
|
||
}
|
||
|
||
/* Callback for the gdb_exiting observable. EXIT_CODE is the value GDB
|
||
will exit with. */
|
||
|
||
static void
|
||
gdbpy_gdb_exiting (int exit_code)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
if (emit_exiting_event (exit_code) < 0)
|
||
gdbpy_print_stack ();
|
||
}
|
||
|
||
/* Signal handler to convert a SIGABRT into an exception. */
|
||
|
||
static void
|
||
catch_python_fatal (int signum)
|
||
{
|
||
signal (SIGABRT, catch_python_fatal);
|
||
|
||
throw_exception_sjlj (gdb_exception {RETURN_ERROR, GENERIC_ERROR});
|
||
}
|
||
|
||
/* Stand-in for Py_IsInitialized (). To be used because after a python fatal
|
||
error, no calls into Python are allowed. */
|
||
|
||
static bool py_isinitialized = false;
|
||
|
||
/* Call Py_Initialize (), and return true if successful. */
|
||
|
||
static bool ATTRIBUTE_UNUSED
|
||
py_initialize ()
|
||
{
|
||
auto prev_handler = signal (SIGABRT, catch_python_fatal);
|
||
SCOPE_EXIT { signal (SIGABRT, prev_handler); };
|
||
|
||
TRY_SJLJ
|
||
{
|
||
Py_Initialize ();
|
||
py_isinitialized = true;
|
||
}
|
||
CATCH_SJLJ (e, RETURN_MASK_ERROR)
|
||
{
|
||
}
|
||
END_CATCH_SJLJ;
|
||
|
||
return py_isinitialized;
|
||
}
|
||
|
||
static bool
|
||
do_start_initialization ()
|
||
{
|
||
/* Define all internal modules. These are all imported (and thus
|
||
created) during initialization. */
|
||
struct _inittab mods[] =
|
||
{
|
||
{ "_gdb", init__gdb_module },
|
||
{ "_gdbevents", gdbpy_events_mod_func },
|
||
{ nullptr, nullptr }
|
||
};
|
||
|
||
if (PyImport_ExtendInittab (mods) < 0)
|
||
return false;
|
||
|
||
#ifdef WITH_PYTHON_PATH
|
||
/* Work around problem where python gets confused about where it is,
|
||
and then can't find its libraries, etc.
|
||
NOTE: Python assumes the following layout:
|
||
/foo/bin/python
|
||
/foo/lib/pythonX.Y/...
|
||
This must be done before calling Py_Initialize. */
|
||
gdb::unique_xmalloc_ptr<char> progname
|
||
(concat (ldirname (python_libdir.c_str ()).c_str (), SLASH_STRING, "bin",
|
||
SLASH_STRING, "python", (char *) NULL));
|
||
/* Python documentation indicates that the memory given
|
||
to Py_SetProgramName cannot be freed. However, it seems that
|
||
at least Python 3.7.4 Py_SetProgramName takes a copy of the
|
||
given program_name. Making progname_copy static and not release
|
||
the memory avoids a leak report for Python versions that duplicate
|
||
program_name, and respect the requirement of Py_SetProgramName
|
||
for Python versions that do not duplicate program_name. */
|
||
static wchar_t *progname_copy;
|
||
|
||
{
|
||
std::string oldloc = setlocale (LC_ALL, NULL);
|
||
SCOPE_EXIT { setlocale (LC_ALL, oldloc.c_str ()); };
|
||
|
||
setlocale (LC_ALL, "");
|
||
size_t progsize = strlen (progname.get ());
|
||
progname_copy = XNEWVEC (wchar_t, progsize + 1);
|
||
size_t count = mbstowcs (progname_copy, progname.get (), progsize + 1);
|
||
if (count == (size_t) -1)
|
||
{
|
||
fprintf (stderr, "Could not convert python path to string\n");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/* Py_SetProgramName was deprecated in Python 3.11. Use PyConfig
|
||
mechanisms for Python 3.10 and newer. */
|
||
#if PY_VERSION_HEX < 0x030a0000
|
||
/* Note that Py_SetProgramName expects the string it is passed to
|
||
remain alive for the duration of the program's execution, so
|
||
it is not freed after this call. */
|
||
Py_SetProgramName (progname_copy);
|
||
if (!py_initialize ())
|
||
return false;
|
||
#else
|
||
PyConfig config;
|
||
|
||
PyConfig_InitPythonConfig (&config);
|
||
PyStatus status = PyConfig_SetString (&config, &config.program_name,
|
||
progname_copy);
|
||
if (PyStatus_Exception (status))
|
||
goto init_done;
|
||
|
||
config.write_bytecode = python_write_bytecode ();
|
||
config.use_environment = !python_ignore_environment;
|
||
|
||
status = PyConfig_Read (&config);
|
||
if (PyStatus_Exception (status))
|
||
goto init_done;
|
||
|
||
status = Py_InitializeFromConfig (&config);
|
||
|
||
init_done:
|
||
PyConfig_Clear (&config);
|
||
if (PyStatus_Exception (status))
|
||
{
|
||
if (PyStatus_IsError (status))
|
||
gdb_printf (_("Python initialization failed: %s\n"), status.err_msg);
|
||
else
|
||
gdb_printf (_("Python initialization failed with exit status: %d\n"),
|
||
status.exitcode);
|
||
return false;
|
||
}
|
||
py_isinitialized = true;
|
||
#endif
|
||
#else
|
||
if (!py_initialize ())
|
||
return false;
|
||
#endif
|
||
|
||
#if PY_VERSION_HEX < 0x03090000
|
||
/* PyEval_InitThreads became deprecated in Python 3.9 and will
|
||
be removed in Python 3.11. Prior to Python 3.7, this call was
|
||
required to initialize the GIL. */
|
||
PyEval_InitThreads ();
|
||
#endif
|
||
|
||
gdb_module = PyImport_ImportModule ("_gdb");
|
||
if (gdb_module == NULL)
|
||
return false;
|
||
|
||
if (PyModule_AddStringConstant (gdb_module, "VERSION", version) < 0
|
||
|| PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", host_name) < 0
|
||
|| PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG",
|
||
target_name) < 0)
|
||
return false;
|
||
|
||
/* Add stream constants. */
|
||
if (PyModule_AddIntConstant (gdb_module, "STDOUT", 0) < 0
|
||
|| PyModule_AddIntConstant (gdb_module, "STDERR", 1) < 0
|
||
|| PyModule_AddIntConstant (gdb_module, "STDLOG", 2) < 0)
|
||
return false;
|
||
|
||
gdbpy_gdb_error = PyErr_NewException ("gdb.error", PyExc_RuntimeError, NULL);
|
||
if (gdbpy_gdb_error == NULL
|
||
|| gdb_pymodule_addobject (gdb_module, "error", gdbpy_gdb_error) < 0)
|
||
return false;
|
||
|
||
gdbpy_gdb_memory_error = PyErr_NewException ("gdb.MemoryError",
|
||
gdbpy_gdb_error, NULL);
|
||
if (gdbpy_gdb_memory_error == NULL
|
||
|| gdb_pymodule_addobject (gdb_module, "MemoryError",
|
||
gdbpy_gdb_memory_error) < 0)
|
||
return false;
|
||
|
||
gdbpy_gdberror_exc = PyErr_NewException ("gdb.GdbError", NULL, NULL);
|
||
if (gdbpy_gdberror_exc == NULL
|
||
|| gdb_pymodule_addobject (gdb_module, "GdbError",
|
||
gdbpy_gdberror_exc) < 0)
|
||
return false;
|
||
|
||
/* Call the gdbpy_initialize_* functions from every *.c file. */
|
||
if (!gdbpy_initialize_file::initialize_all ())
|
||
return false;
|
||
|
||
#define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \
|
||
if (gdbpy_type_ready (&name##_event_object_type) < 0) \
|
||
return false;
|
||
#include "py-event-types.def"
|
||
#undef GDB_PY_DEFINE_EVENT_TYPE
|
||
|
||
gdbpy_to_string_cst = PyUnicode_FromString ("to_string");
|
||
if (gdbpy_to_string_cst == NULL)
|
||
return false;
|
||
gdbpy_children_cst = PyUnicode_FromString ("children");
|
||
if (gdbpy_children_cst == NULL)
|
||
return false;
|
||
gdbpy_display_hint_cst = PyUnicode_FromString ("display_hint");
|
||
if (gdbpy_display_hint_cst == NULL)
|
||
return false;
|
||
gdbpy_doc_cst = PyUnicode_FromString ("__doc__");
|
||
if (gdbpy_doc_cst == NULL)
|
||
return false;
|
||
gdbpy_enabled_cst = PyUnicode_FromString ("enabled");
|
||
if (gdbpy_enabled_cst == NULL)
|
||
return false;
|
||
gdbpy_value_cst = PyUnicode_FromString ("value");
|
||
if (gdbpy_value_cst == NULL)
|
||
return false;
|
||
|
||
gdb::observers::gdb_exiting.attach (gdbpy_gdb_exiting, "python");
|
||
|
||
/* Release the GIL while gdb runs. */
|
||
PyEval_SaveThread ();
|
||
|
||
/* Only set this when initialization has succeeded. */
|
||
gdb_python_initialized = 1;
|
||
return true;
|
||
}
|
||
|
||
#if GDB_SELF_TEST
|
||
namespace selftests {
|
||
|
||
/* Entry point for python unit tests. */
|
||
|
||
static void
|
||
test_python ()
|
||
{
|
||
#define CMD(S) execute_command_to_string (S, "python print(5)", 0, true)
|
||
|
||
std::string output;
|
||
|
||
CMD (output);
|
||
SELF_CHECK (output == "5\n");
|
||
output.clear ();
|
||
|
||
bool saw_exception = false;
|
||
{
|
||
scoped_restore reset_gdb_python_initialized
|
||
= make_scoped_restore (&gdb_python_initialized, 0);
|
||
try
|
||
{
|
||
CMD (output);
|
||
}
|
||
catch (const gdb_exception &e)
|
||
{
|
||
saw_exception = true;
|
||
SELF_CHECK (e.reason == RETURN_ERROR);
|
||
SELF_CHECK (e.error == GENERIC_ERROR);
|
||
SELF_CHECK (*e.message == "Python not initialized");
|
||
}
|
||
SELF_CHECK (saw_exception);
|
||
SELF_CHECK (output.empty ());
|
||
}
|
||
|
||
saw_exception = false;
|
||
{
|
||
scoped_restore save_hook
|
||
= make_scoped_restore (&hook_set_active_ext_lang,
|
||
[]() { raise (SIGINT); });
|
||
try
|
||
{
|
||
CMD (output);
|
||
}
|
||
catch (const gdb_exception_quit &e)
|
||
{
|
||
saw_exception = true;
|
||
SELF_CHECK (e.reason == RETURN_QUIT);
|
||
SELF_CHECK (e.error == GDB_NO_ERROR);
|
||
SELF_CHECK (*e.message == "Quit");
|
||
}
|
||
SELF_CHECK (saw_exception);
|
||
SELF_CHECK (output.empty ());
|
||
}
|
||
|
||
#undef CMD
|
||
}
|
||
|
||
#undef CHECK_OUTPUT
|
||
|
||
} // namespace selftests
|
||
#endif /* GDB_SELF_TEST */
|
||
|
||
#endif /* HAVE_PYTHON */
|
||
|
||
/* See python.h. */
|
||
cmd_list_element *python_cmd_element = nullptr;
|
||
|
||
void _initialize_python ();
|
||
void
|
||
_initialize_python ()
|
||
{
|
||
cmd_list_element *python_interactive_cmd
|
||
= add_com ("python-interactive", class_obscure,
|
||
python_interactive_command,
|
||
#ifdef HAVE_PYTHON
|
||
_("\
|
||
Start an interactive Python prompt.\n\
|
||
\n\
|
||
To return to GDB, type the EOF character (e.g., Ctrl-D on an empty\n\
|
||
prompt).\n\
|
||
\n\
|
||
Alternatively, a single-line Python command can be given as an\n\
|
||
argument, and if the command is an expression, the result will be\n\
|
||
printed. For example:\n\
|
||
\n\
|
||
(gdb) python-interactive 2 + 3\n\
|
||
5")
|
||
#else /* HAVE_PYTHON */
|
||
_("\
|
||
Start a Python interactive prompt.\n\
|
||
\n\
|
||
Python scripting is not supported in this copy of GDB.\n\
|
||
This command is only a placeholder.")
|
||
#endif /* HAVE_PYTHON */
|
||
);
|
||
add_com_alias ("pi", python_interactive_cmd, class_obscure, 1);
|
||
|
||
python_cmd_element = add_com ("python", class_obscure, python_command,
|
||
#ifdef HAVE_PYTHON
|
||
_("\
|
||
Evaluate a Python command.\n\
|
||
\n\
|
||
The command can be given as an argument, for instance:\n\
|
||
\n\
|
||
python print (23)\n\
|
||
\n\
|
||
If no argument is given, the following lines are read and used\n\
|
||
as the Python commands. Type a line containing \"end\" to indicate\n\
|
||
the end of the command.")
|
||
#else /* HAVE_PYTHON */
|
||
_("\
|
||
Evaluate a Python command.\n\
|
||
\n\
|
||
Python scripting is not supported in this copy of GDB.\n\
|
||
This command is only a placeholder.")
|
||
#endif /* HAVE_PYTHON */
|
||
);
|
||
add_com_alias ("py", python_cmd_element, class_obscure, 1);
|
||
|
||
/* Add set/show python print-stack. */
|
||
add_setshow_prefix_cmd ("python", no_class,
|
||
_("Prefix command for python preference settings."),
|
||
_("Prefix command for python preference settings."),
|
||
&user_set_python_list, &user_show_python_list,
|
||
&setlist, &showlist);
|
||
|
||
add_setshow_enum_cmd ("print-stack", no_class, python_excp_enums,
|
||
&gdbpy_should_print_stack, _("\
|
||
Set mode for Python stack dump on error."), _("\
|
||
Show the mode of Python stack printing on error."), _("\
|
||
none == no stack or message will be printed.\n\
|
||
full == a message and a stack will be printed.\n\
|
||
message == an error message without a stack will be printed."),
|
||
NULL, NULL,
|
||
&user_set_python_list,
|
||
&user_show_python_list);
|
||
|
||
add_setshow_boolean_cmd ("ignore-environment", no_class,
|
||
&python_ignore_environment, _("\
|
||
Set whether the Python interpreter should ignore environment variables."), _("\
|
||
Show whether the Python interpreter showlist ignore environment variables."), _("\
|
||
When enabled GDB's Python interpreter will ignore any Python related\n\
|
||
flags in the environment. This is equivalent to passing `-E' to a\n\
|
||
python executable."),
|
||
set_python_ignore_environment,
|
||
show_python_ignore_environment,
|
||
&user_set_python_list,
|
||
&user_show_python_list);
|
||
|
||
add_setshow_auto_boolean_cmd ("dont-write-bytecode", no_class,
|
||
&python_dont_write_bytecode, _("\
|
||
Set whether the Python interpreter should avoid byte-compiling python modules."), _("\
|
||
Show whether the Python interpreter should avoid byte-compiling python modules."), _("\
|
||
When enabled, GDB's embedded Python interpreter won't byte-compile python\n\
|
||
modules. In order to take effect, this setting must be enabled in an early\n\
|
||
initialization file, i.e. those run via the --early-init-eval-command or\n\
|
||
-eix command line options. A 'set python dont-write-bytecode on' command\n\
|
||
can also be issued directly from the GDB command line via the\n\
|
||
--early-init-eval-command or -eiex command line options.\n\
|
||
\n\
|
||
This setting defaults to 'auto'. In this mode, provided the 'python\n\
|
||
ignore-environment' setting is 'off', the environment variable\n\
|
||
PYTHONDONTWRITEBYTECODE is examined to determine whether or not to\n\
|
||
byte-compile python modules. PYTHONDONTWRITEBYTECODE is considered to be\n\
|
||
off/disabled either when set to the empty string or when the\n\
|
||
environment variable doesn't exist. All other settings, including those\n\
|
||
which don't seem to make sense, indicate that it's on/enabled."),
|
||
set_python_dont_write_bytecode,
|
||
show_python_dont_write_bytecode,
|
||
&user_set_python_list,
|
||
&user_show_python_list);
|
||
|
||
#ifdef HAVE_PYTHON
|
||
#if GDB_SELF_TEST
|
||
selftests::register_test ("python", selftests::test_python);
|
||
#endif /* GDB_SELF_TEST */
|
||
#endif /* HAVE_PYTHON */
|
||
}
|
||
|
||
#ifdef HAVE_PYTHON
|
||
|
||
/* Helper function for gdbpy_initialize. This does the work and then
|
||
returns false if an error has occurred and must be displayed, or true on
|
||
success. */
|
||
|
||
static bool
|
||
do_initialize (const struct extension_language_defn *extlang)
|
||
{
|
||
PyObject *m;
|
||
PyObject *sys_path;
|
||
|
||
/* Add the initial data-directory to sys.path. */
|
||
|
||
std::string gdb_pythondir = (std::string (gdb_datadir) + SLASH_STRING
|
||
+ "python");
|
||
|
||
sys_path = PySys_GetObject ("path");
|
||
|
||
/* PySys_SetPath was deprecated in Python 3.11. Disable this
|
||
deprecated code for Python 3.10 and newer. Also note that this
|
||
ifdef eliminates potential initialization of sys.path via
|
||
PySys_SetPath. My (kevinb's) understanding of PEP 587 suggests
|
||
that it's not necessary due to module_search_paths being
|
||
initialized to an empty list following any of the PyConfig
|
||
initialization functions. If it does turn out that some kind of
|
||
initialization is still needed, it should be added to the
|
||
PyConfig-based initialization in do_start_initialize(). */
|
||
#if PY_VERSION_HEX < 0x030a0000
|
||
/* If sys.path is not defined yet, define it first. */
|
||
if (!(sys_path && PyList_Check (sys_path)))
|
||
{
|
||
PySys_SetPath (L"");
|
||
sys_path = PySys_GetObject ("path");
|
||
}
|
||
#endif
|
||
if (sys_path && PyList_Check (sys_path))
|
||
{
|
||
gdbpy_ref<> pythondir (PyUnicode_FromString (gdb_pythondir.c_str ()));
|
||
if (pythondir == NULL || PyList_Insert (sys_path, 0, pythondir.get ()))
|
||
return false;
|
||
}
|
||
else
|
||
return false;
|
||
|
||
/* Import the gdb module to finish the initialization, and
|
||
add it to __main__ for convenience. */
|
||
m = PyImport_AddModule ("__main__");
|
||
if (m == NULL)
|
||
return false;
|
||
|
||
/* Keep the reference to gdb_python_module since it is in a global
|
||
variable. */
|
||
gdb_python_module = PyImport_ImportModule ("gdb");
|
||
if (gdb_python_module == NULL)
|
||
{
|
||
gdbpy_print_stack ();
|
||
/* This is passed in one call to warning so that blank lines aren't
|
||
inserted between each line of text. */
|
||
warning (_("\n"
|
||
"Could not load the Python gdb module from `%s'.\n"
|
||
"Limited Python support is available from the _gdb module.\n"
|
||
"Suggest passing --data-directory=/path/to/gdb/data-directory."),
|
||
gdb_pythondir.c_str ());
|
||
/* We return "success" here as we've already emitted the
|
||
warning. */
|
||
return true;
|
||
}
|
||
|
||
return gdb_pymodule_addobject (m, "gdb", gdb_python_module) >= 0;
|
||
}
|
||
|
||
/* Perform Python initialization. This will be called after GDB has
|
||
performed all of its own initialization. This is the
|
||
extension_language_ops.initialize "method". */
|
||
|
||
static void
|
||
gdbpy_initialize (const struct extension_language_defn *extlang)
|
||
{
|
||
if (!do_start_initialization ())
|
||
{
|
||
if (py_isinitialized)
|
||
{
|
||
if (PyErr_Occurred ())
|
||
gdbpy_print_stack ();
|
||
|
||
/* We got no use for the Python interpreter anymore. Finalize it
|
||
ASAP. */
|
||
Py_Finalize ();
|
||
}
|
||
|
||
/* Continue with python disabled. */
|
||
return;
|
||
}
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
if (!do_initialize (extlang))
|
||
{
|
||
gdbpy_print_stack ();
|
||
warning (_("internal error: Unhandled Python exception"));
|
||
}
|
||
}
|
||
|
||
/* Return non-zero if Python has successfully initialized.
|
||
This is the extension_languages_ops.initialized "method". */
|
||
|
||
static int
|
||
gdbpy_initialized (const struct extension_language_defn *extlang)
|
||
{
|
||
return gdb_python_initialized;
|
||
}
|
||
|
||
PyMethodDef python_GdbMethods[] =
|
||
{
|
||
{ "history", gdbpy_history, METH_VARARGS,
|
||
"Get a value from history" },
|
||
{ "add_history", gdbpy_add_history, METH_VARARGS,
|
||
"Add a value to the value history list" },
|
||
{ "history_count", gdbpy_history_count, METH_NOARGS,
|
||
"Return an integer, the number of values in GDB's value history" },
|
||
{ "execute", (PyCFunction) execute_gdb_command, METH_VARARGS | METH_KEYWORDS,
|
||
"execute (command [, from_tty] [, to_string]) -> [String]\n\
|
||
Evaluate command, a string, as a gdb CLI command. Optionally returns\n\
|
||
a Python String containing the output of the command if to_string is\n\
|
||
set to True." },
|
||
{ "execute_mi", (PyCFunction) gdbpy_execute_mi_command,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"execute_mi (command, arg...) -> dictionary\n\
|
||
Evaluate command, a string, as a gdb MI command.\n\
|
||
Arguments (also strings) are passed to the command." },
|
||
{ "parameter", gdbpy_parameter, METH_VARARGS,
|
||
"Return a gdb parameter's value" },
|
||
|
||
{ "breakpoints", gdbpy_breakpoints, METH_NOARGS,
|
||
"Return a tuple of all breakpoint objects" },
|
||
|
||
{ "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
|
||
"Find the default visualizer for a Value." },
|
||
|
||
{ "progspaces", gdbpy_progspaces, METH_NOARGS,
|
||
"Return a sequence of all progspaces." },
|
||
|
||
{ "current_objfile", gdbpy_get_current_objfile, METH_NOARGS,
|
||
"Return the current Objfile being loaded, or None." },
|
||
|
||
{ "newest_frame", gdbpy_newest_frame, METH_NOARGS,
|
||
"newest_frame () -> gdb.Frame.\n\
|
||
Return the newest frame object." },
|
||
{ "selected_frame", gdbpy_selected_frame, METH_NOARGS,
|
||
"selected_frame () -> gdb.Frame.\n\
|
||
Return the selected frame object." },
|
||
{ "frame_stop_reason_string", gdbpy_frame_stop_reason_string, METH_VARARGS,
|
||
"stop_reason_string (Integer) -> String.\n\
|
||
Return a string explaining unwind stop reason." },
|
||
|
||
{ "start_recording", gdbpy_start_recording, METH_VARARGS,
|
||
"start_recording ([method] [, format]) -> gdb.Record.\n\
|
||
Start recording with the given method. If no method is given, will fall back\n\
|
||
to the system default method. If no format is given, will fall back to the\n\
|
||
default format for the given method."},
|
||
{ "current_recording", gdbpy_current_recording, METH_NOARGS,
|
||
"current_recording () -> gdb.Record.\n\
|
||
Return current recording object." },
|
||
{ "stop_recording", gdbpy_stop_recording, METH_NOARGS,
|
||
"stop_recording () -> None.\n\
|
||
Stop current recording." },
|
||
|
||
{ "lookup_type", (PyCFunction) gdbpy_lookup_type,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"lookup_type (name [, block]) -> type\n\
|
||
Return a Type corresponding to the given name." },
|
||
{ "lookup_symbol", (PyCFunction) gdbpy_lookup_symbol,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)\n\
|
||
Return a tuple with the symbol corresponding to the given name (or None) and\n\
|
||
a boolean indicating if name is a field of the current implied argument\n\
|
||
`this' (when the current language is object-oriented)." },
|
||
{ "lookup_global_symbol", (PyCFunction) gdbpy_lookup_global_symbol,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"lookup_global_symbol (name [, domain]) -> symbol\n\
|
||
Return the symbol corresponding to the given name (or None)." },
|
||
{ "lookup_static_symbol", (PyCFunction) gdbpy_lookup_static_symbol,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"lookup_static_symbol (name [, domain]) -> symbol\n\
|
||
Return the static-linkage symbol corresponding to the given name (or None)." },
|
||
{ "lookup_static_symbols", (PyCFunction) gdbpy_lookup_static_symbols,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"lookup_static_symbols (name [, domain]) -> symbol\n\
|
||
Return a list of all static-linkage symbols corresponding to the given name." },
|
||
|
||
{ "lookup_objfile", (PyCFunction) gdbpy_lookup_objfile,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"lookup_objfile (name, [by_build_id]) -> objfile\n\
|
||
Look up the specified objfile.\n\
|
||
If by_build_id is True, the objfile is looked up by using name\n\
|
||
as its build id." },
|
||
|
||
{ "decode_line", gdbpy_decode_line, METH_VARARGS,
|
||
"decode_line (String) -> Tuple. Decode a string argument the way\n\
|
||
that 'break' or 'edit' does. Return a tuple containing two elements.\n\
|
||
The first element contains any unparsed portion of the String parameter\n\
|
||
(or None if the string was fully parsed). The second element contains\n\
|
||
a tuple that contains all the locations that match, represented as\n\
|
||
gdb.Symtab_and_line objects (or None)."},
|
||
{ "parse_and_eval", (PyCFunction) gdbpy_parse_and_eval,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"parse_and_eval (String, [Boolean]) -> Value.\n\
|
||
Parse String as an expression, evaluate it, and return the result as a Value."
|
||
},
|
||
|
||
{ "post_event", gdbpy_post_event, METH_VARARGS,
|
||
"Post an event into gdb's event loop." },
|
||
{ "interrupt", gdbpy_interrupt, METH_NOARGS,
|
||
"Interrupt gdb's current operation." },
|
||
|
||
{ "target_charset", gdbpy_target_charset, METH_NOARGS,
|
||
"target_charset () -> string.\n\
|
||
Return the name of the current target charset." },
|
||
{ "target_wide_charset", gdbpy_target_wide_charset, METH_NOARGS,
|
||
"target_wide_charset () -> string.\n\
|
||
Return the name of the current target wide charset." },
|
||
{ "host_charset", gdbpy_host_charset, METH_NOARGS,
|
||
"host_charset () -> string.\n\
|
||
Return the name of the current host charset." },
|
||
{ "rbreak", (PyCFunction) gdbpy_rbreak, METH_VARARGS | METH_KEYWORDS,
|
||
"rbreak (Regex) -> List.\n\
|
||
Return a Tuple containing gdb.Breakpoint objects that match the given Regex." },
|
||
{ "string_to_argv", gdbpy_string_to_argv, METH_VARARGS,
|
||
"string_to_argv (String) -> Array.\n\
|
||
Parse String and return an argv-like array.\n\
|
||
Arguments are separate by spaces and may be quoted."
|
||
},
|
||
{ "write", (PyCFunction)gdbpy_write, METH_VARARGS | METH_KEYWORDS,
|
||
"Write a string using gdb's filtered stream." },
|
||
{ "flush", (PyCFunction)gdbpy_flush, METH_VARARGS | METH_KEYWORDS,
|
||
"Flush gdb's filtered stdout stream." },
|
||
{ "selected_thread", gdbpy_selected_thread, METH_NOARGS,
|
||
"selected_thread () -> gdb.InferiorThread.\n\
|
||
Return the selected thread object." },
|
||
{ "selected_inferior", gdbpy_selected_inferior, METH_NOARGS,
|
||
"selected_inferior () -> gdb.Inferior.\n\
|
||
Return the selected inferior object." },
|
||
{ "inferiors", gdbpy_inferiors, METH_NOARGS,
|
||
"inferiors () -> (gdb.Inferior, ...).\n\
|
||
Return a tuple containing all inferiors." },
|
||
|
||
{ "invalidate_cached_frames", gdbpy_invalidate_cached_frames, METH_NOARGS,
|
||
"invalidate_cached_frames () -> None.\n\
|
||
Invalidate any cached frame objects in gdb.\n\
|
||
Intended for internal use only." },
|
||
|
||
{ "convenience_variable", gdbpy_convenience_variable, METH_VARARGS,
|
||
"convenience_variable (NAME) -> value.\n\
|
||
Return the value of the convenience variable $NAME,\n\
|
||
or None if not set." },
|
||
{ "set_convenience_variable", gdbpy_set_convenience_variable, METH_VARARGS,
|
||
"convenience_variable (NAME, VALUE) -> None.\n\
|
||
Set the value of the convenience variable $NAME." },
|
||
|
||
#ifdef TUI
|
||
{ "register_window_type", (PyCFunction) gdbpy_register_tui_window,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"register_window_type (NAME, CONSTRUCTOR) -> None\n\
|
||
Register a TUI window constructor." },
|
||
#endif /* TUI */
|
||
|
||
{ "architecture_names", gdbpy_all_architecture_names, METH_NOARGS,
|
||
"architecture_names () -> List.\n\
|
||
Return a list of all the architecture names GDB understands." },
|
||
|
||
{ "connections", gdbpy_connections, METH_NOARGS,
|
||
"connections () -> List.\n\
|
||
Return a list of gdb.TargetConnection objects." },
|
||
|
||
{ "format_address", (PyCFunction) gdbpy_format_address,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"format_address (ADDRESS, PROG_SPACE, ARCH) -> String.\n\
|
||
Format ADDRESS, an address within PROG_SPACE, a gdb.Progspace, using\n\
|
||
ARCH, a gdb.Architecture to determine the address size. The format of\n\
|
||
the returned string is 'ADDRESS <SYMBOL+OFFSET>' without the quotes." },
|
||
|
||
{ "current_language", gdbpy_current_language, METH_NOARGS,
|
||
"current_language () -> string\n\
|
||
Return the name of the currently selected language." },
|
||
|
||
{ "print_options", gdbpy_print_options, METH_NOARGS,
|
||
"print_options () -> dict\n\
|
||
Return the current print options." },
|
||
|
||
{ "notify_mi", (PyCFunction) gdbpy_notify_mi,
|
||
METH_VARARGS | METH_KEYWORDS,
|
||
"notify_mi (name, data) -> None\n\
|
||
Output async record to MI channels if any." },
|
||
{NULL, NULL, 0, NULL}
|
||
};
|
||
|
||
/* Define all the event objects. */
|
||
#define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \
|
||
PyTypeObject name##_event_object_type \
|
||
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object") \
|
||
= { \
|
||
PyVarObject_HEAD_INIT (NULL, 0) \
|
||
"gdb." py_name, /* tp_name */ \
|
||
sizeof (event_object), /* tp_basicsize */ \
|
||
0, /* tp_itemsize */ \
|
||
evpy_dealloc, /* tp_dealloc */ \
|
||
0, /* tp_print */ \
|
||
0, /* tp_getattr */ \
|
||
0, /* tp_setattr */ \
|
||
0, /* tp_compare */ \
|
||
0, /* tp_repr */ \
|
||
0, /* tp_as_number */ \
|
||
0, /* tp_as_sequence */ \
|
||
0, /* tp_as_mapping */ \
|
||
0, /* tp_hash */ \
|
||
0, /* tp_call */ \
|
||
0, /* tp_str */ \
|
||
0, /* tp_getattro */ \
|
||
0, /* tp_setattro */ \
|
||
0, /* tp_as_buffer */ \
|
||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ \
|
||
doc, /* tp_doc */ \
|
||
0, /* tp_traverse */ \
|
||
0, /* tp_clear */ \
|
||
0, /* tp_richcompare */ \
|
||
0, /* tp_weaklistoffset */ \
|
||
0, /* tp_iter */ \
|
||
0, /* tp_iternext */ \
|
||
0, /* tp_methods */ \
|
||
0, /* tp_members */ \
|
||
0, /* tp_getset */ \
|
||
&base, /* tp_base */ \
|
||
0, /* tp_dict */ \
|
||
0, /* tp_descr_get */ \
|
||
0, /* tp_descr_set */ \
|
||
0, /* tp_dictoffset */ \
|
||
0, /* tp_init */ \
|
||
0 /* tp_alloc */ \
|
||
};
|
||
#include "py-event-types.def"
|
||
#undef GDB_PY_DEFINE_EVENT_TYPE
|
||
|
||
#endif /* HAVE_PYTHON */
|