From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20560 invoked by alias); 22 Mar 2013 13:05:15 -0000 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 Received: (qmail 18282 invoked by uid 89); 22 Mar 2013 13:04:29 -0000 X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL,BAYES_00,TW_CP autolearn=ham version=3.3.1 Received: from na3sys009aog138.obsmtp.com (HELO na3sys009aog138.obsmtp.com) (74.125.149.19) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Fri, 22 Mar 2013 13:04:24 +0000 Received: from mx20.qnx.com ([72.1.200.103]) (using TLSv1) by na3sys009aob138.postini.com ([74.125.148.12]) with SMTP ID DSNKUUxW1yku8jH5an9FO8Vtb3tv3cbg5Wo6@postini.com; Fri, 22 Mar 2013 06:04:24 PDT Received: by mx20.qnx.com (Postfix, from userid 500) id 62DDC20E3B; Fri, 22 Mar 2013 09:04:22 -0400 (EDT) Received: from exhts.ott.qnx.com (exch2 [10.222.2.136]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) by mx20.qnx.com (Postfix) with ESMTPS id 97F6520A6D; Fri, 22 Mar 2013 09:04:21 -0400 (EDT) Received: from [10.222.96.215] (10.222.2.5) by exch2.ott.qnx.com (10.222.2.136) with Microsoft SMTP Server id 14.2.318.4; Fri, 22 Mar 2013 09:04:21 -0400 Message-ID: <514C56D4.1060906@qnx.com> Date: Fri, 22 Mar 2013 13:05:00 -0000 From: Aleksandar Ristovski User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130308 Thunderbird/17.0.4 MIME-Version: 1.0 Newsgroups: gmane.comp.gdb.patches To: Jan Kratochvil CC: "gdb-patches@sourceware.org" Subject: Re: [patch 6/6] gdbserver build-id attribute generator References: <51278984.3070208@qnx.com> <20130310210843.GG21130@host2.jankratochvil.net> In-Reply-To: <20130310210843.GG21130@host2.jankratochvil.net> Content-Type: multipart/mixed; boundary="------------000305000903050809000608" X-Virus-Found: No X-SW-Source: 2013-03/txt/msg00839.txt.bz2 --------------000305000903050809000608 Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit Content-length: 754 This is the final patch that does actual addition of build-id attribute to qxfer_libraries. * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add 'build-id' in description, example, new attribute in dtd. * linux-low.c (linux-maps.h, search.h): Include. (struct build_id_list): New structure. (build_id_list_s): New typedef, new vector type def. (free_build_id_list, compare_build_id_list, compare_build_id_list_range, compare_build_id_list_inode): New. (struct find_memory_region_callback_data): New. (find_memory_region_callback): New fwd. declaration. (read_build_id, find_memory_region_callback, get_hex_build_id): New. (linux_qxfer_libraries_svr4): Add optional build-id attribute to reply XML document. Thanks, Aleksandar --------------000305000903050809000608 Content-Type: text/x-patch; name="0006-gdbserver-linux_qxfer_libraries_svr4-return-build-id.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0006-gdbserver-linux_qxfer_libraries_svr4-return-build-id.pa"; filename*1="tch" Content-length: 11817 diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 4ac28bb..5ff9e95 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40404,6 +40404,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 @@ -40421,7 +40424,7 @@ looks like this: + l_ld="0x152350" build-id="9afccf7cc41e6293476223fe72480854"/> @end smallexample @@ -40437,6 +40440,7 @@ The format of an SVR4 library list is described by this DTD: + @end smallexample @node Memory Map Format diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd index cae7fd8..e4409ba 100644 --- a/gdb/features/library-list-svr4.dtd +++ b/gdb/features/library-list-svr4.dtd @@ -14,3 +14,4 @@ + diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 523926d..8bbb5ba 100644 --- 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 @@ -43,6 +44,7 @@ #include "gdb_stat.h" #include #include +#include #ifndef ELFMAG0 /* Don't include here. If it got included by gdb_proc_service.h then ELFMAG0 will have been defined. If it didn't get included by @@ -5643,6 +5645,265 @@ struct link_map_offsets int l_prev_offset; }; + +/* Structure for holding all mappings. Only mapping + containing l_ld can have hex_build_id set. */ + +struct build_id_list +{ + ULONGEST vaddr; + + ULONGEST size; + + ULONGEST offset; + + ULONGEST inode; + + const char *filename; + int read:1; + int write:1; + int exec:1; + int modified:1; + + /* build_id is hex encoded string allocated using malloc, and + needs to be freed. */ + + char *hex_build_id; +}; + +typedef struct build_id_list build_id_list_s; + +DEF_VEC_O(build_id_list_s); + +static void +free_build_id_list (VEC (build_id_list_s) *lst) +{ + if (VEC_length (build_id_list_s, lst)) + { + int ix; + build_id_list_s *p; + + for (ix = 0; VEC_iterate (build_id_list_s, lst, ix, p); ++ix) + xfree (p->hex_build_id); + } + + VEC_free (build_id_list_s, lst); +} + +/* Used for qsort-ing list by vaddr. */ + +static int +compare_build_id_list (const void *const b1, + const void *const b2) +{ + const build_id_list_s *const p1 = b1; + const build_id_list_s *const p2 = b2; + + if (p1->vaddr > p2->vaddr) + return 1; + if (p1->vaddr < p2->vaddr) + return -1; + return 0; +} + +/* Used for finding a mapping containing the given + l_ld passed in K. */ + +static int +compare_build_id_list_range (const void *const k, + const void *const b) +{ + const ULONGEST key = *(CORE_ADDR*) k; + const build_id_list_s *const p = b; + + if (key < p->vaddr) + return -1; + + if (key < p->vaddr + p->size) + return 0; + + return 1; +} + +/* Used for linear search of the lowest vaddr for the given + inode. */ + +static int +compare_build_id_list_inode (const void *const k, const void *const b) +{ + const ULONGEST key = *(ULONGEST*)k; + const build_id_list_s *const p = b; + + return !(key == p->inode); +} + +struct find_memory_region_callback_data { + unsigned is_elf64; + + /* Return. Ordered list of all object mappings sorted in + ascending order by VADDR. Must be freed with free_build_id_list. */ + VEC (build_id_list_s) *list; +}; + +static linux_find_memory_region_ftype find_memory_region_callback; + +/* Read .note.gnu.build-id from PT_NOTE. */ + +static void +read_build_id (struct find_memory_region_callback_data *const p, + build_id_list_s *const bil, const CORE_ADDR load_addr, + const CORE_ADDR l_addr) +{ + 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(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld) +#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32)) + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (ehdr)) + == 0 + && HDR (ehdr, e_ident[EI_MAG0]) == ELFMAG0 + && HDR (ehdr, e_ident[EI_MAG1]) == ELFMAG1 + && HDR (ehdr, e_ident[EI_MAG2]) == ELFMAG2 + && HDR (ehdr, e_ident[EI_MAG3]) == ELFMAG3) + { + unsigned i; + + for (i = 0; i < HDR (ehdr, e_phnum); ++i) + { + if (linux_read_memory (load_addr + HDR (ehdr, e_phoff) + + HDR (ehdr, e_phentsize) * i, + (unsigned char *) &phdr, + HDR (ehdr, e_phentsize)) != 0) + { + warning ("Could not read program header."); + break; + } + if (HDR (phdr, p_type) == PT_NOTE) + { + void *const pt_note = xmalloc (HDR (phdr, p_memsz)); + const void *const pt_end + = (char*)pt_note + HDR (phdr, p_memsz); + + if (linux_read_memory (HDR (phdr, p_vaddr) + l_addr, + pt_note, HDR (phdr, p_memsz)) != 0) + { + xfree (pt_note); + warning ("Could not read note."); + break; + } + + for (nhdr = pt_note; (void*)nhdr < pt_end;) + { + const size_t note_sz + = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz) + + SIZEOFHDR (*nhdr); + + if ((char*)nhdr + note_sz > (char*)pt_end) + { + warning ("Malformed PT_NOTE\n"); + break; + } + if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID) + { + /* .note.gnu.build-id. */ + bil->hex_build_id = xmalloc (note_sz * 2 + 1); + bin2hex ((gdb_byte*)nhdr, bil->hex_build_id, note_sz); + xfree (pt_note); + return; + } + nhdr = (void*)((char *)nhdr + note_sz); + } + xfree (pt_note); + } + } + } + else + warning ("Reading build-id failed."); +#undef HDR +#undef SIZEOFHDR +} + + +/* Create list of build_id_list. */ + +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) +{ + if (inode != 0) + { + struct find_memory_region_callback_data *const p = data; + build_id_list_s bil; + + bil.vaddr = vaddr; + bil.size = size; + bil.inode = inode; + bil.read = !(read == 0); + bil.write = !(write == 0); + bil.exec = !(write == 0); + bil.modified = !(write == 0); + bil.filename = filename; + bil.hex_build_id = NULL; + + VEC_safe_push (build_id_list_s, p->list, &bil); + } + + return 0; +} + +/* Get build-id for the given L_LD. DATA must point to + already filled list of build_id_list elements. + + Return build_id as stored in the list element corresponding + to L_LD. + + NULL may be returned if build-id could not be fetched. + + Returned string must not be freed explicitly. +*/ + +static const char * +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld, + struct find_memory_region_callback_data *const data) +{ + build_id_list_s *const bil + = bsearch (&l_ld, VEC_address (build_id_list_s, data->list), + VEC_length (build_id_list_s, data->list), + sizeof (build_id_list_s), compare_build_id_list_range); + + if (bil == NULL) + return NULL; + + if (bil->hex_build_id == NULL) + { + CORE_ADDR load_addr; + size_t len = VEC_length (build_id_list_s, data->list); + + /* Must do linear search for the first mapping of this inode. */ + build_id_list_s *const bil_min + = lfind (&bil->inode, VEC_address (build_id_list_s, data->list), &len, + sizeof (build_id_list_s), compare_build_id_list_inode); + gdb_assert (bil_min != NULL && "This should never happen."); + load_addr = bil_min->vaddr; + read_build_id (data, bil, load_addr, l_addr); + } + + return bil->hex_build_id; +} + /* Construct qXfer:libraries-svr4:read reply. */ static int @@ -5655,6 +5916,8 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, struct process_info_private *const priv = current_process ()->private; char filename[PATH_MAX]; int pid, is_elf64; + struct find_memory_region_callback_data data; + int build_id_list_p; static const struct link_map_offsets lmo_32bit_offsets = { @@ -5690,6 +5953,19 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, is_elf64 = elf_64_file_p (filename, &machine); lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; + data.is_elf64 = is_elf64; + data.list = NULL; + VEC_reserve (build_id_list_s, data.list, 16); + build_id_list_p + = linux_find_memory_regions_full ( + lwpid_of (get_thread_lwp (current_inferior)), + find_memory_region_callback, &data, NULL) >= 0; + + if (build_id_list_p) + qsort (VEC_address (build_id_list_s, data.list), + VEC_length (build_id_list_s, data.list), + sizeof (build_id_list_s), compare_build_id_list); + if (priv->r_debug == 0) priv->r_debug = get_r_debug (pid, is_elf64); @@ -5764,6 +6040,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; + const char *hex_enc_build_id = NULL; if (!header_done) { @@ -5772,21 +6049,29 @@ 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); + if (build_id_list_p) + hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data); + + 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; + const ptrdiff_t document_len = p - document; - document = xrealloc (document, 2 * allocated); allocated *= 2; + document = xrealloc (document, allocated); 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); } else if (lm_prev == 0) @@ -5821,6 +6106,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, memcpy (readbuf, document + offset, len); xfree (document); + free_build_id_list (data.list); return len; } -- 1.7.10.4 --------------000305000903050809000608-- From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32385 invoked by alias); 22 Mar 2013 13:20:44 -0000 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 Received: (qmail 32123 invoked by uid 89); 22 Mar 2013 13:19:49 -0000 X-Spam-SWARE-Status: No, score=-1.1 required=5.0 tests=AWL,BAYES_00,FSL_HELO_BARE_IP_2,RCVD_IN_DNSWL_NONE,RCVD_NUMERIC_HELO,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_CP autolearn=no version=3.3.1 Received: from plane.gmane.org (HELO plane.gmane.org) (80.91.229.3) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Fri, 22 Mar 2013 13:19:45 +0000 Received: from list by plane.gmane.org with local (Exim 4.69) (envelope-from ) id 1UJ1t6-00017G-Po for gdb-patches@sourceware.org; Fri, 22 Mar 2013 14:20:04 +0100 Received: from 209.226.137.106 ([209.226.137.106]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 22 Mar 2013 14:20:04 +0100 Received: from aristovski by 209.226.137.106 with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 22 Mar 2013 14:20:04 +0100 To: gdb-patches@sourceware.org From: Aleksandar Ristovski Subject: Re: [patch 6/6] gdbserver build-id attribute generator Date: Fri, 22 Mar 2013 15:19:00 -0000 Message-ID: <514C56D4.1060906@qnx.com> References: <51278984.3070208@qnx.com> <20130310210843.GG21130@host2.jankratochvil.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------000305000903050809000608" Cc: "gdb-patches@sourceware.org" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130308 Thunderbird/17.0.4 In-Reply-To: <20130310210843.GG21130@host2.jankratochvil.net> X-Virus-Found: No X-SW-Source: 2013-03/txt/msg00848.txt.bz2 Message-ID: <20130322151900.OQLc4PNPVlgvQ-fNzOmYfep4ekTo-lLnvWVrMjqsSYM@z> This is a multi-part message in MIME format. --------------000305000903050809000608 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 754 This is the final patch that does actual addition of build-id attribute to qxfer_libraries. * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add 'build-id' in description, example, new attribute in dtd. * linux-low.c (linux-maps.h, search.h): Include. (struct build_id_list): New structure. (build_id_list_s): New typedef, new vector type def. (free_build_id_list, compare_build_id_list, compare_build_id_list_range, compare_build_id_list_inode): New. (struct find_memory_region_callback_data): New. (find_memory_region_callback): New fwd. declaration. (read_build_id, find_memory_region_callback, get_hex_build_id): New. (linux_qxfer_libraries_svr4): Add optional build-id attribute to reply XML document. Thanks, Aleksandar --------------000305000903050809000608 Content-Type: text/x-patch; name="0006-gdbserver-linux_qxfer_libraries_svr4-return-build-id.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0006-gdbserver-linux_qxfer_libraries_svr4-return-build-id.pa"; filename*1="tch" Content-length: 11817 diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 4ac28bb..5ff9e95 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40404,6 +40404,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 @@ -40421,7 +40424,7 @@ looks like this: + l_ld="0x152350" build-id="9afccf7cc41e6293476223fe72480854"/> @end smallexample @@ -40437,6 +40440,7 @@ The format of an SVR4 library list is described by this DTD: + @end smallexample @node Memory Map Format diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd index cae7fd8..e4409ba 100644 --- a/gdb/features/library-list-svr4.dtd +++ b/gdb/features/library-list-svr4.dtd @@ -14,3 +14,4 @@ + diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 523926d..8bbb5ba 100644 --- 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 @@ -43,6 +44,7 @@ #include "gdb_stat.h" #include #include +#include #ifndef ELFMAG0 /* Don't include here. If it got included by gdb_proc_service.h then ELFMAG0 will have been defined. If it didn't get included by @@ -5643,6 +5645,265 @@ struct link_map_offsets int l_prev_offset; }; + +/* Structure for holding all mappings. Only mapping + containing l_ld can have hex_build_id set. */ + +struct build_id_list +{ + ULONGEST vaddr; + + ULONGEST size; + + ULONGEST offset; + + ULONGEST inode; + + const char *filename; + int read:1; + int write:1; + int exec:1; + int modified:1; + + /* build_id is hex encoded string allocated using malloc, and + needs to be freed. */ + + char *hex_build_id; +}; + +typedef struct build_id_list build_id_list_s; + +DEF_VEC_O(build_id_list_s); + +static void +free_build_id_list (VEC (build_id_list_s) *lst) +{ + if (VEC_length (build_id_list_s, lst)) + { + int ix; + build_id_list_s *p; + + for (ix = 0; VEC_iterate (build_id_list_s, lst, ix, p); ++ix) + xfree (p->hex_build_id); + } + + VEC_free (build_id_list_s, lst); +} + +/* Used for qsort-ing list by vaddr. */ + +static int +compare_build_id_list (const void *const b1, + const void *const b2) +{ + const build_id_list_s *const p1 = b1; + const build_id_list_s *const p2 = b2; + + if (p1->vaddr > p2->vaddr) + return 1; + if (p1->vaddr < p2->vaddr) + return -1; + return 0; +} + +/* Used for finding a mapping containing the given + l_ld passed in K. */ + +static int +compare_build_id_list_range (const void *const k, + const void *const b) +{ + const ULONGEST key = *(CORE_ADDR*) k; + const build_id_list_s *const p = b; + + if (key < p->vaddr) + return -1; + + if (key < p->vaddr + p->size) + return 0; + + return 1; +} + +/* Used for linear search of the lowest vaddr for the given + inode. */ + +static int +compare_build_id_list_inode (const void *const k, const void *const b) +{ + const ULONGEST key = *(ULONGEST*)k; + const build_id_list_s *const p = b; + + return !(key == p->inode); +} + +struct find_memory_region_callback_data { + unsigned is_elf64; + + /* Return. Ordered list of all object mappings sorted in + ascending order by VADDR. Must be freed with free_build_id_list. */ + VEC (build_id_list_s) *list; +}; + +static linux_find_memory_region_ftype find_memory_region_callback; + +/* Read .note.gnu.build-id from PT_NOTE. */ + +static void +read_build_id (struct find_memory_region_callback_data *const p, + build_id_list_s *const bil, const CORE_ADDR load_addr, + const CORE_ADDR l_addr) +{ + 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(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld) +#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32)) + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (ehdr)) + == 0 + && HDR (ehdr, e_ident[EI_MAG0]) == ELFMAG0 + && HDR (ehdr, e_ident[EI_MAG1]) == ELFMAG1 + && HDR (ehdr, e_ident[EI_MAG2]) == ELFMAG2 + && HDR (ehdr, e_ident[EI_MAG3]) == ELFMAG3) + { + unsigned i; + + for (i = 0; i < HDR (ehdr, e_phnum); ++i) + { + if (linux_read_memory (load_addr + HDR (ehdr, e_phoff) + + HDR (ehdr, e_phentsize) * i, + (unsigned char *) &phdr, + HDR (ehdr, e_phentsize)) != 0) + { + warning ("Could not read program header."); + break; + } + if (HDR (phdr, p_type) == PT_NOTE) + { + void *const pt_note = xmalloc (HDR (phdr, p_memsz)); + const void *const pt_end + = (char*)pt_note + HDR (phdr, p_memsz); + + if (linux_read_memory (HDR (phdr, p_vaddr) + l_addr, + pt_note, HDR (phdr, p_memsz)) != 0) + { + xfree (pt_note); + warning ("Could not read note."); + break; + } + + for (nhdr = pt_note; (void*)nhdr < pt_end;) + { + const size_t note_sz + = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz) + + SIZEOFHDR (*nhdr); + + if ((char*)nhdr + note_sz > (char*)pt_end) + { + warning ("Malformed PT_NOTE\n"); + break; + } + if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID) + { + /* .note.gnu.build-id. */ + bil->hex_build_id = xmalloc (note_sz * 2 + 1); + bin2hex ((gdb_byte*)nhdr, bil->hex_build_id, note_sz); + xfree (pt_note); + return; + } + nhdr = (void*)((char *)nhdr + note_sz); + } + xfree (pt_note); + } + } + } + else + warning ("Reading build-id failed."); +#undef HDR +#undef SIZEOFHDR +} + + +/* Create list of build_id_list. */ + +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) +{ + if (inode != 0) + { + struct find_memory_region_callback_data *const p = data; + build_id_list_s bil; + + bil.vaddr = vaddr; + bil.size = size; + bil.inode = inode; + bil.read = !(read == 0); + bil.write = !(write == 0); + bil.exec = !(write == 0); + bil.modified = !(write == 0); + bil.filename = filename; + bil.hex_build_id = NULL; + + VEC_safe_push (build_id_list_s, p->list, &bil); + } + + return 0; +} + +/* Get build-id for the given L_LD. DATA must point to + already filled list of build_id_list elements. + + Return build_id as stored in the list element corresponding + to L_LD. + + NULL may be returned if build-id could not be fetched. + + Returned string must not be freed explicitly. +*/ + +static const char * +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld, + struct find_memory_region_callback_data *const data) +{ + build_id_list_s *const bil + = bsearch (&l_ld, VEC_address (build_id_list_s, data->list), + VEC_length (build_id_list_s, data->list), + sizeof (build_id_list_s), compare_build_id_list_range); + + if (bil == NULL) + return NULL; + + if (bil->hex_build_id == NULL) + { + CORE_ADDR load_addr; + size_t len = VEC_length (build_id_list_s, data->list); + + /* Must do linear search for the first mapping of this inode. */ + build_id_list_s *const bil_min + = lfind (&bil->inode, VEC_address (build_id_list_s, data->list), &len, + sizeof (build_id_list_s), compare_build_id_list_inode); + gdb_assert (bil_min != NULL && "This should never happen."); + load_addr = bil_min->vaddr; + read_build_id (data, bil, load_addr, l_addr); + } + + return bil->hex_build_id; +} + /* Construct qXfer:libraries-svr4:read reply. */ static int @@ -5655,6 +5916,8 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, struct process_info_private *const priv = current_process ()->private; char filename[PATH_MAX]; int pid, is_elf64; + struct find_memory_region_callback_data data; + int build_id_list_p; static const struct link_map_offsets lmo_32bit_offsets = { @@ -5690,6 +5953,19 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, is_elf64 = elf_64_file_p (filename, &machine); lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; + data.is_elf64 = is_elf64; + data.list = NULL; + VEC_reserve (build_id_list_s, data.list, 16); + build_id_list_p + = linux_find_memory_regions_full ( + lwpid_of (get_thread_lwp (current_inferior)), + find_memory_region_callback, &data, NULL) >= 0; + + if (build_id_list_p) + qsort (VEC_address (build_id_list_s, data.list), + VEC_length (build_id_list_s, data.list), + sizeof (build_id_list_s), compare_build_id_list); + if (priv->r_debug == 0) priv->r_debug = get_r_debug (pid, is_elf64); @@ -5764,6 +6040,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; + const char *hex_enc_build_id = NULL; if (!header_done) { @@ -5772,21 +6049,29 @@ 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); + if (build_id_list_p) + hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data); + + 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; + const ptrdiff_t document_len = p - document; - document = xrealloc (document, 2 * allocated); allocated *= 2; + document = xrealloc (document, allocated); 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); } else if (lm_prev == 0) @@ -5821,6 +6106,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, memcpy (readbuf, document + offset, len); xfree (document); + free_build_id_list (data.list); return len; } -- 1.7.10.4 --------------000305000903050809000608--