From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 485 invoked by alias); 10 Mar 2013 21:09:08 -0000 Received: (qmail 444 invoked by uid 22791); 10 Mar 2013 21:09:07 -0000 X-SWARE-Spam-Status: No, hits=-7.4 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_SPAMHAUS_DROP,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,RP_MATCHES_RCVD,SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 10 Mar 2013 21:08:51 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r2AL8nYO024617 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sun, 10 Mar 2013 17:08:49 -0400 Received: from host2.jankratochvil.net (ovpn-116-31.ams2.redhat.com [10.36.116.31]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r2AL8heD031000 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Sun, 10 Mar 2013 17:08:46 -0400 Date: Sun, 10 Mar 2013 21:09:00 -0000 From: Jan Kratochvil To: Aleksandar Ristovski Cc: "gdb-patches@sourceware.org" Subject: [draft patch 6/6] gdbserver build-id attribute generator (unfixed) Message-ID: <20130310210843.GG21130@host2.jankratochvil.net> References: <51278984.3070208@qnx.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <51278984.3070208@qnx.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2013-03/txt/msg00438.txt.bz2 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40179,6 +40179,9 @@ memory address. It is a displacement of absolute memory address against address the file was prelinked to during the library load. @item @code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment +@item +@code{build-id}, hex encoded @code{.note.gnu.build-id} section, if such +section exists. @end itemize Additionally the single @code{main-lm} attribute specifies address of @@ -40196,7 +40199,7 @@ looks like this: + l_ld="0x152350" build-id="9afccf7cc41e6293476223fe72480854"/> @end smallexample @@ -40212,6 +40215,7 @@ The format of an SVR4 library list is described by this DTD: + @end smallexample @node Memory Map Format --- a/gdb/features/library-list-svr4.dtd +++ b/gdb/features/library-list-svr4.dtd @@ -14,3 +14,4 @@ + --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -20,6 +20,7 @@ #include "linux-low.h" #include "linux-osdata.h" #include "agent.h" +#include "linux-maps.h" #include "gdb_wait.h" #include @@ -5639,6 +5640,149 @@ struct link_map_offsets int l_prev_offset; }; +struct find_memory_region_callback_data +{ + unsigned is_elf64 : 1; + const char *soname; + CORE_ADDR l_addr; + + /* Return. Meaningful iff *build_id != NULL. */ + size_t build_idsz; + + /* Return. malloc allocated memory. */ + void *build_id; +}; + +static linux_find_memory_region_ftype find_memory_region_callback; + +static int +find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset, + ULONGEST inode, int read, int write, int exec, + int modified, const char *filename, void *data) +{ + struct find_memory_region_callback_data *p = data; + + if (filename != NULL && strcmp (filename, p->soname) == 0) + { + union ElfXX_Ehdr + { + Elf32_Ehdr _32; + Elf64_Ehdr _64; + } ehdr; + union ElfXX_Phdr + { + Elf32_Phdr _32; + Elf64_Phdr _64; + } phdr; + union ElfXX_Nhdr + { + Elf32_Nhdr _32; + Elf64_Nhdr _64; + } *nhdr; +#define HDR(p, hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld) + if (linux_read_memory (vaddr, (unsigned char *) &ehdr, sizeof (ehdr)) + == 0 + && HDR (p, ehdr, e_ident[EI_MAG0]) == ELFMAG0 + && HDR (p, ehdr, e_ident[EI_MAG1]) == ELFMAG1 + && HDR (p, ehdr, e_ident[EI_MAG2]) == ELFMAG2 + && HDR (p, ehdr, e_ident[EI_MAG3]) == ELFMAG3) + { + unsigned i; + + for (i = 0; i < HDR (p, ehdr, e_phnum); ++i) + { + if (linux_read_memory (vaddr + HDR (p, ehdr, e_phoff) + + HDR (p, ehdr, e_phentsize) * i, + (unsigned char *) &phdr, + HDR (p, ehdr, e_phentsize)) != 0) + { + warning ("Could not read program header."); + break; + } + if (HDR (p, phdr, p_type) == PT_NOTE) + { + nhdr = xmalloc (HDR (p, phdr, p_memsz)); + + if (linux_read_memory (p->l_addr + HDR (p, phdr, p_vaddr), + (unsigned char *) nhdr, + HDR (p, phdr, p_memsz)) != 0) + { + warning ("Could not read note."); + break; + } + if (HDR (p, *nhdr, n_type) == NT_GNU_BUILD_ID) + { + p->build_idsz = (HDR (p, *nhdr, n_namesz) + + HDR (p, *nhdr, n_descsz) + + (p->is_elf64 + ? sizeof (nhdr->_64) + : sizeof (nhdr->_32))); + if (p->build_idsz > HDR (p, phdr, p_memsz)) + { + warning ("NT_GNU_BUILD_ID has invalid size.."); + break; + } + p->build_id = nhdr; + break; + } + free (nhdr); + } + } + } + else + warning ("Reading build-id failed."); + + return 1; + } +#undef HDR + return 0; +} + +/* Return malloc allocated buffer. User must free it. + + NULL may be returned if build-id could not be fetched. */ + +static char * +get_hex_build_id (const char *const soname, const int is_elf64, + const CORE_ADDR l_addr) +{ + struct find_memory_region_callback_data data; + char *hex_build_id; + char *real_soname = realpath (soname, NULL); + + if (real_soname == NULL) + { + fprintf (stderr, "Failed to get realpath of %s (%s).\n", soname, + strerror (errno)); + return NULL; + } + + data.is_elf64 = is_elf64 != 0; + data.soname = real_soname; + data.l_addr = l_addr; + data.build_idsz = 0; + data.build_id = NULL; + + linux_find_memory_regions_full (lwpid_of (get_thread_lwp (current_inferior)), + find_memory_region_callback, &data, NULL); + free (real_soname); + if (data.build_id != NULL) + { + hex_build_id = xmalloc (data->build_idsz * 2 + 1); + if (bin2hex (data.build_id, hex_build_id, data->build_idsz) + != data->build_idsz) + { + fprintf (stderr, "Hex encoding of build-id failed\n"); + xfree (hex_build_id); + hex_build_id = NULL; + } + } + else + hex_build_id = NULL; + free (data.build_id); + return hex_build_id; +} + /* Construct qXfer:libraries-svr4:read reply. */ static int @@ -5760,6 +5904,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, /* 6x the size for xml_escape_text below. */ size_t len = 6 * strlen ((char *) libname); char *name; + char *hex_enc_build_id; if (!header_done) { @@ -5768,7 +5913,12 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, header_done = 1; } - while (allocated < p - document + len + 200) + name = xml_escape_text ((char *) libname); + hex_enc_build_id = get_hex_build_id (name, is_elf64, l_addr); + + while (allocated < (p - document + len + 200 + + (hex_enc_build_id != NULL + ? strlen (hex_enc_build_id) : 0))) { /* Expand to guarantee sufficient storage. */ uintptr_t document_len = p - document; @@ -5778,12 +5928,15 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, p = document + document_len; } - name = xml_escape_text ((char *) libname); p += sprintf (p, "", + "l_addr=\"0x%lx\" l_ld=\"0x%lx\"", name, (unsigned long) lm_addr, (unsigned long) l_addr, (unsigned long) l_ld); + if (hex_enc_build_id != NULL) + p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id); + p += sprintf(p, "/>"); free (name); + xfree (hex_enc_build_id); } else if (lm_prev == 0) {