Add a new method 'disassemble' to gdb.Architecture class.
authorSiva Chandra Reddy <sivachandra@sourceware.org>
Thu, 21 Feb 2013 01:46:57 +0000 (01:46 +0000)
committerSiva Chandra Reddy <sivachandra@sourceware.org>
Thu, 21 Feb 2013 01:46:57 +0000 (01:46 +0000)
* python/py-arch.c (archpy_disassmble): Implementation of the
new method gdb.Architecture.disassemble.
(arch_object_methods): Add entry for the new method.

* doc/gdb.texinfo (Architectures In Python): Add description
about the new method gdb.Architecture.disassemble.

* testsuite/gdb.python/py-arch.c: New test case
* testsuite/gdb.python/py-arch.exp: New tests to test
gdb.Architecture.disassemble
* testsuite/gdb.python/Makefile.in: Add py-arch to the list of
EXECUTABLES.

gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/python/py-arch.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/Makefile.in
gdb/testsuite/gdb.python/py-arch.c [new file with mode: 0644]
gdb/testsuite/gdb.python/py-arch.exp [new file with mode: 0644]

index 46c67f4608dc8335499eea2b12e41cb9016e335f..f72353b97260f22aba9b399d71da41ab756280a3 100644 (file)
@@ -1,3 +1,10 @@
+2013-02-20  Siva Chandra Reddy  <sivachandra@google.com>
+
+       Add a new method 'disassemble' to gdb.Architecture class.
+       * python/py-arch.c (archpy_disassmble): Implementation of the
+       new method gdb.Architecture.disassemble.
+       (arch_object_methods): Add entry for the new method.
+
 2013-02-20  Jiong Wang  <jiwang@tilera.com>
 
        * MAINTAINERS (Write After Approval): Add myself to the list.
index 6a16958c04f6ea6d420c78dc8e27f742451a275e..a2a6ec68db6832d7ac17d2f9c6547c4616a065a7 100644 (file)
@@ -1,3 +1,8 @@
+2013-02-20  Siva Chandra Reddy <sivachandra@google.com>
+
+       * gdb.texinfo (Architectures In Python): Add description about
+       the new method gdb.Architecture.disassemble.
+
 2013-02-15  Pedro Alves  <pedro@codesourcery.com>
            Hafiz Abid Qadeer  <abidh@codesourcery.com>
 
index e8ac8c5987b81bf4cadccd9bcf7a3db1e325e6a0..d611f968d64169ddc724d764649e8a0b2cc82849 100644 (file)
@@ -26040,6 +26040,42 @@ A @code{gdb.Architecture} class has the following methods:
 Return the name (string value) of the architecture.
 @end defun
 
+@defun Architecture.disassemble (@var{start_pc} @r{[}, @var{end_pc} @r{[}, @var{count}@r{]]})
+Return a list of disassembled instructions starting from the memory
+address @var{start_pc}.  The optional arguments @var{end_pc} and
+@var{count} determine the number of instructions in the returned list.
+If both the optional arguments @var{end_pc} and @var{count} are
+specified, then a list of at most @var{count} disassembled instructions
+whose start address falls in the closed memory address interval from
+@var{start_pc} to @var{end_pc} are returned.  If @var{end_pc} is not
+specified, but @var{count} is specified, then @var{count} number of
+instructions starting from the address @var{start_pc} are returned.  If
+@var{count} is not specified but @var{end_pc} is specified, then all
+instructions whose start address falls in the closed memory address
+interval from @var{start_pc} to @var{end_pc} are returned.  If neither
+@var{end_pc} nor @var{count} are specified, then a single instruction at
+@var{start_pc} is returned.  For all of these cases, each element of the
+returned list is a Python @code{dict} with the following string keys:
+
+@table @code
+
+@item addr
+The value corresponding to this key is a Python long integer capturing
+the memory address of the instruction.
+
+@item asm
+The value corresponding to this key is a string value which represents
+the instruction with assembly language mnemonics.  The assembly
+language flavor used is the same as that specified by the current CLI
+variable @code{disassembly-flavor}.  @xref{Machine Code}.
+
+@item length
+The value corresponding to this key is the length (integer value) of the
+instruction in bytes.
+
+@end table
+@end defun
+
 @node Python Auto-loading
 @subsection Python Auto-loading
 @cindex Python auto-loading
index edd508faf78d70def4724b6e0716267a7b4b885b..b41de0625227de0ffa131f43ce8ba38a6c810e67 100644 (file)
@@ -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,145 @@ archpy_name (PyObject *self, PyObject *args)
   return py_name;
 }
 
+/* Implementation of
+   gdb.Architecture.disassemble (self, start_pc [, end_pc [,count]]) -> List.
+   Returns a list of instructions in a memory address range.  Each instruction
+   in the list is a Python dict object.
+*/
+
+static PyObject *
+archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
+{
+  static char *keywords[] = { "start_pc", "end_pc", "count", NULL };
+  CORE_ADDR start, end = 0;
+  CORE_ADDR pc;
+  gdb_py_ulongest start_temp;
+  long count = 0, i;
+  PyObject *result_list, *end_obj = NULL, *count_obj = NULL;
+  struct gdbarch *gdbarch = arch_object_to_gdbarch (self);
+
+  if (!PyArg_ParseTupleAndKeywords (args, kw, GDB_PY_LLU_ARG "|OO", keywords,
+                                    &start_temp, &end_obj, &count_obj))
+    return NULL;
+
+  start = start_temp;
+  if (end_obj)
+    {
+      if (PyObject_TypeCheck (end_obj, &PyInt_Type))
+        /* If the end_pc value is specified without a trailing 'L', end_obj will
+           be an integer and not a long integer.  */
+        end = PyInt_AsLong (end_obj);
+      else if (PyObject_TypeCheck (end_obj, &PyLong_Type))
+        end = PyLong_AsUnsignedLongLong (end_obj);
+      else
+        {
+          Py_DECREF (end_obj);
+          Py_XDECREF (count_obj);
+          PyErr_SetString (PyExc_TypeError,
+                           _("Argument 'end_pc' should be a (long) integer."));
+
+          return NULL;
+        }
+
+      if (end < start)
+        {
+          Py_DECREF (end_obj);
+          Py_XDECREF (count_obj);
+          PyErr_SetString (PyExc_ValueError,
+                           _("Argument 'end_pc' should be greater than or "
+                             "equal to the argument 'start_pc'."));
+
+          return NULL;
+        }
+    }
+  if (count_obj)
+    {
+      count = PyInt_AsLong (count_obj);
+      if (PyErr_Occurred () || count < 0)
+        {
+          Py_DECREF (count_obj);
+          Py_XDECREF (end_obj);
+          PyErr_SetString (PyExc_TypeError,
+                           _("Argument 'count' should be an non-negative "
+                             "integer."));
+
+          return NULL;
+        }
+    }
+
+  result_list = PyList_New (0);
+  if (result_list == NULL)
+    return NULL;
+
+  for (pc = start, i = 0;
+       /* All args are specified.  */
+       (end_obj && count_obj && pc <= end && i < count)
+       /* end_pc is specified, but no count.  */
+       || (end_obj && count_obj == NULL && pc <= end)
+       /* end_pc is not specified, but a count is.  */
+       || (end_obj == NULL && count_obj && i < count)
+       /* Both end_pc and count are not specified.  */
+       || (end_obj == NULL && count_obj == NULL && pc == start);)
+    {
+      int insn_len = 0;
+      char *as = NULL;
+      struct ui_file *memfile = mem_fileopen ();
+      PyObject *insn_dict = PyDict_New ();
+      volatile struct gdb_exception except;
+
+      if (insn_dict == NULL)
+        {
+          Py_DECREF (result_list);
+          ui_file_delete (memfile);
+
+          return NULL;
+        }
+      if (PyList_Append (result_list, insn_dict))
+        {
+          Py_DECREF (result_list);
+          Py_DECREF (insn_dict);
+          ui_file_delete (memfile);
+
+          return NULL;  /* PyList_Append Sets the exception.  */
+        }
+
+      TRY_CATCH (except, RETURN_MASK_ALL)
+        {
+          insn_len = gdb_print_insn (gdbarch, pc, memfile, NULL);
+        }
+      if (except.reason < 0)
+        {
+          Py_DECREF (result_list);
+          ui_file_delete (memfile);
+
+          return gdbpy_convert_exception (except);
+        }
+
+      as = ui_file_xstrdup (memfile, NULL);
+      if (PyDict_SetItemString (insn_dict, "addr",
+                                gdb_py_long_from_ulongest (pc))
+          || PyDict_SetItemString (insn_dict, "asm",
+                                   PyString_FromString (*as ? as : "<unknown>"))
+          || PyDict_SetItemString (insn_dict, "length",
+                                   PyInt_FromLong (insn_len)))
+        {
+          Py_DECREF (result_list);
+
+          ui_file_delete (memfile);
+          xfree (as);
+
+          return NULL;
+        }
+
+      pc += insn_len;
+      i++;
+      ui_file_delete (memfile);
+      xfree (as);
+    }
+
+  return result_list;
+}
+
 /* Initializes the Architecture class in the gdb module.  */
 
 void
@@ -105,6 +245,11 @@ 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 (start_pc [, end_pc [, count]]) -> List.\n\
+Return a list of at most COUNT disassembled instructions from START_PC to\n\
+END_PC." },
   {NULL}  /* Sentinel */
 };
 
index 60c6bf8c4846796505512d6b9e046d43c03eaf70..3a8a8e1bb80411df32ef02ffa7e9c99ba7f7bff6 100644 (file)
@@ -1,3 +1,11 @@
+2013-02-20  Siva Chandra Reddy  <sivachandra@google.com>
+
+       * gdb.python/py-arch.c: New test case
+       * gdb.python/py-arch.exp: New tests to test
+       gdb.Architecture.disassemble
+       * gdb.python/Makefile.in: Add py-arch to the list of
+       EXECUTABLES.
+
 2013-02-18  Tom Tromey  <tromey@redhat.com>
 
        * gdb.dwarf2/subrange.exp: New file.
index 4e286b539dc68adc621bda6d92fe65d2c1d1f532..0b815075599dc125f210651c347959c4e48cab0d 100644 (file)
@@ -6,7 +6,7 @@ EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
        py-shared python lib-types py-events py-evthreads py-frame \
        py-mi py-pp-maint py-progspace py-section-script py-objfile \
        py-finish-breakpoint py-finish-breakpoint2 py-value-cc py-explore \
-       py-explore-cc
+       py-explore-cc py-arch
 
 MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so 
 
diff --git a/gdb/testsuite/gdb.python/py-arch.c b/gdb/testsuite/gdb.python/py-arch.c
new file mode 100644 (file)
index 0000000..e2fe55c
--- /dev/null
@@ -0,0 +1,23 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   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/>.
+*/
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.python/py-arch.exp b/gdb/testsuite/gdb.python/py-arch.exp
new file mode 100644 (file)
index 0000000..4e736b8
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright 2013 Free Software Foundation, Inc.
+
+# 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/>.
+
+standard_testfile
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    return -1
+}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+if ![runto_main] {
+   return -1
+}
+
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "get frame" 0
+gdb_py_test_silent_cmd "python arch = frame.architecture()" "get arch" 0
+gdb_py_test_silent_cmd "python pc = frame.pc()" "get pc" 0
+gdb_py_test_silent_cmd "python insn_list1 = arch.disassemble(pc, pc, 1)" \
+  "disassemble" 0
+gdb_py_test_silent_cmd "python insn_list2 = arch.disassemble(pc, pc)" \
+  "disassemble no count" 0
+gdb_py_test_silent_cmd "python insn_list3 = arch.disassemble(pc, count=1)" \
+  "disassemble no end" 0
+gdb_py_test_silent_cmd "python insn_list4 = arch.disassemble(pc)" \
+  "disassemble no end no count" 0
+
+gdb_test "python print len(insn_list1)" "1" "test number of instructions 1"
+gdb_test "python print len(insn_list2)" "1" "test number of instructions 2"
+gdb_test "python print len(insn_list3)" "1" "test number of instructions 3"
+gdb_test "python print len(insn_list4)" "1" "test number of instructions 4"
+
+gdb_py_test_silent_cmd "python insn = insn_list1\[0\]" "get instruction" 0
+
+gdb_test "python print \"addr\" in insn" "True" "test key addr"
+gdb_test "python print \"asm\" in insn" "True" "test key asm"
+gdb_test "python print \"length\" in insn" "True" "test key length"
+
+# Negative test
+gdb_test "python arch.disassemble(0, 0)" ".*gdb\.MemoryError.*" \
+  "test exception"