Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Siva Chandra <sivachandra@google.com>
To: gdb-patches@sourceware.org
Subject: [RFC - Python Scripting] New method gdb.Architecture.disassemble
Date: Mon, 04 Feb 2013 14:09:00 -0000	[thread overview]
Message-ID: <CAGyQ6gy_08hZn2Pk6pmD+AuOkH7SCsQ6732KTa7sucZ7-4prUA@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 794 bytes --]

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.

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.

[-- Attachment #2: arch_disassemble_patch_v1.txt --]
[-- Type: text/plain, Size: 14042 bytes --]

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);
 

             reply	other threads:[~2013-02-04 14:09 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-04 14:09 Siva Chandra [this message]
2013-02-05 23:28 ` Doug Evans
2013-02-06  1:53   ` Siva Chandra
2013-02-06 20:00     ` Tom Tromey
2013-02-08 18:05     ` Doug Evans
2013-02-09 17:55       ` Matt Rice
2013-02-12 14:56       ` Siva Chandra
2013-02-12 21:18         ` Tom Tromey
2013-02-13 14:37           ` Siva Chandra
2013-02-13 17:52             ` Eli Zaretskii
2013-02-13 18:03             ` Tom Tromey
2013-02-13 19:50               ` Siva Chandra
2013-02-13 20:42                 ` Doug Evans
2013-02-14 22:46                   ` Siva Chandra
2013-02-15  6:43                     ` Doug Evans
2013-02-15 17:32                       ` Doug Evans
2013-02-15 17:40                         ` Siva Chandra
2013-02-15 17:41                           ` Siva Chandra
2013-02-15 18:57                           ` Doug Evans
2013-02-15 20:36                       ` Siva Chandra
2013-02-15 21:01                         ` Siva Chandra
2013-02-16  5:30                           ` Doug Evans
2013-02-16  8:47                           ` Eli Zaretskii
2013-02-19  5:36                             ` Siva Chandra
2013-02-19 15:51                               ` Paul_Koning
2013-02-19 16:35                                 ` Eli Zaretskii
2013-02-19 16:38                               ` Eli Zaretskii
2013-02-20 12:34                                 ` Siva Chandra
2013-02-20 18:44                                   ` Eli Zaretskii
2013-02-21  1:49                                     ` Siva Chandra
2013-02-06 19:58 ` Tom Tromey
2013-02-06 20:31   ` Phil Muldoon
2013-02-06 22:31   ` Matt Rice
2013-02-06 23:19     ` Siva Chandra
2013-02-07  1:11       ` Siva Chandra
2013-02-07 23:03         ` Matt Rice
     [not found]       ` <20130206235707.GA2353@klara.mpi.htwm.de>
2013-02-07  1:18         ` Siva Chandra
2013-02-07 14:14   ` Siva Chandra
2013-02-07 16:42     ` Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAGyQ6gy_08hZn2Pk6pmD+AuOkH7SCsQ6732KTa7sucZ7-4prUA@mail.gmail.com \
    --to=sivachandra@google.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox