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 '' 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 */ };