New python function gdb.lookup_objfile.
authorDoug Evans <dje@google.com>
Fri, 12 Dec 2014 17:48:13 +0000 (09:48 -0800)
committerDoug Evans <dje@google.com>
Fri, 12 Dec 2014 17:48:13 +0000 (09:48 -0800)
gdb/ChangeLog:

* NEWS: Mention gdb.lookup_objfile.
* python/python.c (GdbMethods): Add lookup_objfile.
* python/python-internal.h (gdbpy_lookup_objfile): Declare.
* python/py-objfile.c: #include "symtab.h".
(objfpy_build_id_ok, objfpy_build_id_matches): New functions.
(objfpy_lookup_objfile_by_name): New function.
(objfpy_lookup_objfile_by_build_id): New function.
(gdbpy_lookup_objfile): New function.

gdb/doc/ChangeLog:

* python.texi (Objfiles In Python): Document gdb.lookup_objfile.

gdb/testsuite/ChangeLog:

* lib/gdb-python.exp (get_python_valueof): New function.
* gdb.python/py-objfile.exp: Add tests for gdb.lookup_objfile.

gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/python.texi
gdb/python/py-objfile.c
gdb/python/python-internal.h
gdb/python/python.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/py-objfile.exp
gdb/testsuite/lib/gdb-python.exp

index a54e2c1863bb08fc8ae487f7f74068ed5bd4516e..70d46293ec94d5799ba2d3a69b9ddc47589fd62b 100644 (file)
@@ -1,3 +1,14 @@
+2014-12-12  Doug Evans  <dje@google.com>
+
+       * NEWS: Mention gdb.lookup_objfile.
+       * python/python.c (GdbMethods): Add lookup_objfile.
+       * python/python-internal.h (gdbpy_lookup_objfile): Declare.
+       * python/py-objfile.c: #include "symtab.h".
+       (objfpy_build_id_ok, objfpy_build_id_matches): New functions.
+       (objfpy_lookup_objfile_by_name): New function.
+       (objfpy_lookup_objfile_by_build_id): New function.
+       (gdbpy_lookup_objfile): New function.
+
 2014-12-12  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * mips-tdep.h (MSYMBOL_TARGET_FLAG_MIPS16): New macro.
index a47dfbf645ab932c2c5ea49cf5ab233fb0460c28..d2c5637ed69a3fe9680dbba4faf0e5e79ffe9810 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -28,6 +28,7 @@
   ** A new event "gdb.clear_objfiles" has been added, triggered when
      selecting a new file to debug.
   ** You can now add attributes to gdb.Objfile and gdb.Progspace objects.
+  ** New function gdb.lookup_objfile.
 
 * New Python-based convenience functions:
 
index b8152df282d6ba165fb81060e5941366937a5ea0..9b36c373bf0a2cea93c287ea62e6bfd05be8bca6 100644 (file)
@@ -1,3 +1,7 @@
+2014-12-12  Doug Evans  <dje@google.com>
+
+       * python.texi (Objfiles In Python): Document gdb.lookup_objfile.
+
 2014-12-12  Andreas Arnez  <arnez@linux.vnet.ibm.com>
 
        * gdb.texinfo: Document "maint print user-registers".
index efd258d9882e986742076dcf30f669b97c8a3c0d..234ce5c5f15f31817dc46081ceb3b2d9c2e692e0 100644 (file)
@@ -3488,6 +3488,27 @@ Return a sequence of all the objfiles current known to @value{GDBN}.
 @xref{Objfiles In Python}.
 @end defun
 
+@findex gdb.lookup_objfile
+@defun gdb.lookup_objfile (name @r{[}, by_build_id{]})
+Look up @var{name}, a file name or build ID, in the list of objfiles
+for the current program space (@pxref{Progspaces In Python}).
+If the objfile is not found throw the Python @code{ValueError} exception.
+
+If @var{name} is a relative file name, then it will match any
+source file name with the same trailing components.  For example, if
+@var{name} is @samp{gcc/expr.c}, then it will match source file
+name of @file{/build/trunk/gcc/expr.c}, but not
+@file{/build/trunk/libcpp/expr.c} or @file{/build/trunk/gcc/x-expr.c}.
+
+If @var{by_build_id} is provided and is @code{True} then @var{name}
+is the build ID of the objfile.  Otherwise, @var{name} is a file name.
+This is supported only on some operating systems, notably those which use
+the ELF format for binary files and the @sc{gnu} Binutils.  For more details
+about this feature, see the description of the @option{--build-id}
+command-line option in @ref{Options, , Command Line Options, ld.info,
+The GNU Linker}.
+@end defun
+
 Each objfile is represented by an instance of the @code{gdb.Objfile}
 class.
 
index d90928bb300b0da514868f37169f2d46a198c101..e78cebaeebb1e944b49944951f0b6c29b2acc40f 100644 (file)
@@ -24,6 +24,7 @@
 #include "language.h"
 #include "build-id.h"
 #include "elf-bfd.h"
+#include "symtab.h"
 
 typedef struct
 {
@@ -384,6 +385,147 @@ objfpy_add_separate_debug_file (PyObject *self, PyObject *args, PyObject *kw)
   Py_RETURN_NONE;
 }
 
+/* Subroutine of gdbpy_lookup_objfile_by_build_id to simplify it.
+   Return non-zero if STRING is a potentially valid build id.  */
+
+static int
+objfpy_build_id_ok (const char *string)
+{
+  size_t i, n = strlen (string);
+
+  if (n % 2 != 0)
+    return 0;
+  for (i = 0; i < n; ++i)
+    {
+      if (!isxdigit (string[i]))
+       return 0;
+    }
+  return 1;
+}
+
+/* Subroutine of gdbpy_lookup_objfile_by_build_id to simplify it.
+   Returns non-zero if BUILD_ID matches STRING.
+   It is assumed that objfpy_build_id_ok (string) returns TRUE.  */
+
+static int
+objfpy_build_id_matches (const struct elf_build_id *build_id,
+                        const char *string)
+{
+  size_t i;
+
+  if (strlen (string) != 2 * build_id->size)
+    return 0;
+
+  for (i = 0; i < build_id->size; ++i)
+    {
+      char c1 = string[i * 2], c2 = string[i * 2 + 1];
+      int byte = (host_hex_value (c1) << 4) | host_hex_value (c2);
+
+      if (byte != build_id->data[i])
+       return 0;
+    }
+
+  return 1;
+}
+
+/* Subroutine of gdbpy_lookup_objfile to simplify it.
+   Look up an objfile by its file name.  */
+
+static struct objfile *
+objfpy_lookup_objfile_by_name (const char *name)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+    {
+      if ((objfile->flags & OBJF_NOT_FILENAME) != 0)
+       continue;
+      /* Don't return separate debug files.  */
+      if (objfile->separate_debug_objfile_backlink != NULL)
+       continue;
+      if (compare_filenames_for_search (objfile_name (objfile), name))
+       return objfile;
+    }
+
+  return NULL;
+}
+
+/* Subroutine of gdbpy_lookup_objfile to simplify it.
+   Look up an objfile by its build id.  */
+
+static struct objfile *
+objfpy_lookup_objfile_by_build_id (const char *build_id)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+    {
+      const struct elf_build_id *obfd_build_id;
+
+      if (objfile->obfd == NULL)
+       continue;
+      /* Don't return separate debug files.  */
+      if (objfile->separate_debug_objfile_backlink != NULL)
+       continue;
+      obfd_build_id = build_id_bfd_get (objfile->obfd);
+      if (obfd_build_id == NULL)
+       continue;
+      if (objfpy_build_id_matches (obfd_build_id, build_id))
+       return objfile;
+    }
+
+  return NULL;
+}
+
+/* Implementation of gdb.lookup_objfile.  */
+
+PyObject *
+gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw)
+{
+  static char *keywords[] = { "name", "by_build_id", NULL };
+  const char *name;
+  PyObject *by_build_id_obj = NULL;
+  int by_build_id;
+  struct objfile *objfile;
+
+  if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!", keywords,
+                                    &name, &PyBool_Type, &by_build_id_obj))
+    return NULL;
+
+  by_build_id = 0;
+  if (by_build_id_obj != NULL)
+    {
+      int cmp = PyObject_IsTrue (by_build_id_obj);
+
+      if (cmp < 0)
+       return NULL;
+      by_build_id = cmp;
+    }
+
+  if (by_build_id)
+    {
+      if (!objfpy_build_id_ok (name))
+       {
+         PyErr_SetString (PyExc_TypeError, _("Not a valid build id."));
+         return NULL;
+       }
+      objfile = objfpy_lookup_objfile_by_build_id (name);
+    }
+  else
+    objfile = objfpy_lookup_objfile_by_name (name);
+
+  if (objfile != NULL)
+    {
+      PyObject *result = objfile_to_objfile_object (objfile);
+
+      Py_XINCREF (result);
+      return result;
+    }
+
+  PyErr_SetString (PyExc_ValueError, _("Objfile not found."));
+  return NULL;
+}
+
 \f
 
 /* Clear the OBJFILE pointer in an Objfile object and remove the
index 716c0de419627307c51caa032fbe647f7b9f4d9e..544fe932af8a572d18fff45556b72c2df431459a 100644 (file)
@@ -393,6 +393,7 @@ PyObject *objfile_to_objfile_object (struct objfile *)
 PyObject *objfpy_get_printers (PyObject *, void *);
 PyObject *objfpy_get_frame_filters (PyObject *, void *);
 PyObject *objfpy_get_xmethods (PyObject *, void *);
+PyObject *gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw);
 
 PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch);
 
index 1362bd24e5a98f521c16e695c1c9648bf9881525..b1d82838f3205b6744a8dd7b766d5e3316cc96f1 100644 (file)
@@ -1956,6 +1956,14 @@ a boolean indicating if name is a field of the current implied argument\n\
     METH_VARARGS | METH_KEYWORDS,
     "lookup_global_symbol (name [, domain]) -> symbol\n\
 Return the symbol corresponding to the given name (or None)." },
+
+  { "lookup_objfile", (PyCFunction) gdbpy_lookup_objfile,
+    METH_VARARGS | METH_KEYWORDS,
+    "lookup_objfile (name, [by_build_id]) -> objfile\n\
+Look up the specified objfile.\n\
+If by_build_id is True, the objfile is looked up by using name\n\
+as its build id." },
+
   { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS,
     "Return the block containing the given pc value, or None." },
   { "solib_name", gdbpy_solib_name, METH_VARARGS,
index b21ac451376afc0dbcc43c9e3957d1b09a63f9a7..22f3ffc85b91ff8b989951bdee3c956fb30b8950 100644 (file)
@@ -1,3 +1,8 @@
+2014-12-12  Doug Evans  <dje@google.com>
+
+       * lib/gdb-python.exp (get_python_valueof): New function.
+       * gdb.python/py-objfile.exp: Add tests for gdb.lookup_objfile.
+
 2014-12-12  Andreas Arnez  <arnez@linux.vnet.ibm.com>
 
        * gdb.base/completion.exp: Add test for completion of "info
index f3a8a6c916f854d4ea4e37c1ec787cfb32e3d279..5d3c084e9164126fc46d6878d772f14bc9c0a477 100644 (file)
@@ -32,23 +32,39 @@ if ![runto_main] then {
     return 0
 }
 
+set python_error_text "Error while executing Python code\\."
+
 gdb_py_test_silent_cmd "python sym = gdb.lookup_symbol(\"some_var\")" \
     "Find a symbol in objfile" 1
 gdb_py_test_silent_cmd "python objfile = sym\[0\].symtab.objfile" \
     "Get backing object file" 1
 
-gdb_test "python print (objfile.filename)" ".*py-objfile.*" \
+gdb_test "python print (objfile.filename)" "${testfile}" \
   "Get objfile file name"
 
+gdb_test "python print (gdb.lookup_objfile (\"${testfile}\").filename)" \
+    "${testfile}"
+gdb_test "python print (gdb.lookup_objfile (\"junk\"))" \
+    "Objfile not found\\.\r\n${python_error_text}"
+
 set binfile_build_id [get_build_id $binfile]
 if [string compare $binfile_build_id ""] {
     verbose -log "binfile_build_id = $binfile_build_id"
     gdb_test "python print (objfile.build_id)" "$binfile_build_id" \
     "Get objfile build id"
+    gdb_test "python print (gdb.lookup_objfile (\"$binfile_build_id\", by_build_id=True).filename)" \
+       "${testfile}"
 } else {
     unsupported "build-id is not supported by the compiler"
 }
 
+# Other lookup_objfile_by_build_id tests we can do, even if compiler doesn't
+# support them.
+gdb_test "python print (gdb.lookup_objfile (\"foo\", by_build_id=True))" \
+    "Not a valid build id\\.\r\n${python_error_text}"
+gdb_test "python print (gdb.lookup_objfile (\"1234abcdef\", by_build_id=True))" \
+    "Objfile not found\\.\r\n${python_error_text}"
+
 gdb_test "python print (objfile.progspace)" "<gdb\.Progspace object at .*>" \
   "Get objfile program space"
 gdb_test "python print (objfile.is_valid())" "True" \
@@ -93,3 +109,9 @@ gdb_test "python print (sep_objfile.owner.filename)" "${testfile}2" \
 
 gdb_test "p main" "= {int \\(\\)} $hex <main>" \
     "print main with debug info"
+
+# Separate debug files are not findable.
+if { [get_python_valueof "sep_objfile.build_id" "None"] != "None" } {
+    gdb_test "python print (gdb.lookup_objfile (sep_objfile.build_id, by_build_id=True))" \
+       "Objfile not found\\.\r\n${python_error_text}"
+}
index d5e79289b4245cd26c908b5967e470255a6a23b3..eefff7331749b45a7842ca80c833e49165535934 100644 (file)
@@ -45,3 +45,24 @@ proc gdb_py_test_multiple { name args } {
     }
     return 0
 }
+
+# Return the result of python expression EXPR.
+# DEFAULT is returned if there's an error.
+# This is modelled after get_integer_valueof.
+
+proc get_python_valueof { exp default } {
+    global gdb_prompt
+
+    set test "get python valueof \"${exp}\""
+    set val ${default}
+    gdb_test_multiple "python print (\"valueof: %s\" % (${exp}))" "$test" {
+       -re "valueof: (\[^\r\n\]*)\[\r\n\]*$gdb_prompt $" {
+           set val $expect_out(1,string)
+           pass "$test ($val)"
+       }
+       timeout {
+           fail "$test (timeout)"
+       }
+    }
+    return ${val}
+}