This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH 1/4] python support for fetching separate debug files: build_id
- From: Doug Evans <dje at google dot com>
- To: Eli Zaretskii <eliz at gnu dot org>, gdb-patches at sourceware dot org
- Date: Fri, 5 Dec 2014 10:36:30 -0800
- Subject: Re: [PATCH 1/4] python support for fetching separate debug files: build_id
- Authentication-results: sourceware.org; auth=none
- References: <yjt2fvddo9gy dot fsf at ruffy dot mtv dot corp dot google dot com> <838uj557ez dot fsf at gnu dot org>
Eli Zaretskii writes:
> > From: Doug Evans <dje@google.com>
> > Date: Thu, 20 Nov 2014 13:20:13 -0800
> >
> > This patch just provides a Python API call to fetch the build id from
> > objfiles. In my use-case separate debug files are looked up via the
> > build id.
>
> OK for the documentation parts.
>
> Thanks.
Thanks.
Here is what I committed.
[no real change from original]
commit 7c50a93137df660f7b2d9d68c0db748a9cb7868f
Author: Doug Evans <dje@google.com>
Date: Thu Dec 4 11:32:24 2014 -0800
New python attribute gdb.Objfile.build_id.
gdb/ChangeLog:
* NEWS: Mention gdb.Objfile.build_id.
* build-id.c (build_id_bfd_get): Make non-static.
* build-id.h (build_id_bfd_get): Add declaration.
* python/py-objfile.c: #include "build-id.h", "elf-bfd.h".
(OBJFPY_REQUIRE_VALID): New macro.
(objfpy_get_build_id): New function.
(objfile_getset): Add "build_id".
* utils.c (make_hex_string): New function.
* utils.h (make_hex_string): Add declaration.
gdb/doc/ChangeLog:
* python.texi (Objfiles In Python): Document Objfile.build_id.
gdb/testsuite/ChangeLog:
* lib/gdb.exp (get_build_id): New function.
(build_id_debug_filename_get): Rewrite to use it.
* gdb.python/py-objfile.exp: Add test for objfile.build_id.
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 352d107..e6da0b5 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,15 @@
+2014-12-04 Doug Evans <dje@google.com>
+
+ * NEWS: Mention gdb.Objfile.build_id.
+ * build-id.c (build_id_bfd_get): Make non-static.
+ * build-id.h (build_id_bfd_get): Add declaration.
+ * python/py-objfile.c: #include "build-id.h", "elf-bfd.h".
+ (OBJFPY_REQUIRE_VALID): New macro.
+ (objfpy_get_build_id): New function.
+ (objfile_getset): Add "build_id".
+ * utils.c (make_hex_string): New function.
+ * utils.h (make_hex_string): Add declaration.
+
2014-12-04 Jan Kratochvil <jan.kratochvil@redhat.com>
* block.c (block_lookup_symbol_primary): New function.
diff --git a/gdb/NEWS b/gdb/NEWS
index 7262502..16ed91e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -21,6 +21,8 @@
** New attribute 'producer' for gdb.Symtab objects.
** gdb.Objfile objects have a new attribute "progspace",
which is the gdb.Progspace object of the containing program space.
+ ** gdb.Objfile objects have a new attribute "build_id",
+ which is the build ID generated when the file was built.
** 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.
diff --git a/gdb/build-id.c b/gdb/build-id.c
index 0f553ce..5c1f415 100644
--- a/gdb/build-id.c
+++ b/gdb/build-id.c
@@ -27,9 +27,9 @@
#include "objfiles.h"
#include "filenames.h"
-/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */
+/* See build-id.h. */
-static const struct elf_build_id *
+const struct elf_build_id *
build_id_bfd_get (bfd *abfd)
{
if (!bfd_check_format (abfd, bfd_object)
diff --git a/gdb/build-id.h b/gdb/build-id.h
index ddd2645..548ea5e 100644
--- a/gdb/build-id.h
+++ b/gdb/build-id.h
@@ -20,6 +20,10 @@
#ifndef BUILD_ID_H
#define BUILD_ID_H
+/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */
+
+extern const struct elf_build_id *build_id_bfd_get (bfd *abfd);
+
/* Return true if ABFD has NT_GNU_BUILD_ID matching the CHECK value.
Otherwise, issue a warning and return false. */
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 08b49f5..7f36a31 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2014-12-04 Doug Evans <dje@google.com>
+
+ * python.texi (Objfiles In Python): Document Objfile.build_id.
+
2014-12-02 Nick Bull <nicholaspbull@gmail.com>
* python.texi (Events In Python): Document new events
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 63db2b2..a951410 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3495,6 +3495,17 @@ class.
The file name of the objfile as a string.
@end defvar
+@defvar Objfile.build_id
+The build ID of the objfile as a string.
+If the objfile does not have a build ID then the value is @code{None}.
+
+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 defvar
+
@defvar Objfile.progspace
The containing program space of the objfile as a @code{gdb.Progspace}
object. @xref{Progspaces In Python}.
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index c99de87..05a7c21 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -22,6 +22,8 @@
#include "charset.h"
#include "objfiles.h"
#include "language.h"
+#include "build-id.h"
+#include "elf-bfd.h"
typedef struct
{
@@ -51,9 +53,21 @@ static PyTypeObject objfile_object_type
static const struct objfile_data *objfpy_objfile_data_key;
+/* Require that OBJF be a valid objfile. */
+#define OBJFPY_REQUIRE_VALID(obj) \
+ do { \
+ if (!(obj)->objfile) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ _("Objfile no longer exists.")); \
+ return NULL; \
+ } \
+ } while (0)
+
/* An Objfile method which returns the objfile's file name, or None. */
+
static PyObject *
objfpy_get_filename (PyObject *self, void *closure)
{
@@ -66,6 +80,38 @@ objfpy_get_filename (PyObject *self, void *closure)
Py_RETURN_NONE;
}
+/* An Objfile method which returns the objfile's build id, or None. */
+
+static PyObject *
+objfpy_get_build_id (PyObject *self, void *closure)
+{
+ objfile_object *obj = (objfile_object *) self;
+ struct objfile *objfile = obj->objfile;
+ const struct elf_build_id *build_id = NULL;
+ volatile struct gdb_exception except;
+
+ OBJFPY_REQUIRE_VALID (obj);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ build_id = build_id_bfd_get (objfile->obfd);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (build_id != NULL)
+ {
+ char *hex_form = make_hex_string (build_id->data, build_id->size);
+ PyObject *result;
+
+ result = PyString_Decode (hex_form, strlen (hex_form),
+ host_charset (), NULL);
+ xfree (hex_form);
+ return result;
+ }
+
+ Py_RETURN_NONE;
+}
+
/* An Objfile method which returns the objfile's progspace, or None. */
static PyObject *
@@ -364,6 +410,8 @@ static PyGetSetDef objfile_getset[] =
"The __dict__ for this objfile.", &objfile_object_type },
{ "filename", objfpy_get_filename, NULL,
"The objfile's filename, or None.", NULL },
+ { "build_id", objfpy_get_build_id, NULL,
+ "The objfile's build id, or None.", NULL },
{ "progspace", objfpy_get_progspace, NULL,
"The objfile's progspace, or None.", NULL },
{ "pretty_printers", objfpy_get_printers, objfpy_set_printers,
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index f1584e0..b19a5c0 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2014-12-04 Doug Evans <dje@google.com>
+
+ * lib/gdb.exp (get_build_id): New function.
+ (build_id_debug_filename_get): Rewrite to use it.
+ * gdb.python/py-objfile.exp: Add test for objfile.build_id.
+
2014-12-04 Maciej W. Rozycki <macro@codesourcery.com>
* gdb.cp/expand-psymtabs-cxx.exp: Accept any address of
diff --git a/gdb/testsuite/gdb.python/py-objfile.exp b/gdb/testsuite/gdb.python/py-objfile.exp
index 7bf41ed..74384ed 100644
--- a/gdb/testsuite/gdb.python/py-objfile.exp
+++ b/gdb/testsuite/gdb.python/py-objfile.exp
@@ -39,6 +39,16 @@ gdb_py_test_silent_cmd "python objfile = sym\[0\].symtab.objfile" \
gdb_test "python print (objfile.filename)" ".*py-objfile.*" \
"Get objfile file name"
+
+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"
+} else {
+ unsupported "build-id is not supported by the compiler"
+}
+
gdb_test "python print (objfile.progspace)" "<gdb\.Progspace object at .*>" \
"Get objfile program space"
gdb_test "python print (objfile.is_valid())" "True" \
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 2c79bc1..a29b661 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4330,14 +4330,14 @@ gdb_caching_proc gdb_has_argv0 {
# foo.debug --> foo's debug info
# foo --> like foo, but with a new .gnu_debuglink section pointing to foo.debug.
-# Return the build-id hex string (usually 160 bits as 40 hex characters)
-# converted to the form: .build-id/ab/cdef1234...89.debug
-# Return "" if no build-id found.
-proc build_id_debug_filename_get { exec } {
- set tmp [standard_output_file "${exec}-tmp"]
+# Fetch the build id from the file.
+# Returns "" if there is none.
+
+proc get_build_id { filename } {
+ set tmp [standard_output_file "${filename}-tmp"]
set objcopy_program [gdb_find_objcopy]
- set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $exec $tmp" output]
+ set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output]
verbose "result is $result"
verbose "output is $output"
if {$result == 1} {
@@ -4355,6 +4355,17 @@ proc build_id_debug_filename_get { exec } {
}
# Convert it to hex.
binary scan $data H* data
+ return $data
+}
+
+# Return the build-id hex string (usually 160 bits as 40 hex characters)
+# converted to the form: .build-id/ab/cdef1234...89.debug
+# Return "" if no build-id found.
+proc build_id_debug_filename_get { filename } {
+ set data [get_build_id $filename]
+ if { $data == "" } {
+ return ""
+ }
regsub {^..} $data {\0/} data
return ".build-id/${data}.debug"
}
diff --git a/gdb/utils.c b/gdb/utils.c
index 1f5f4f4..1ab183c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1112,6 +1112,23 @@ gdb_print_host_address (const void *addr, struct ui_file *stream)
{
fprintf_filtered (stream, "%s", host_address_to_string (addr));
}
+
+/* See utils.h. */
+
+char *
+make_hex_string (const gdb_byte *data, size_t length)
+{
+ char *result = xmalloc (length * 2 + 1);
+ char *p;
+ size_t i;
+
+ p = result;
+ for (i = 0; i < length; ++i)
+ p += sprintf (p, "%02x", data[i]);
+ *p = '\0';
+ return result;
+}
+
/* A cleanup function that calls regfree. */
diff --git a/gdb/utils.h b/gdb/utils.h
index 1568011..660b548 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -369,4 +369,9 @@ extern void warn_cant_dump_core (const char *reason);
extern void dump_core (void);
+/* Return the hex string form of LENGTH bytes of DATA.
+ Space for the result is malloc'd, caller must free. */
+
+extern char *make_hex_string (const gdb_byte *data, size_t length);
+
#endif /* UTILS_H */