This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Siva Chandra writes:
 > The attached patch adds a new method 'disassemble' to the class
 > gdb.Architecture.  I have not yet added docs and tests, but will do so
 > after I get feedback that adding such a method is OK.

Hi.
I like the idea, but for an API I wouldn't mind seeing something
a bit lower level.  E.g., skip the higher level disassembler entry
points in gdb (mixed source/assembly support and all that), and provide
more direct access to the disassembler.

I didn't go through it with a fine toothed comb, but here are some questions.
1) Can we remove the py_out global?
2) It seems like this will export a lot of struct ui_out to the user.
   I'd rather provide disassembly without having to commit to supporting
   struct ui_out in Python.

Thoughts?

 > 2013-02-04  Siva Chandra Reddy  <sivachandra@google.com>
 > 
 >         Add a new method 'disassemble' to gdb.Architecture class.
 >         * Makefile.in: Add entries for the new file python/py-out.c
 >         * python/py-arch.c (archpy_disassmble): Implementation of the
 >         new method gdb.Architecture.disassemble.
 >         (arch_object_methods): Add entry for the new method.
 >         * python/py-out.c: Implementation of a Python ui_out.
 >         * python/python-internal.h: Add declarations for new utility
 >         functions.
 >         * python/python.c (_initialize_python): Initialize Python
 >         ui_out.
 > 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..b6f4f5a 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,44 @@ 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;
 > +  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 +144,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..d278bc2
 > --- /dev/null
 > +++ b/gdb/python/py-out.c
 > @@ -0,0 +1,259 @@
 > +/* 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 <http://www.gnu.org/licenses/>.  */
 > +
 > +#include "defs.h"
 > +#include "ui-out.h"
 > +#include "python-internal.h"
 > +
 > +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);
 > +}
 > diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
 > index 8dff1d7..d852d03 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,8 @@ 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 *);
 > +
 >  void gdbpy_initialize_gdb_readline (void);
 >  void gdbpy_initialize_auto_load (void);
 >  void gdbpy_initialize_values (void);
 > @@ -297,6 +300,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);
 >  
 > @@ -305,6 +309,7 @@ struct cleanup *ensure_python_env (struct gdbarch *gdbarch,
 >  
 >  extern struct gdbarch *python_gdbarch;
 >  extern const struct language_defn *python_language;
 > +extern struct ui_out *py_out;
 >  
 >  /* Use this after a TRY_EXCEPT to throw the appropriate Python
 >     exception.  */
 > 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);
 >  

-- 
/dje


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]