diff options
author | Tom Tromey <tom@tromey.com> | 2025-09-05 05:31:34 -0600 |
---|---|---|
committer | Tom Tromey <tom@tromey.com> | 2025-09-05 11:28:42 -0600 |
commit | 27697103012d289fe279e46a5222308959fe4290 (patch) | |
tree | 95131c956f50d42c7ab14cdda88a2cd3d9cde817 | |
parent | aaad5a3254db53434eaf1cf70384e7ee0dfb886a (diff) | |
download | binutils-27697103012d289fe279e46a5222308959fe4290.zip binutils-27697103012d289fe279e46a5222308959fe4290.tar.gz binutils-27697103012d289fe279e46a5222308959fe4290.tar.bz2 |
Allow conversion of 128-bit integers to Python
Currently, trying to convert a 128-bit integer from a gdb.Value to a
Python integer will fail. This is surprising because Python uses
bigints internally.
The bug here is that valpy_long uses value_as_long, which fails for
anything wider than LONGEST. This patch fixes the problem by using
the recommended Python API.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33366
Approved-By: Simon Marchi <simon.marchi@efficios.com>
-rw-r--r-- | gdb/python/py-value.c | 52 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-value.exp | 12 |
2 files changed, 58 insertions, 6 deletions
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index 833ce26..7cde7a5 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -1866,7 +1866,7 @@ valpy_long (PyObject *self) { struct value *value = ((value_object *) self)->value; struct type *type = value->type (); - LONGEST l = 0; + PyObject *result; try { @@ -1882,17 +1882,57 @@ valpy_long (PyObject *self) && type->code () != TYPE_CODE_PTR) error (_("Cannot convert value to long.")); - l = value_as_long (value); + gdb::array_view<const gdb_byte> contents = value->contents (); +#if PY_VERSION_HEX >= 0x030d0000 + int flags = (type_byte_order (type) == BFD_ENDIAN_BIG + ? Py_ASNATIVEBYTES_BIG_ENDIAN + : Py_ASNATIVEBYTES_LITTLE_ENDIAN); + if (type->is_unsigned ()) + flags |= Py_ASNATIVEBYTES_UNSIGNED_BUFFER; + result = PyLong_FromNativeBytes (contents.data (), contents.size (), + flags); +#else + /* Here we construct a call to "int.from_bytes", passing in the + appropriate arguments. We need a somewhat roundabout + approach because int.from_bytes requires "signed" to be a + keyword arg. */ + + /* PyObject_Call requires a tuple argument. */ + gdbpy_ref<> empty_tuple (PyTuple_New (0)); + if (empty_tuple == nullptr) + return nullptr; + + /* Since we need a dictionary anyway, we pass all arguments as + keywords, building the dictionary here. */ + gdbpy_ref<> args + (Py_BuildValue ("{sy#sssO}", + "bytes", contents.data (), + (Py_ssize_t) contents.size (), + "byteorder", + (type_byte_order (type) == BFD_ENDIAN_BIG + ? "big" : "little"), + "signed", + type->is_unsigned () + ? Py_False : Py_True)); + if (args == nullptr) + return nullptr; + + /* Find the "int.from_bytes" callable. */ + gdbpy_ref<> callable (PyObject_GetAttrString ((PyObject *) &PyLong_Type, + "from_bytes")); + if (callable == nullptr) + return nullptr; + + result = PyObject_Call (callable.get (), empty_tuple.get (), + args.get ()); +#endif } catch (const gdb_exception &except) { return gdbpy_handle_gdb_exception (nullptr, except); } - if (type->is_unsigned ()) - return gdb_py_object_from_ulongest (l).release (); - else - return gdb_py_object_from_longest (l).release (); + return result; } /* Implements conversion to float. */ diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp index ab49f2d..089bf75 100644 --- a/gdb/testsuite/gdb.python/py-value.exp +++ b/gdb/testsuite/gdb.python/py-value.exp @@ -844,3 +844,15 @@ if {[allow_cplus_tests]} { test_subscript_regression "${binfile}-cxx" "c++" } } + +if {[allow_rust_tests]} { + gdb_test "set lang rust" + + set cst 0x80000000000000000000000000000000 + gdb_test "python print(int(gdb.parse_and_eval('${cst}u128')))" \ + "170141183460469231731687303715884105728" \ + "convert 128 bit unsigned constant to python int" + gdb_test "python print(int(gdb.parse_and_eval('${cst}i128')))" \ + "-170141183460469231731687303715884105728" \ + "convert 128 bit signed constant to python int" +} |