From 6dddd6a5747532ef6e9703432c51680011df4e8d Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Fri, 12 Dec 2014 09:48:13 -0800 Subject: [PATCH] New python function gdb.lookup_objfile. 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 | 11 ++ gdb/NEWS | 1 + gdb/doc/ChangeLog | 4 + gdb/doc/python.texi | 21 ++++ gdb/python/py-objfile.c | 142 ++++++++++++++++++++++++ gdb/python/python-internal.h | 1 + gdb/python/python.c | 8 ++ gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.python/py-objfile.exp | 24 +++- gdb/testsuite/lib/gdb-python.exp | 21 ++++ 10 files changed, 237 insertions(+), 1 deletion(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a54e2c1863b..70d46293ec9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2014-12-12 Doug Evans + + * 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 * mips-tdep.h (MSYMBOL_TARGET_FLAG_MIPS16): New macro. diff --git a/gdb/NEWS b/gdb/NEWS index a47dfbf645a..d2c5637ed69 100644 --- 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: diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index b8152df282d..9b36c373bf0 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2014-12-12 Doug Evans + + * python.texi (Objfiles In Python): Document gdb.lookup_objfile. + 2014-12-12 Andreas Arnez * gdb.texinfo: Document "maint print user-registers". diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index efd258d9882..234ce5c5f15 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -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. diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c index d90928bb300..e78cebaeebb 100644 --- a/gdb/python/py-objfile.c +++ b/gdb/python/py-objfile.c @@ -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; +} + /* Clear the OBJFILE pointer in an Objfile object and remove the diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 716c0de4196..544fe932af8 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -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); diff --git a/gdb/python/python.c b/gdb/python/python.c index 1362bd24e5a..b1d82838f32 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -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, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index b21ac451376..22f3ffc85b9 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-12-12 Doug Evans + + * 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 * gdb.base/completion.exp: Add test for completion of "info diff --git a/gdb/testsuite/gdb.python/py-objfile.exp b/gdb/testsuite/gdb.python/py-objfile.exp index f3a8a6c916f..5d3c084e916 100644 --- a/gdb/testsuite/gdb.python/py-objfile.exp +++ b/gdb/testsuite/gdb.python/py-objfile.exp @@ -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)" "" \ "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
" \ "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}" +} diff --git a/gdb/testsuite/lib/gdb-python.exp b/gdb/testsuite/lib/gdb-python.exp index d5e79289b42..eefff733174 100644 --- a/gdb/testsuite/lib/gdb-python.exp +++ b/gdb/testsuite/lib/gdb-python.exp @@ -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} +} -- 2.30.2