[RFC - Python Scripting] New method gdb.Architecture.disassemble

Siva Chandra sivachandra@google.com
Tue Feb 12 14:56:00 GMT 2013


On Fri, Feb 8, 2013 at 10:05 AM, Doug Evans <dje@google.com> wrote:
> On Tue, Feb 5, 2013 at 5:53 PM, Siva Chandra <sivachandra@google.com> wrote:
>> The only useful entry point currently available is gdb_disassembly and
>> I do not think it is a bad entry point. Other disassembly functions in
>> disasm.c are static.
>
> Well, it begs the question what entrypoint into libopcodes does
> gdb_disassembly use? :-)
> Anyways, my point is gdb_disassembly is a bit high level for the
> Python API for me.

Thanks for your detailed reply. I now have a patch which does not use
ui_out. Instead of calling gdb_disassembly, it essentially
re-implements disasm.c:dump_insns. The patch is attached.

2013-02-12  Siva Chandra Reddy  <sivachandra@google.com>

        Add a new method 'disassemble' to gdb.Architecture class.
        * python/py-arch.c (archpy_disassmble): Implementation of the
        new method gdb.Architecture.disassemble.
        (arch_object_methods): Add entry for the new method.
-------------- next part --------------
diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c
index edd508f..dd50d78 100644
--- a/gdb/python/py-arch.c
+++ b/gdb/python/py-arch.c
@@ -20,6 +20,7 @@
 #include "defs.h"
 #include "gdbarch.h"
 #include "arch-utils.h"
+#include "disasm.h"
 #include "python-internal.h"
 
 typedef struct arch_object_type_object {
@@ -86,6 +87,137 @@ archpy_name (PyObject *self, PyObject *args)
   return py_name;
 }
 
+/* Implementation of gdb.Architecture.disassemble (self, low, high) -> List.
+   Returns a list of instructions in a memory address range.  Each instruction
+   in the list is a dict object with the following string keys:
+
+   KEY         VALUE TYPE      DESCRIPTION
+   =============================================================================
+   'addr'      long integer    The address of the instruction in target memory.
+   -----------------------------------------------------------------------------
+   'asm'       string          The instruction depicted in its assembly
+                               language. Will be set to 'unknown' if GDB is
+                               unable to obtain this value.
+   -----------------------------------------------------------------------------
+   'func'      string          Name of the function to which the instruction
+                               belongs to. Will be set to '<unknown>' if GDB is
+                               unable to obtain this value.
+   -----------------------------------------------------------------------------
+   'length'    integer         Length of the instruction in bytes.
+   -----------------------------------------------------------------------------
+   'offset'    integer         The byte offset of the instruction in the func
+                               above. Will be set to -1 if GDB is unable to
+                               obtain this value.
+*/
+
+static PyObject *
+archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
+{
+  static char *keywords[] = { "low", "high", NULL };
+  CORE_ADDR low, high;
+  CORE_ADDR pc;
+  PyObject *result_list;
+  static char unknown_str[] = { '<', 'u', 'n', 'k', 'n', 'o', 'w', 'n', '>', '\0' };
+  struct gdbarch *gdbarch = arch_object_to_gdbarch (self);
+
+  if (!PyArg_ParseTupleAndKeywords (args, kw, GDB_PY_LLU_ARG GDB_PY_LLU_ARG,
+                                    keywords, &low, &high))
+    return NULL;
+
+  result_list = PyList_New (0);
+  if (!result_list)
+    {
+      PyErr_SetString (PyExc_MemoryError,
+                       _("Unable to create a list of disassembled "
+                         "instructions."));
+      return NULL;
+    }
+
+  for (pc = low; pc <= high;)
+    {
+      int line = -1, unmapped, offset = -1, insn_len = 0;
+      char *filename = NULL, *funcname = NULL, *asm_code = NULL;
+      struct ui_file *memfile = mem_fileopen ();
+      PyObject *insn_dict = PyDict_New ();
+      volatile struct gdb_exception except;
+
+      if (!insn_dict)
+        {
+          Py_DECREF (result_list);
+          PyErr_SetString (PyExc_MemoryError,
+                           _("Unable to create a dict for instruction."));
+
+          return NULL;
+        }
+      if (PyList_Append (result_list, insn_dict))
+        {
+          Py_DECREF (result_list);
+          Py_DECREF (insn_dict);
+
+          return NULL;  /* PyList_Append Sets the exception.  */
+        }
+
+      TRY_CATCH (except, RETURN_MASK_ALL)
+        {
+          insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL);
+          /* Even though filename, line and unmapped are passed as arguments,
+             they do not give us any meaningful values currently.  */
+          build_address_symbolic (gdbarch, pc, 0, &funcname, &offset, &filename,
+                                  &line, &unmapped);
+        }
+      if (except.reason < 0)
+        {
+          Py_DECREF (result_list);
+          ui_file_delete (memfile);
+          if (funcname)
+            xfree (funcname);
+          if (filename)
+            xfree (filename);
+          if (asm_code)
+            xfree (asm_code);
+
+          return gdbpy_convert_exception (except);
+        }
+
+      asm_code = ui_file_xstrdup (memfile, NULL);
+      if (!asm_code)
+        asm_code = unknown_str;
+      if (!funcname)
+        funcname = unknown_str;
+      if (!filename)
+        filename = unknown_str;
+
+      if (PyDict_SetItemString (insn_dict, "addr",
+                                gdb_py_long_from_ulongest (pc))
+          || PyDict_SetItemString (insn_dict, "asm",
+                                   PyString_FromString (asm_code))
+          || PyDict_SetItemString (insn_dict, "func",
+                                   PyString_FromString (funcname))
+          || PyDict_SetItemString (insn_dict, "length",
+                                   PyInt_FromLong (insn_len))
+          || PyDict_SetItemString (insn_dict, "offset",
+                                   PyInt_FromLong (offset)))
+        {
+          Py_DECREF (result_list);
+          PyErr_SetString (PyExc_MemoryError,
+                           _("Unable to add fields to instruction dict."));
+
+          return NULL;
+        }
+
+      pc += insn_len;
+      ui_file_delete (memfile);
+      if (funcname && funcname != unknown_str)
+        xfree (funcname);
+      if (filename && filename != unknown_str)
+        xfree (filename);
+      if (asm_code && asm_code != unknown_str)
+        xfree (asm_code);
+    }
+
+  return result_list;
+}
+
 /* Initializes the Architecture class in the gdb module.  */
 
 void
@@ -105,6 +237,10 @@ static PyMethodDef arch_object_methods [] = {
   { "name", archpy_name, METH_NOARGS,
     "name () -> String.\n\
 Return the name of the architecture as a string value." },
+  { "disassemble", (PyCFunction) archpy_disassemble,
+    METH_VARARGS | METH_KEYWORDS,
+    "disassemble (low, high) -> List.\n\
+Return the list of disassembled instructions from LOW to HIGH." },
   {NULL}  /* Sentinel */
 };
 


More information about the Gdb-patches mailing list