From patchwork Thu Nov 20 21:20:13 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 3818 Received: (qmail 580 invoked by alias); 20 Nov 2014 21:20:19 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 568 invoked by uid 89); 20 Nov 2014 21:20:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS, T_RP_MATCHES_RCVD, UNSUBSCRIBE_BODY autolearn=no version=3.3.2 X-HELO: mail-pd0-f202.google.com Received: from mail-pd0-f202.google.com (HELO mail-pd0-f202.google.com) (209.85.192.202) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Thu, 20 Nov 2014 21:20:16 +0000 Received: by mail-pd0-f202.google.com with SMTP id v10so638032pde.3 for ; Thu, 20 Nov 2014 13:20:15 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-type; bh=ZxCxICB3pqejHfzRF2uJYFKSsLBmIAEovjoaCQfNvKs=; b=nLxaGynRNWOGSJF95YU49+jm+hDfgU4/HYqND36L7d3ZiEYNmkfCjTzYAoE1iHgRPY 82/s44gVeFdl6WGL1PNSSOwNpOfNUow8yNhHPDeEaPtLYuEQPoS2Ja8OtZE88Pf/Fxwm nWgpVWltHWF1tggfk3F2vYXNRbfbIDEjRK/DXwNd2L+HP+ZvGK14lRQWStwaso2gDIaW 4wGs4f1GGdcNoRsHetLgiJgWUA+0oqKBO/omfpiTaTfTzVd75W6LyPv4j3dbhpbCf/ml S/tMYeiiXj+bwzXgA4lazxLHeONv3qqqRaZmPYI0/s3L4rIvL7Ykb/GhCqfLsafnHyXW jnJA== X-Gm-Message-State: ALoCoQmKyo1SD1mzqGg2yuEKFbBE6+yMvVMLtD1REIMkr0VGiXxqY7GUxiwBSVYEhvuHtX+biSZv X-Received: by 10.70.37.109 with SMTP id x13mr673381pdj.0.1416518415135; Thu, 20 Nov 2014 13:20:15 -0800 (PST) Received: from corpmail-nozzle1-1.hot.corp.google.com ([100.108.1.104]) by gmr-mx.google.com with ESMTPS id b3si846329qcq.2.2014.11.20.13.20.14 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 20 Nov 2014 13:20:15 -0800 (PST) Received: from ruffy.mtv.corp.google.com ([172.17.128.44]) by corpmail-nozzle1-1.hot.corp.google.com with ESMTPS id lZTGVbsp.1; Thu, 20 Nov 2014 13:20:14 -0800 From: Doug Evans To: gdb-patches@sourceware.org, eliz@gnu.org, palves@redhat.com, sergiodj@redhat.com Subject: [PATCH 1/4] python support for fetching separate debug files: build_id Date: Thu, 20 Nov 2014 13:20:13 -0800 Message-ID: MIME-Version: 1.0 X-IsSubscribed: yes 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. 2014-11-20 Doug Evans * 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. doc/ * python.texi (Objfiles In Python): Document Objfile.build_id. testsuite/ * 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/NEWS b/gdb/NEWS index d6a8b61..eecc7da 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -11,6 +11,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/python.texi b/gdb/doc/python.texi index 5b35306..a47a259 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -3446,6 +3446,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/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)" "" \ "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..906bb4e 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 { exec } { + set build_id [get_build_id $exec] + if { $build_id == "" } { + return "" + } regsub {^..} $data {\0/} data return ".build-id/${data}.debug" } diff --git a/gdb/utils.c b/gdb/utils.c index 3915b58..2bfa7ca 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 */