From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14867 invoked by alias); 5 Feb 2013 23:28:10 -0000 Received: (qmail 14847 invoked by uid 22791); 5 Feb 2013 23:28:09 -0000 X-SWARE-Spam-Status: No, hits=-5.6 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,KHOP_RCVD_TRUST,KHOP_THREADED,RCVD_IN_DNSWL_LOW,RCVD_IN_HOSTKARMA_YE,RP_MATCHES_RCVD,TW_HP X-Spam-Check-By: sourceware.org Received: from mail-qa0-f73.google.com (HELO mail-qa0-f73.google.com) (209.85.216.73) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 05 Feb 2013 23:28:02 +0000 Received: by mail-qa0-f73.google.com with SMTP id g10so100601qah.2 for ; Tue, 05 Feb 2013 15:28:01 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:mime-version:content-type:content-transfer-encoding :message-id:date:to:cc:subject:in-reply-to:references:x-mailer :x-gm-message-state; bh=YP1lT2tkGvXgYdEGj57IkjQka+q/voKsPyQi3n2k03Q=; b=pupCeJR5ju6gU9d/TOG01oziyhf1kigrTpwgE7EcvFuQLi6l/S8XtTdrRmG0LJ3Fnn +7J80Ip47NKWDAqNoHjjVuVx6ghCBUrU8UZ1tO5ZBmu6K9h7BWSJ6eMBOe15fMupM/oJ X3UJj1FhwL8NfTTcBgUis3eX6WjckPjhbkD4BEHHBuR/r22TzME5pZOyJlci1maAuhPw aPZ5yLlqyEaisDdVj8Yg1xcsO9JjqP4j5ZuTmEcFORfdYRvj7fjGM20KUdBvBkLXOpr3 PNxlR/MIi1Zqh6vNoT1fA+5PPEEzK0FFi+DdoNeh/tO+fNipSKvsgT8zw6Pqc9RsAefC iTKw== X-Received: by 10.236.154.2 with SMTP id g2mr12638852yhk.13.1360106881169; Tue, 05 Feb 2013 15:28:01 -0800 (PST) Received: from corp2gmr1-1.hot.corp.google.com (corp2gmr1-1.hot.corp.google.com [172.24.189.92]) by gmr-mx.google.com with ESMTPS id u21si931574yhj.0.2013.02.05.15.28.01 (version=TLSv1.1 cipher=AES128-SHA bits=128/128); Tue, 05 Feb 2013 15:28:01 -0800 (PST) Received: from ruffy2.mtv.corp.google.com (ruffy2.mtv.corp.google.com [172.17.128.107]) by corp2gmr1-1.hot.corp.google.com (Postfix) with ESMTP id 9E40731C1CE; Tue, 5 Feb 2013 15:28:00 -0800 (PST) From: Doug Evans MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <20753.38272.55066.651097@ruffy2.mtv.corp.google.com> Date: Tue, 05 Feb 2013 23:28:00 -0000 To: Siva Chandra Cc: gdb-patches@sourceware.org Subject: Re: [RFC - Python Scripting] New method gdb.Architecture.disassemble In-Reply-To: References: X-Gm-Message-State: ALoCoQl+sczZG07mZ7sSS+oyoPO7V47hUJ75tD4qYvIwC4T8rYaT+8FNzQw/uy+LK5/+zpToh1JWK4JVY8rI1cV7/FbTnicac9KUZ1oWGJAjEP4I7/Dz+XeYHhWLCgx5NchQoLJ5kXCNoOQqY9PX6H6xOJ3dYVuEXTm8KHHANHpIrT+tJWVI4ViTWBwvf/sQIgKzil7ipjDLZ+TYkTXF/l1MBaKAewInXA== X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2013-02/txt/msg00132.txt.bz2 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 > > 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 . */ > + > +#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