From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3024 invoked by alias); 5 Apr 2013 13:03:14 -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 2993 invoked by uid 89); 5 Apr 2013 13:03:13 -0000 X-Spam-SWARE-Status: No, score=-4.2 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,TW_CP,TW_CS autolearn=ham version=3.3.1 Received: from na3sys009aog124.obsmtp.com (HELO na3sys009aog124.obsmtp.com) (74.125.149.151) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Fri, 05 Apr 2013 13:03:09 +0000 Received: from mx10.qnx.com ([209.226.137.110]) (using TLSv1) by na3sys009aob124.postini.com ([74.125.148.12]) with SMTP ID DSNKUV7Liq+xeuOazeun0wiYpgxvyHhgCAAr@postini.com; Fri, 05 Apr 2013 06:03:08 PDT Received: by mx10.qnx.com (Postfix, from userid 500) id 6AAFA20E56; Fri, 5 Apr 2013 09:03:06 -0400 (EDT) Received: from exhts.ott.qnx.com (exch1 [10.222.2.137]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) by mx10.qnx.com (Postfix) with ESMTPS id 7DFFF20E1B; Fri, 5 Apr 2013 09:03:05 -0400 (EDT) Received: from [10.222.96.215] (10.222.2.5) by EXCH1.ott.qnx.com (10.222.2.137) with Microsoft SMTP Server id 14.2.318.4; Fri, 5 Apr 2013 09:03:05 -0400 Message-ID: <515ECB30.5010504@qnx.com> Date: Fri, 05 Apr 2013 15: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> <514C56D4.1060906@qnx.com> <20130326204157.GC12291@host2.jankratochvil.net> <51530465.30503@qnx.com> <20130327145028.GA17905@host2.jankratochvil.net> <515353CF.40601@qnx.com> <5154ADD2.9040206@qnx.com> <20130331174322.GB21374@host2.jankratochvil.net> <515B05D8.1000003@qnx.com> <20130403193258.GA9853@host2.jankratochvil.net> In-Reply-To: <20130403193258.GA9853@host2.jankratochvil.net> Content-Type: multipart/mixed; boundary="------------000902040202040306000702" X-Virus-Found: No X-SW-Source: 2013-04/txt/msg00120.txt.bz2 --------------000902040202040306000702 Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit Content-length: 2754 Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7 On 13-04-03 03:32 PM, Jan Kratochvil wrote: > On Tue, 02 Apr 2013 18:22:48 +0200, Aleksandar Ristovski wrote: >>>> +static int >>>> +find_phdr_p (const void *const phdr, const int is_elf64, >>>> + const void *const data) >>> >>> But I do not understand why this function exists - it could be integrated in >>> find_phdr as very every caller of find_phdr passse as find_phdr_p parameter >>> this find_phdr_p implementation. >> >> >> [AR] Yes, but I am eyeing solib-svr4.c loops over pheaders >> generalization - find_phdr could be moved to 'common' and possibly >> called 'iterate_phdrs' with the ability to pass in any function, not >> necessarily a predicate only. E.g. svr4_exec_displacement, etc...) > > It is not relevant for this patch what do you plan. In the form as is it is > needlessly overcomplicated. That more thorough generalization would be > possibly good but it is not here and it may never happen. GDB will just > remain with needlessly complicated code. > > > >>> You need to check here also the name content, it is "GNU\x00" (n_namesz == 4). >> >> [AR], can it be any other name if type is NT_GNU_BUILD_ID? Added the >> check but seems like an overkill to me. > > NT_GNU_BUILD_ID is just number 3. I find very realistic for example > "SUNW Solaris" would use at least 3 note types (does not use it already?). > > >>>> +/* Linear reverse find starting from RBEGIN towards REND looking for >>>> + the lowest vaddr mapping of the same inode and zero offset. */ >>>> + >>>> +static mapping_entry_s * >>>> +lrfind_mapping_entry (mapping_entry_s *const rbegin, >>>> + const mapping_entry_s *const rend) >>>> +{ >>>> + mapping_entry_s *p; >>>> + >>>> + for (p = rbegin - 1; p >= rend && p->inode == rbegin->inode; --p) >>>> + if (p->offset == 0) >>>> + return p; >>> >>> I had here this layout: >>> 7ffff7ddc000-7ffff7dfd000 r-xp 00000000 fd:01 51415762 /usr/lib64/ld-2.17.so >>> 7ffff7ff9000-7ffff7ffa000 rw-p 00000000 00:00 0 >>> 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] >>> 7ffff7ffc000-7ffff7ffe000 rw-p 00020000 fd:01 51415762 /usr/lib64/ld-2.17.so >>> >>> so it should rather be: >>> for (p = rbegin - 1; p >= rend; --p) >>> if (p->offset == 0 && p->inode == rbegin->inode) >>> return p; >>> >>> Fortunately it should not have any real performance impact. >> >> [AR] Ok, though we are not adding mappings with inode == 0. See >> 'find_memory_region_callback'. > > Hmm, that's true, I do not see now why it failed for me. But that could be > even non-zero-inode mapping so a change was appropriate. > > > This is not yet a full review. > > > Thanks, > Jan > --------------000902040202040306000702 Content-Type: text/x-patch; name="0006-gdbserver-build-id-attribute-generator.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0006-gdbserver-build-id-attribute-generator.patch" Content-length: 19047 >From 8a176b511f358b82d5b1f4c5556a501b62bf6dc6 Mon Sep 17 00:00:00 2001 From: Aleksandar Ristovski Date: Wed, 27 Mar 2013 11:56:57 -0400 Subject: [PATCH 6/8] gdbserver build-id attribute generator * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add 'build-id' in description, example, new attribute in dtd. * features/library-list-svr4.dtd (library-list-svr4): New 'build-id' attribute. * linux-low.c (linux-maps.h, search.h): Include. (ElfXX_Ehdr, ElfXX_Phdr, ElfXX_Nhdr): New. (ELFXX_FLD, ELFXX_SIZEOF, ELFXX_ROUNDUP, BUILD_ID_INVALID): New. (find_phdr_p_ftype, find_phdr, find_phdr_p): New. (get_dynamic): Use find_pdhr to traverse program headers. (struct mapping_entry): New structure. (mapping_entry_s): New typedef, new vector type def. (free_mapping_entry, compare_mapping_entry, compare_mapping_entry_range, compare_mapping_entry_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. --- gdb/doc/gdb.texinfo | 17 +- gdb/features/library-list-svr4.dtd | 13 +- gdb/gdbserver/linux-low.c | 409 +++++++++++++++++++++++++++++++++--- 3 files changed, 402 insertions(+), 37 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 8ae7259..0002d23 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40354,6 +40354,8 @@ 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{NT_GNU_BUILD_ID} note, if it exists. @end itemize Additionally the single @code{main-lm} attribute specifies address of @@ -40371,7 +40373,7 @@ looks like this: + l_ld="0x152350" build-id="9afccf7cc41e6293476223fe72480854"/> @end smallexample @@ -40380,13 +40382,14 @@ The format of an SVR4 library list is described by this DTD: @smallexample - - + + - - - - + + + + + @end smallexample @node Memory Map Format diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd index cae7fd8..fdd6ec0 100644 --- a/gdb/features/library-list-svr4.dtd +++ b/gdb/features/library-list-svr4.dtd @@ -6,11 +6,12 @@ - - + + - - - - + + + + + diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 72c51e0..61da37c 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 @@ -118,6 +120,33 @@ typedef struct } Elf64_auxv_t; #endif +typedef union ElfXX_Ehdr +{ + Elf32_Ehdr _32; + Elf64_Ehdr _64; +} ElfXX_Ehdr; + +typedef union ElfXX_Phdr +{ + Elf32_Phdr _32; + Elf64_Phdr _64; +} ElfXX_Phdr; + +typedef union ElfXX_Nhdr +{ + Elf32_Nhdr _32; + Elf64_Nhdr _64; +} ElfXX_Nhdr; + +#define ELFXX_FLD(hdr, fld) ((is_elf64) ? (hdr)._64.fld : (hdr)._32.fld) +#define ELFXX_SIZEOF(hdr) ((is_elf64) ? sizeof ((hdr)._64) \ + : sizeof ((hdr)._32)) +#define ELFXX_ROUNDUP(what) ((is_elf64) ? (((what) + sizeof (Elf64_Word) - 1) \ + & ~(sizeof (Elf64_Word) - 1)) \ + : (((what) + sizeof (Elf32_Word) - 1) \ + & ~(sizeof (Elf32_Word) - 1))) +#define BUILD_ID_INVALID "?" + /* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol representation of the thread ID. @@ -5432,15 +5461,76 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, return 0; } +/* Predicate function type returns 1 if the given phdr is what is + being looked for. Returns 0 otherwise. */ + +typedef int (find_phdr_p_ftype) (const void *phdr, int is_elf64, + const void *data); + +/* Linearly traverse pheaders given in PHDR until supplied + predicate function returns 1. If supplied predicate function + did return 1, stop traversal and return that PHDR. */ + +static const void * +find_phdr (int is_elf64, const void *const phdr_begin, + const void *const phdr_end, find_phdr_p_ftype *const find_phdr_p, + const void *const data) +{ +#define PHDR_NEXT(hdrp) ((const void *) ((const gdb_byte *) (hdrp) + \ + ELFXX_SIZEOF (*hdrp))) + + const ElfXX_Phdr *phdr = phdr_begin; + + if (phdr == NULL) + return NULL; + + while (PHDR_NEXT (phdr) <= phdr_end) + { + if (find_phdr_p (phdr, is_elf64, data) == 1) + return phdr; + phdr = PHDR_NEXT (phdr); + } + + return NULL; +#undef PHDR_NEXT +} + +/* Predicate function for find_phdr iteration. */ + +static int +find_phdr_p (const void *const phdr, const int is_elf64, + const void *const data) +{ + const ULONGEST *const type = data; + + if (is_elf64) + { + const Elf64_Phdr *const p = phdr; + + if (p->p_type == *type) + return 1; + } + else + { + const Elf32_Phdr *const p = phdr; + + if (p->p_type == *type) + return 1; + } + return 0; +} + /* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */ static CORE_ADDR get_dynamic (const int pid, const int is_elf64) { CORE_ADDR phdr_memaddr, relocation; - int num_phdr, i; + int num_phdr; unsigned char *phdr_buf; const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); + const void *phdr; + ULONGEST p_type; if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) return 0; @@ -5454,21 +5544,24 @@ get_dynamic (const int pid, const int is_elf64) /* Compute relocation: it is expected to be 0 for "regular" executables, non-zero for PIE ones. */ relocation = -1; - for (i = 0; relocation == -1 && i < num_phdr; i++) - if (is_elf64) - { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + p_type = PT_PHDR; + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, + find_phdr_p, &p_type); + if (phdr != NULL) + { + if (is_elf64) + { + const Elf64_Phdr *const p = phdr; - if (p->p_type == PT_PHDR) relocation = phdr_memaddr - p->p_vaddr; - } - else - { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + } + else + { + const Elf32_Phdr *const p = phdr; - if (p->p_type == PT_PHDR) relocation = phdr_memaddr - p->p_vaddr; - } + } + } if (relocation == -1) { @@ -5485,21 +5578,23 @@ get_dynamic (const int pid, const int is_elf64) return 0; } - for (i = 0; i < num_phdr; i++) + p_type = PT_DYNAMIC; + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, + find_phdr_p, &p_type); + + if (phdr != NULL) { if (is_elf64) { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + const Elf64_Phdr *const p = phdr; - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; + return p->p_vaddr + relocation; } else { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + const Elf32_Phdr *const p = phdr; - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; + return p->p_vaddr + relocation; } } @@ -5641,6 +5736,254 @@ struct link_map_offsets int l_prev_offset; }; + +/* Structure for holding a mapping. Only mapping + containing l_ld can have hex_build_id set. */ + +struct mapping_entry +{ + /* Fields are populated from linux_find_memory_region parameters. */ + + ULONGEST vaddr; + ULONGEST size; + ULONGEST offset; + ULONGEST inode; + + /* Hex encoded string allocated using xmalloc, and + needs to be freed. It can be NULL. */ + + char *hex_build_id; +}; + +typedef struct mapping_entry mapping_entry_s; + +DEF_VEC_O(mapping_entry_s); + +static void +free_mapping_entry (VEC (mapping_entry_s) *lst) +{ + int ix; + mapping_entry_s *p; + + for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix) + xfree (p->hex_build_id); + + VEC_free (mapping_entry_s, lst); +} + +/* Used for finding a mapping containing the given + l_ld passed in K. */ + +static int +compare_mapping_entry_range (const void *const k, const void *const b) +{ + const ULONGEST key = *(CORE_ADDR*) k; + const mapping_entry_s *const p = b; + + if (key < p->vaddr) + return -1; + + if (key < p->vaddr + p->size) + return 0; + + return 1; +} + +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_mapping_entry. */ + VEC (mapping_entry_s) *list; +}; + +static linux_find_memory_region_ftype find_memory_region_callback; + +/* Read build-id from PT_NOTE. */ + +static void +read_build_id (struct find_memory_region_callback_data *const p, + mapping_entry_s *const bil, const CORE_ADDR load_addr, + const CORE_ADDR l_addr) +{ + const int is_elf64 = p->is_elf64; + ElfXX_Ehdr ehdr; + + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, + ELFXX_SIZEOF (ehdr)) == 0 + && ELFXX_FLD (ehdr, e_ident[EI_MAG0]) == ELFMAG0 + && ELFXX_FLD (ehdr, e_ident[EI_MAG1]) == ELFMAG1 + && ELFXX_FLD (ehdr, e_ident[EI_MAG2]) == ELFMAG2 + && ELFXX_FLD (ehdr, e_ident[EI_MAG3]) == ELFMAG3) + { + const ElfXX_Phdr *phdr; + void *phdr_buf; + const ULONGEST p_type = PT_NOTE; + const unsigned e_phentsize = ELFXX_FLD (ehdr, e_phentsize); + + gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); /* Basic sanity check. */ + gdb_assert (e_phentsize == ELFXX_SIZEOF (*phdr)); + phdr_buf = alloca (ELFXX_FLD (ehdr, e_phnum) * e_phentsize); + + if (linux_read_memory (load_addr + ELFXX_FLD (ehdr, e_phoff), phdr_buf, + ELFXX_FLD (ehdr, e_phnum) * e_phentsize) != 0) + { + warning ("Could not read program header."); + return; + } + + phdr = phdr_buf; + + for (;;) + { + gdb_byte *pt_note; + const gdb_byte *pt_end; + const ElfXX_Nhdr *nhdr; + + phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf + + ELFXX_FLD (ehdr, e_phnum) * e_phentsize, + find_phdr_p, &p_type); + if (phdr == NULL) + break; + pt_note = xmalloc (ELFXX_FLD (*phdr, p_memsz)); + pt_end = (gdb_byte*) pt_note + ELFXX_FLD (*phdr, p_memsz); + + if (linux_read_memory (ELFXX_FLD (*phdr, p_vaddr) + l_addr, pt_note, + ELFXX_FLD (*phdr, p_memsz)) != 0) + { + xfree (pt_note); + warning ("Could not read note."); + break; + } + + nhdr = (void *) pt_note; + while ((void *) nhdr < (void *) pt_end) + { + const size_t namesz + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_namesz)); + const size_t descsz + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_descsz)); + const size_t note_sz = ELFXX_SIZEOF (*nhdr) + namesz + descsz; + + if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0 + || descsz == 0) + { + warning ("Malformed PT_NOTE\n"); + break; + } + if (ELFXX_FLD (*nhdr, n_type) == NT_GNU_BUILD_ID + && ELFXX_FLD (*nhdr, n_namesz) == 4) + { + const char gnu[4] = "GNU\0"; + const char *const pname + = (char *) nhdr + ELFXX_SIZEOF (*nhdr); + + if (memcmp (pname, gnu, 4) == 0) + { + const size_t n_descsz = ELFXX_FLD (*nhdr, n_descsz); + + bil->hex_build_id = xmalloc (n_descsz * 2 + 1); + bin2hex ((gdb_byte*) pname + namesz, bil->hex_build_id, + n_descsz); + xfree (pt_note); + return; + } + } + nhdr = (void*) ((gdb_byte *) nhdr + note_sz); + } + xfree (pt_note); + } + } +} + +/* Add mapping_entry. */ + +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; + mapping_entry_s bil; + + bil.vaddr = vaddr; + bil.size = size; + bil.offset = offset; + bil.inode = inode; + bil.hex_build_id = NULL; + + VEC_safe_push (mapping_entry_s, p->list, &bil); + } + + /* Continue the traversal. */ + return 0; +} + +/* Linear reverse find starting from RBEGIN towards REND looking for + the lowest vaddr mapping of the same inode and zero offset. */ + +static mapping_entry_s * +lrfind_mapping_entry (mapping_entry_s *const rbegin, + const mapping_entry_s *const rend) +{ + mapping_entry_s *p; + + for (p = rbegin - 1; p >= rend; --p) + if (p->offset == 0 && p->inode == rbegin->inode) + return p; + + return NULL; +} + +/* Get build-id for the given L_LD. DATA must point to + already filled list of mapping_entry 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) +{ + mapping_entry_s *bil; + + if (VEC_address (mapping_entry_s, data->list) == NULL) + return NULL; + + bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list), + VEC_length (mapping_entry_s, data->list), + sizeof (mapping_entry_s), compare_mapping_entry_range); + + if (bil == NULL) + return NULL; + + if (bil->hex_build_id == NULL) + { + mapping_entry_s *bil_min; + + bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s, + data->list)); + if (bil_min != NULL) + read_build_id (data, bil, bil_min->vaddr, l_addr); + else + { + /* Do not try to find hex_build_id again. */ + bil->hex_build_id = xstrdup (BUILD_ID_INVALID); + warning ("Could not determine load address; " + "build-id can not be used."); + } + } + + return bil->hex_build_id; +} + /* Construct qXfer:libraries-svr4:read reply. */ static int @@ -5653,6 +5996,7 @@ 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; static const struct link_map_offsets lmo_32bit_offsets = { @@ -5688,6 +6032,13 @@ 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 (mapping_entry_s, data.list, 16); + if (linux_find_memory_regions_full (pid, find_memory_region_callback, &data, + NULL) < 0) + warning ("Finding memory regions failed"); + if (priv->r_debug == 0) priv->r_debug = get_r_debug (pid, is_elf64); @@ -5762,6 +6113,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) { @@ -5770,21 +6122,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); + 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 + && strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0) + p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id); + p += sprintf(p, "/>"); free (name); } else if (lm_prev == 0) @@ -5819,6 +6179,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, memcpy (readbuf, document + offset, len); xfree (document); + free_mapping_entry (data.list); return len; } -- 1.7.10.4 --------------000902040202040306000702--