diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 68d545e..6be64cf 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -291,6 +291,7 @@ SUBDIR_PYTHON_OBS = \ py-lazy-string.o \ py-newobjfileevent.o \ py-objfile.o \ + py-out.o \ py-param.o \ py-prettyprint.o \ py-progspace.o \ @@ -325,6 +326,7 @@ SUBDIR_PYTHON_SRCS = \ python/py-lazy-string.c \ python/py-newobjfileevent.c \ python/py-objfile.c \ + python/py-out.c \ python/py-param.c \ python/py-prettyprint.c \ python/py-progspace.c \ @@ -2129,6 +2131,10 @@ py-objfile.o: $(srcdir)/python/py-objfile.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-objfile.c $(POSTCOMPILE) +py-out.o: $(srcdir)/python/py-out.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-out.c + $(POSTCOMPILE) + py-param.o: $(srcdir)/python/py-param.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-param.c $(POSTCOMPILE) diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c index edd508f..b1608d7 100644 --- a/gdb/python/py-arch.c +++ b/gdb/python/py-arch.c @@ -19,6 +19,7 @@ #include "defs.h" #include "gdbarch.h" +#include "disasm.h" #include "arch-utils.h" #include "python-internal.h" @@ -86,6 +87,45 @@ archpy_name (PyObject *self, PyObject *args) return py_name; } +/* Implementation of Architecture.disassemble (low, high, [opcodes]) -> List. + Returns a list of instructions, each of which is a dictionary. */ + +static PyObject * +archpy_disassemble (PyObject *self, PyObject *args) +{ + struct gdbarch *gdbarch = arch_object_to_gdbarch (self); + CORE_ADDR low, high; + int opcodes = 0, flags = 0; + PyObject *result, *temp; + struct ui_out *py_out = py_ui_out (); + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "KK|i", &low, &high, &opcodes)) + return NULL; + + if (opcodes) + flags = DISASSEMBLY_RAW_INSN; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + gdb_disassembly (gdbarch, py_out, NULL, flags, -1, low, high); + } + GDB_PY_HANDLE_EXCEPTION (except); + + temp = fetch_and_reset_py_out_object (py_out); + if (! (PyList_Check (temp) && PyList_Size (temp) > 0)) + return NULL; + + /* gdb_disassembly puts a list of lists in py_out with the higher level list + containing a single item which is itself a list of instructions. Hence, + return the first element of the higher level list. */ + result = PyList_GetItem (temp, 0); + Py_XINCREF (result); + Py_XDECREF (temp); + + return result; +} + /* Initializes the Architecture class in the gdb module. */ void @@ -105,6 +145,9 @@ static PyMethodDef arch_object_methods [] = { { "name", archpy_name, METH_NOARGS, "name () -> String.\n\ Return the name of the architecture as a string value." }, + { "disassemble", archpy_disassemble, METH_VARARGS, + "name (low, high, [opcodes]) -> List.\n\ +Return the list of instructions in the address range from LOW to HIGH." }, {NULL} /* Sentinel */ }; diff --git a/gdb/python/py-out.c b/gdb/python/py-out.c new file mode 100644 index 0000000..f6a1456 --- /dev/null +++ b/gdb/python/py-out.c @@ -0,0 +1,265 @@ +/* Python ui_out implementation. + + Copyright (C) 2013 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "ui-out.h" +#include "python-internal.h" + +static struct ui_out *py_out; + +struct row_data +{ + /* DATA is either a list of rows, or just a dict. */ + PyObject *data; + + /* The enclosing row for the above DATA. */ + struct row_data *parent_row; +}; + +/* This data structure captures the Python version of ui_out. The Python + version is not used to display output to a user, but to capture the results + from GDB's internals in to a Python data structure. Hence, it does not have + any representation for table headers. However, it can be viewed as a + recursive table structure wherin the highest level is a list of rows. All + rows in this list can either be a list themselves, or all of them can be + dicts holding the table's fields. If they were lists, then they follow the + same recurrsive structure as the higher levels. + + Example: + + [ # Highest level list which has two lists for rows + [ # Inner level row which is a list of lists + [ # Inner level row which is a list of dicts + {'a': 1, 'b': 2}, # Leaf row which is a dict + {'a': 3, 'b': 4}, # Leaf row which is a dict + ], + + [ # Inner level row which is a list of dicts + {'x': 5, 'y': 6}, # Leaf row which is a dict + {'x': 7, 'y': 8}, # Leaf row which is a dict + ], + ], + + [ # Inner level row which is list of dicts + {'p': 1, 'q': 2}, # Leaf row which is a dict + {'p': 3, 'q': 4}, # Leaf row which is a dict + ], + ] +*/ + +struct py_out_data +{ + /* The highest level list of rows. */ + struct row_data *table; + + /* The current row that is being added to the table. */ + struct row_data *current_row; +}; + +static struct row_data * +new_row (struct row_data *parent) +{ + struct row_data *row; + + row = (struct row_data *) xmalloc (sizeof (struct row_data)); + row->data = NULL; + row->parent_row = parent; + + return row; +} + +PyObject * +fetch_and_reset_py_out_object (struct ui_out *ui_out) +{ + PyObject *temp; + struct py_out_data *py_out_data = ui_out_data (ui_out); + + /* Ensure that the py_out object is complete. */ + if (py_out_data->current_row != py_out_data->table) + internal_error (__FILE__, __LINE__, + _("Trying to fetch an incomplete Python ui_out object")); + + temp = py_out_data->table->data; + py_out_data->table->data = PyList_New (0); + + return temp; +} + +static void +py_out_row_begin (struct ui_out *ui_out, enum ui_out_type type, int level, + const char *id) +{ + struct py_out_data *py_out_data = ui_out_data (ui_out); + + if (py_out_data->current_row) + { + if (py_out_data->current_row->data) + { + if (PyDict_Check (py_out_data->current_row->data)) + /* If the row has data, check that it is not a dict first. */ + internal_error (__FILE__, __LINE__, + _("Trying to add a row to a row which has " + "fields.")); + else if (PyList_Check (py_out_data->current_row->data)) + { + /* If the row is already a list, add a new row. */ + struct row_data *new_row_data; + + new_row_data = new_row (py_out_data->current_row); + py_out_data->current_row = new_row_data; + } + else + /* If it is neither a list or a dict, then something has gone wrong + somewhere. */ + internal_error (__FILE__, __LINE__, + _("Unexpected internal state in creating Python " + "ui_out object.")); + } + else + { + /* Make the current row a list and add a new row. */ + struct row_data *new_row_data; + + py_out_data->current_row->data = PyList_New (0); + new_row_data = new_row (py_out_data->current_row); + py_out_data->current_row = new_row_data; + } + } + else + { + /* This should never happen. */ + internal_error (__FILE__, __LINE__, + _("Unexpected internal state in creating Python ui_out " + "object.")); + } +} + +static void +py_out_row_end (struct ui_out *ui_out, enum ui_out_type type, int level) +{ + struct py_out_data *py_out_data = ui_out_data (ui_out); + struct row_data *temp; + + /* If nothing was added to current row, then make it Py_None. */ + if (py_out_data->current_row->data == NULL) + { + Py_INCREF (Py_None); + py_out_data->current_row->data = Py_None; + } + + /* Commit the row to the parent list. */ + PyList_Append (py_out_data->current_row->parent_row->data, + py_out_data->current_row->data); + + /* Move up a level by making the parent row as the current row and free the + row_data object corresponding to current_row. */ + temp = py_out_data->current_row; + py_out_data->current_row = py_out_data->current_row->parent_row; + xfree (temp); +} + +#define CHECK_AND_INIT_FIELD_ROW_DATA(data) \ + do { \ + if (!(data)) \ + (data) = PyDict_New (); \ + else \ + { \ + if (!PyDict_Check ((data))) \ + internal_error (__FILE__, __LINE__, \ + _("Adding fields to a row which is not a field " \ + "row.")); \ + } \ + } while (0) + +static void +py_out_field_int (struct ui_out * ui_out, int fldno, int width, + enum ui_align align, const char *fldname, int value) +{ + struct py_out_data *py_out_data = ui_out_data (ui_out); + + CHECK_AND_INIT_FIELD_ROW_DATA (py_out_data->current_row->data); + + PyDict_SetItemString (py_out_data->current_row->data, fldname, + PyInt_FromLong (value)); +} + +static void +py_out_field_skip (struct ui_out *ui_out, int fldno, int width, + enum ui_align align, const char *fldname) +{ + struct py_out_data *py_out_data = ui_out_data (ui_out); + + CHECK_AND_INIT_FIELD_ROW_DATA (py_out_data->current_row->data); + + Py_INCREF (Py_None); + PyDict_SetItemString (py_out_data->current_row->data, fldname, + Py_None); +} + +static void +py_out_field_string (struct ui_out * ui_out, int fldno, int width, + enum ui_align align, const char *fldname, const char *str) +{ + struct py_out_data *py_out_data = ui_out_data (ui_out); + + CHECK_AND_INIT_FIELD_ROW_DATA (py_out_data->current_row->data); + + PyDict_SetItemString (py_out_data->current_row->data, fldname, + PyString_FromString (str)); +} + +static struct ui_out_impl py_ui_out_impl = +{ + 0, /* table_begin */ + 0, /* table_body */ + 0, /* table_end */ + 0, /* table_header */ + py_out_row_begin, /* begin */ + py_out_row_end, /* end */ + py_out_field_int, /* field_int */ + py_out_field_skip, /* field_skip */ + py_out_field_string, /* field_string */ + 0, /* field_fmt */ + 0, /* space */ + 0, /* text */ + 0, /* message */ + 0, /* wrap_hint */ + 0, /* flush */ + 0, /* redirect */ + 0 /* is_mi_like_p */ +}; + +void +gdbpy_initialize_py_out (void) +{ + struct py_out_data *py_out_data; + + py_out_data = (struct py_out_data *) xmalloc (sizeof (struct py_out_data)); + py_out_data->table = new_row (NULL); + py_out_data->table->data = PyList_New (0); + py_out_data->current_row = py_out_data->table; + + py_out = ui_out_new (&py_ui_out_impl, py_out_data, 0); +} + +struct ui_out * +py_ui_out (void) +{ + return py_out; +} diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 8dff1d7..cbc9f31 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -143,6 +143,7 @@ struct language_defn; struct program_space; struct bpstats; struct inferior; +struct ui_out; extern PyObject *gdb_module; extern PyObject *gdb_python_module; @@ -267,6 +268,9 @@ struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj); struct frame_info *frame_object_to_frame_info (PyObject *frame_obj); struct gdbarch *arch_object_to_gdbarch (PyObject *obj); +PyObject *fetch_and_reset_py_out_object (struct ui_out *); +struct ui_out *py_ui_out (void); + void gdbpy_initialize_gdb_readline (void); void gdbpy_initialize_auto_load (void); void gdbpy_initialize_values (void); @@ -297,6 +301,7 @@ void gdbpy_initialize_exited_event (void); void gdbpy_initialize_thread_event (void); void gdbpy_initialize_new_objfile_event (void); void gdbpy_initialize_arch (void); +void gdbpy_initialize_py_out (void); struct cleanup *make_cleanup_py_decref (PyObject *py); diff --git a/gdb/python/python.c b/gdb/python/python.c index 53ddee9..3ab4b7c 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1621,6 +1621,7 @@ message == an error message without a stack will be printed."), gdbpy_initialize_thread_event (); gdbpy_initialize_new_objfile_event () ; gdbpy_initialize_arch (); + gdbpy_initialize_py_out (); observer_attach_before_prompt (before_prompt_hook);