123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- /* General utility routines for GDB/Python.
- Copyright (C) 2008-2022 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 "defs.h"
- #include "charset.h"
- #include "value.h"
- #include "python-internal.h"
- /* Converts a Python 8-bit string to a unicode string object. Assumes the
- 8-bit string is in the host charset. If an error occurs during conversion,
- returns NULL with a python exception set.
- As an added bonus, the functions accepts a unicode string and returns it
- right away, so callers don't need to check which kind of string they've
- got. In Python 3, all strings are Unicode so this case is always the
- one that applies.
- If the given object is not one of the mentioned string types, NULL is
- returned, with the TypeError python exception set. */
- gdbpy_ref<>
- python_string_to_unicode (PyObject *obj)
- {
- PyObject *unicode_str;
- /* If obj is already a unicode string, just return it.
- I wish life was always that simple... */
- if (PyUnicode_Check (obj))
- {
- unicode_str = obj;
- Py_INCREF (obj);
- }
- else
- {
- PyErr_SetString (PyExc_TypeError,
- _("Expected a string object."));
- unicode_str = NULL;
- }
- return gdbpy_ref<> (unicode_str);
- }
- /* Returns a newly allocated string with the contents of the given unicode
- string object converted to CHARSET. If an error occurs during the
- conversion, NULL will be returned and a python exception will be
- set. */
- static gdb::unique_xmalloc_ptr<char>
- unicode_to_encoded_string (PyObject *unicode_str, const char *charset)
- {
- /* Translate string to named charset. */
- gdbpy_ref<> string (PyUnicode_AsEncodedString (unicode_str, charset, NULL));
- if (string == NULL)
- return NULL;
- return gdb::unique_xmalloc_ptr<char>
- (xstrdup (PyBytes_AsString (string.get ())));
- }
- /* Returns a PyObject with the contents of the given unicode string
- object converted to a named charset. If an error occurs during
- the conversion, NULL will be returned and a python exception will
- be set. */
- static gdbpy_ref<>
- unicode_to_encoded_python_string (PyObject *unicode_str, const char *charset)
- {
- /* Translate string to named charset. */
- return gdbpy_ref<> (PyUnicode_AsEncodedString (unicode_str, charset, NULL));
- }
- /* Returns a newly allocated string with the contents of the given
- unicode string object converted to the target's charset. If an
- error occurs during the conversion, NULL will be returned and a
- python exception will be set. */
- gdb::unique_xmalloc_ptr<char>
- unicode_to_target_string (PyObject *unicode_str)
- {
- return (unicode_to_encoded_string
- (unicode_str,
- target_charset (gdbpy_enter::get_gdbarch ())));
- }
- /* Returns a PyObject with the contents of the given unicode string
- object converted to the target's charset. If an error occurs
- during the conversion, NULL will be returned and a python exception
- will be set. */
- static gdbpy_ref<>
- unicode_to_target_python_string (PyObject *unicode_str)
- {
- return (unicode_to_encoded_python_string
- (unicode_str,
- target_charset (gdbpy_enter::get_gdbarch ())));
- }
- /* Converts a python string (8-bit or unicode) to a target string in
- the target's charset. Returns NULL on error, with a python
- exception set. */
- gdb::unique_xmalloc_ptr<char>
- python_string_to_target_string (PyObject *obj)
- {
- gdbpy_ref<> str = python_string_to_unicode (obj);
- if (str == NULL)
- return NULL;
- return unicode_to_target_string (str.get ());
- }
- /* Converts a python string (8-bit or unicode) to a target string in the
- target's charset. Returns NULL on error, with a python exception
- set.
- In Python 3, the returned object is a "bytes" object (not a string). */
- gdbpy_ref<>
- python_string_to_target_python_string (PyObject *obj)
- {
- gdbpy_ref<> str = python_string_to_unicode (obj);
- if (str == NULL)
- return str;
- return unicode_to_target_python_string (str.get ());
- }
- /* Converts a python string (8-bit or unicode) to a target string in
- the host's charset. Returns NULL on error, with a python exception
- set. */
- gdb::unique_xmalloc_ptr<char>
- python_string_to_host_string (PyObject *obj)
- {
- gdbpy_ref<> str = python_string_to_unicode (obj);
- if (str == NULL)
- return NULL;
- return unicode_to_encoded_string (str.get (), host_charset ());
- }
- /* Convert a host string to a python string. */
- gdbpy_ref<>
- host_string_to_python_string (const char *str)
- {
- return gdbpy_ref<> (PyUnicode_Decode (str, strlen (str), host_charset (),
- NULL));
- }
- /* Return true if OBJ is a Python string or unicode object, false
- otherwise. */
- int
- gdbpy_is_string (PyObject *obj)
- {
- return PyUnicode_Check (obj);
- }
- /* Return the string representation of OBJ, i.e., str (obj).
- If the result is NULL a python error occurred, the caller must clear it. */
- gdb::unique_xmalloc_ptr<char>
- gdbpy_obj_to_string (PyObject *obj)
- {
- gdbpy_ref<> str_obj (PyObject_Str (obj));
- if (str_obj != NULL)
- return python_string_to_host_string (str_obj.get ());
- return NULL;
- }
- /* See python-internal.h. */
- gdb::unique_xmalloc_ptr<char>
- gdbpy_err_fetch::to_string () const
- {
- /* There are a few cases to consider.
- For example:
- value is a string when PyErr_SetString is used.
- value is not a string when raise "foo" is used, instead it is None
- and type is "foo".
- So the algorithm we use is to print `str (value)' if it's not
- None, otherwise we print `str (type)'.
- Using str (aka PyObject_Str) will fetch the error message from
- gdb.GdbError ("message"). */
- if (m_error_value && m_error_value != Py_None)
- return gdbpy_obj_to_string (m_error_value);
- else
- return gdbpy_obj_to_string (m_error_type);
- }
- /* See python-internal.h. */
- gdb::unique_xmalloc_ptr<char>
- gdbpy_err_fetch::type_to_string () const
- {
- return gdbpy_obj_to_string (m_error_type);
- }
- /* Convert a GDB exception to the appropriate Python exception.
- This sets the Python error indicator. */
- void
- gdbpy_convert_exception (const struct gdb_exception &exception)
- {
- PyObject *exc_class;
- if (exception.reason == RETURN_QUIT)
- exc_class = PyExc_KeyboardInterrupt;
- else if (exception.error == MEMORY_ERROR)
- exc_class = gdbpy_gdb_memory_error;
- else
- exc_class = gdbpy_gdb_error;
- PyErr_Format (exc_class, "%s", exception.what ());
- }
- /* Converts OBJ to a CORE_ADDR value.
- Returns 0 on success or -1 on failure, with a Python exception set.
- */
- int
- get_addr_from_python (PyObject *obj, CORE_ADDR *addr)
- {
- if (gdbpy_is_value_object (obj))
- {
- try
- {
- *addr = value_as_address (value_object_to_value (obj));
- }
- catch (const gdb_exception &except)
- {
- GDB_PY_SET_HANDLE_EXCEPTION (except);
- }
- }
- else
- {
- gdbpy_ref<> num (PyNumber_Long (obj));
- gdb_py_ulongest val;
- if (num == NULL)
- return -1;
- val = gdb_py_long_as_ulongest (num.get ());
- if (PyErr_Occurred ())
- return -1;
- if (sizeof (val) > sizeof (CORE_ADDR) && ((CORE_ADDR) val) != val)
- {
- PyErr_SetString (PyExc_ValueError,
- _("Overflow converting to address."));
- return -1;
- }
- *addr = val;
- }
- return 0;
- }
- /* Convert a LONGEST to the appropriate Python object -- either an
- integer object or a long object, depending on its value. */
- gdbpy_ref<>
- gdb_py_object_from_longest (LONGEST l)
- {
- if (sizeof (l) > sizeof (long))
- return gdbpy_ref<> (PyLong_FromLongLong (l));
- return gdbpy_ref<> (PyLong_FromLong (l));
- }
- /* Convert a ULONGEST to the appropriate Python object -- either an
- integer object or a long object, depending on its value. */
- gdbpy_ref<>
- gdb_py_object_from_ulongest (ULONGEST l)
- {
- if (sizeof (l) > sizeof (unsigned long))
- return gdbpy_ref<> (PyLong_FromUnsignedLongLong (l));
- return gdbpy_ref<> (PyLong_FromUnsignedLong (l));
- }
- /* Like PyLong_AsLong, but returns 0 on failure, 1 on success, and puts
- the value into an out parameter. */
- int
- gdb_py_int_as_long (PyObject *obj, long *result)
- {
- *result = PyLong_AsLong (obj);
- return ! (*result == -1 && PyErr_Occurred ());
- }
- /* Generic implementation of the __dict__ attribute for objects that
- have a dictionary. The CLOSURE argument should be the type object.
- This only handles positive values for tp_dictoffset. */
- PyObject *
- gdb_py_generic_dict (PyObject *self, void *closure)
- {
- PyObject *result;
- PyTypeObject *type_obj = (PyTypeObject *) closure;
- char *raw_ptr;
- raw_ptr = (char *) self + type_obj->tp_dictoffset;
- result = * (PyObject **) raw_ptr;
- Py_INCREF (result);
- return result;
- }
- /* Like PyModule_AddObject, but does not steal a reference to
- OBJECT. */
- int
- gdb_pymodule_addobject (PyObject *module, const char *name, PyObject *object)
- {
- int result;
- Py_INCREF (object);
- result = PyModule_AddObject (module, name, object);
- if (result < 0)
- Py_DECREF (object);
- return result;
- }
- /* See python-internal.h. */
- void
- gdbpy_error (const char *fmt, ...)
- {
- va_list ap;
- va_start (ap, fmt);
- std::string str = string_vprintf (fmt, ap);
- va_end (ap);
- const char *msg = str.c_str ();
- if (msg != nullptr && *msg != '\0')
- error (_("Error occurred in Python: %s"), msg);
- else
- error (_("Error occurred in Python."));
- }
- /* Handle a Python exception when the special gdb.GdbError treatment
- is desired. This should only be called when an exception is set.
- If the exception is a gdb.GdbError, throw a gdb exception with the
- exception text. For other exceptions, print the Python stack and
- then throw a gdb exception. */
- void
- gdbpy_handle_exception ()
- {
- gdbpy_err_fetch fetched_error;
- gdb::unique_xmalloc_ptr<char> msg = fetched_error.to_string ();
- if (msg == NULL)
- {
- /* An error occurred computing the string representation of the
- error message. This is rare, but we should inform the user. */
- gdb_printf (_("An error occurred in Python "
- "and then another occurred computing the "
- "error message.\n"));
- gdbpy_print_stack ();
- }
- /* Don't print the stack for gdb.GdbError exceptions.
- It is generally used to flag user errors.
- We also don't want to print "Error occurred in Python command"
- for user errors. However, a missing message for gdb.GdbError
- exceptions is arguably a bug, so we flag it as such. */
- if (fetched_error.type_matches (PyExc_KeyboardInterrupt))
- throw_quit ("Quit");
- else if (! fetched_error.type_matches (gdbpy_gdberror_exc)
- || msg == NULL || *msg == '\0')
- {
- fetched_error.restore ();
- gdbpy_print_stack ();
- if (msg != NULL && *msg != '\0')
- error (_("Error occurred in Python: %s"), msg.get ());
- else
- error (_("Error occurred in Python."));
- }
- else
- error ("%s", msg.get ());
- }
|