]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Allow conversion of 128-bit integers to Python
authorTom Tromey <tom@tromey.com>
Fri, 5 Sep 2025 11:31:34 +0000 (05:31 -0600)
committerTom Tromey <tom@tromey.com>
Fri, 5 Sep 2025 17:28:42 +0000 (11:28 -0600)
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>
gdb/python/py-value.c
gdb/testsuite/gdb.python/py-value.exp

index 833ce26d5a36d1536fb71ca3e186470ff354b0af..7cde7a5a32791e57b1a8b12255b8623d36675a47 100644 (file)
@@ -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.  */
index ab49f2deb9201fa5cbd82486aadb9ba071538490..089bf7563bfd8bff309e4d214461385748d7ef9b 100644 (file)
@@ -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"
+}