From: Tom Tromey Date: Fri, 5 Sep 2025 11:31:34 +0000 (-0600) Subject: Allow conversion of 128-bit integers to Python X-Git-Tag: gdb-17-branchpoint~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=27697103012d289fe279e46a5222308959fe4290;p=thirdparty%2Fbinutils-gdb.git 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 --- diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index 833ce26d5a3..7cde7a5a327 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 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 ab49f2deb92..089bf7563bf 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" +}