Re: [patch] gdbserver build-id in qxfer_libraries reply

Aleksandar Ristovski
2013-02-22T18:39:05Z

[-- Attachment #1: Type: text/plain, Size: 3025 bytes --]

On 13-02-22 10:06 AM, Aleksandar Ristovski wrote:
> Hello,
>
> This is related to:
> http://sourceware.org/ml/gdb-patches/2013-01/msg00748.html. Changes from
> this patch are needed to finish off the work started in that thread.
>
> As per Jan's request, this patch adds 'build-id' to the gdbserver
> response. The value is hex encoded string representing
> .note.gnu.build-id section of the corresponding shared library.
>
> Majority of the patch is refactoring to reuse code. The real change is
> in gdbserver/linux-low.c.

Something I missed in the original post: the intent was to make build-id
optional; however, I missed to augument library-list-svr4.dtd, which is
rectified in this patch. Also, added doc changes (separate patch also
attached).

The code difference between the original and this patch is in
linux-low.c, build-id is now emitted only if build-id could be retrieved
from the binary.

---
Aleksandar

New ChangeLog (added entry for library-list-svr4.dtd) followed by
ChangeLog for doc:

* Makefile.in (HFILES_NO_SRCDIR): Add linux-maps.h and linux-maps.c.

* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to linux-maps.c.
(linux_find_memory_region_ftype): Moved to linux-maps.h.
(linux_find_memory_regions_full): Moved to linux-maps.c.
(linux_find_memory_regions): Check for fake_pid_p to match
functionality of original linux_find_memory_regions_full.
(linux_make_mappings_corefile_notes): Ditto.
* utils.c (HIGH_BYTE_POSN): Moved to common-utils.c.
(is_digit_in_base): Ditto.
(digit_to_int): Ditto.
(strtoulst): Ditto.

* utils.h (strtoulst): Moved to common-utils.h.

* common/common-utils.c (TARGET_CHAR_BIT): Define if not defined.
(HOST_CHAR_BIT): Ditto.
(ctype.h): Include.
(string.h): Include.
(assert.h): Include.
(HIGH_BYTE_POSN): Moved from utils.c.
(is_digit_in_base): Ditto.
(digit_to_int): Ditto.
(strtoulst): Ditto.
(hchar): Hex charset for hex_encode.
(hex_encode): New function.
(decode_hex_ch): Ditto.
(hex_decode): Ditto.

* common/common-utils.h (strtoulst): Moved from utils.h.
(hex_encode): New declaration.
(hex_decode): Ditto.

* common/linux-maps.c: New file.

* common/linux-maps.h: New file.

* common/xml-utils.h (xml_hex_encode_text): Declare.

* config/i386/linux.mh (NATDEPFILES): Add linux-maps.o.

* config/i386/linux64.mh (NATDEPFILES): Add linux-maps.o.

* features/library-list-svr4.dtd (build-id): New attribute.

* gdbserver/Makefile.in (linux-maps.o): New.

* gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o.

* gdbserver/linux-low.c (linux-maps.h): Include.
(find_memory_region_callback_data): New structure definition.
(find_memory_region_callback): New forward declaration.
(find_memory_region_callback): New function.
(get_hex_build_id): New function.
(linux_qxfer_libraries_svr4): Add hex encoded build-id to the reply.

Doc ChangeLog:

* gdb.texinfo (Library List Format for SVR4 Targets): New
'build-id'
attribute, add it to the example and document it in DTD.

[-- Attachment #2: gdbserver-build-id-201302221119.patch --]
[-- Type: text/x-patch, Size: 40022 bytes --]

Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1238
diff -u -p -r1.1238 Makefile.in
--- gdb/Makefile.in 8 Feb 2013 09:00:34 -0000 1.1238
+++ gdb/Makefile.in 22 Feb 2013 16:19:11 -0000
@@ -771,7 +771,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFI

HFILES_NO_SRCDIR = \
common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-maps.h common/linux-ptrace.h \
proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -1945,6 +1945,10 @@ format.o: ${srcdir}/common/format.c
$(COMPILE) $(srcdir)/common/format.c
$(POSTCOMPILE)

+linux-maps.o: ${srcdir}/common/linux-maps.c
+ $(COMPILE) $(srcdir)/common/linux-maps.c
+ $(POSTCOMPILE)
+
linux-osdata.o: ${srcdir}/common/linux-osdata.c
$(COMPILE) $(srcdir)/common/linux-osdata.c
$(POSTCOMPILE)
Index: gdb/linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-tdep.c,v
retrieving revision 1.27
diff -u -p -r1.27 linux-tdep.c
--- gdb/linux-tdep.c 4 Feb 2013 18:40:41 -0000 1.27
+++ gdb/linux-tdep.c 22 Feb 2013 16:19:11 -0000
@@ -33,6 +33,7 @@
#include "arch-utils.h"
#include "gdb_obstack.h"
#include "cli/cli-utils.h"
+#include "linux-maps.h"

#include <ctype.h>

@@ -207,46 +208,7 @@ linux_core_pid_to_str (struct gdbarch *g
return normal_pid_to_str (ptid);
}

-/* Service function for corefiles and info proc. */

-static void
-read_mapping (const char *line,
- ULONGEST *addr, ULONGEST *endaddr,
- const char **permissions, size_t *permissions_len,
- ULONGEST *offset,
- const char **device, size_t *device_len,
- ULONGEST *inode,
- const char **filename)
-{
- const char *p = line;
-
- *addr = strtoulst (p, &p, 16);
- if (*p == '-')
- p++;
- *endaddr = strtoulst (p, &p, 16);
-
- while (*p && isspace (*p))
- p++;
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- while (*p && isspace (*p))
- p++;
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- while (*p && isspace (*p))
- p++;
- *filename = p;
-}

/* Implement the "info proc" command. */

@@ -666,101 +628,6 @@ linux_core_info_proc (struct gdbarch *gd
error (_("unable to handle request"));
}

-typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
- ULONGEST offset, ULONGEST inode,
- int read, int write,
- int exec, int modified,
- const char *filename,
- void *data);
-
-/* List memory regions in the inferior for a corefile. */
-
-static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
-{
- char filename[100];
- gdb_byte *data;
-
- /* We need to know the real target PID to access /proc. */
- if (current_inferior ()->fake_pid_p)
- return 1;
-
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
- data = target_fileio_read_stralloc (filename);
- if (data == NULL)
- {
- /* Older Linux kernels did not support /proc/PID/smaps. */
- xsnprintf (filename, sizeof filename,
- "/proc/%d/maps", current_inferior ()->pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- struct cleanup *cleanup = make_cleanup (xfree, data);
- char *line;
-
- line = strtok (data, "\n");
- while (line)
- {
- ULONGEST addr, endaddr, offset, inode;
- const char *permissions, *device, *filename;
- size_t permissions_len, device_len;
- int read, write, exec;
- int modified = 0, has_anonymous = 0;
-
- read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
- &offset, &device, &device_len, &inode, &filename);
-
- /* Decode permissions. */
- read = (memchr (permissions, 'r', permissions_len) != 0);
- write = (memchr (permissions, 'w', permissions_len) != 0);
- exec = (memchr (permissions, 'x', permissions_len) != 0);
-
- /* Try to detect if region was modified by parsing smaps counters. */
- for (line = strtok (NULL, "\n");
- line && line[0] >= 'A' && line[0] <= 'Z';
- line = strtok (NULL, "\n"))
- {
- char keyword[64 + 1];
- unsigned long number;
-
- if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
- {
- warning (_("Error parsing {s,}maps file '%s'"), filename);
- break;
- }
- if (strcmp (keyword, "Anonymous:") == 0)
- has_anonymous = 1;
- if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
- || strcmp (keyword, "Private_Dirty:") == 0
- || strcmp (keyword, "Swap:") == 0
- || strcmp (keyword, "Anonymous:") == 0))
- modified = 1;
- }
-
- /* Older Linux kernels did not support the "Anonymous:" counter.
- If it is missing, we can't be sure - dump all the pages. */
- if (!has_anonymous)
- modified = 1;
-
- /* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
- }
-
- do_cleanups (cleanup);
- return 0;
- }
-
- return 1;
-}
-
-/* A structure for passing information through
- linux_find_memory_regions_full. */
-
struct linux_find_memory_regions_data
{
/* The original callback. */
@@ -798,7 +665,10 @@ linux_find_memory_regions (struct gdbarc
data.func = func;
data.obfd = obfd;

- return linux_find_memory_regions_full (gdbarch,
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ return linux_find_memory_regions_full (current_inferior ()->pid,
linux_find_memory_regions_thunk,
&data);
}
@@ -982,8 +852,10 @@ linux_make_mappings_corefile_notes (stru
pack_long (buf, long_type, 1);
obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));

- linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback,
- &mapping_data);
+ if (!current_inferior ()->fake_pid_p)
+ linux_find_memory_regions_full (current_inferior ()->pid,
+ linux_make_mappings_callback,
+ &mapping_data);

if (mapping_data.file_count != 0)
{
Index: gdb/utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.292
diff -u -p -r1.292 utils.c
--- gdb/utils.c 14 Feb 2013 17:11:41 -0000 1.292
+++ gdb/utils.c 22 Feb 2013 16:19:12 -0000
@@ -3309,104 +3309,6 @@ dummy_obstack_deallocate (void *object,
return;
}

-/* The bit offset of the highest byte in a ULONGEST, for overflow
- checking. */
-
-#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
-
-/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
- where 2 <= BASE <= 36. */
-
-static int
-is_digit_in_base (unsigned char digit, int base)
-{
- if (!isalnum (digit))
- return 0;
- if (base <= 10)
- return (isdigit (digit) && digit < base + '0');
- else
- return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
-}
-
-static int
-digit_to_int (unsigned char c)
-{
- if (isdigit (c))
- return c - '0';
- else
- return tolower (c) - 'a' + 10;
-}
-
-/* As for strtoul, but for ULONGEST results. */
-
-ULONGEST
-strtoulst (const char *num, const char **trailer, int base)
-{
- unsigned int high_part;
- ULONGEST result;
- int minus = 0;
- int i = 0;
-
- /* Skip leading whitespace. */
- while (isspace (num[i]))
- i++;
-
- /* Handle prefixes. */
- if (num[i] == '+')
- i++;
- else if (num[i] == '-')
- {
- minus = 1;
- i++;
- }
-
- if (base == 0 || base == 16)
- {
- if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X'))
- {
- i += 2;
- if (base == 0)
- base = 16;
- }
- }
-
- if (base == 0 && num[i] == '0')
- base = 8;
-
- if (base == 0)
- base = 10;
-
- if (base < 2 || base > 36)
- {
- errno = EINVAL;
- return 0;
- }
-
- result = high_part = 0;
- for (; is_digit_in_base (num[i], base); i += 1)
- {
- result = result * base + digit_to_int (num[i]);
- high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN);
- result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
- if (high_part > 0xff)
- {
- errno = ERANGE;
- result = ~ (ULONGEST) 0;
- high_part = 0;
- minus = 0;
- break;
- }
- }
-
- if (trailer != NULL)
- *trailer = &num[i];
-
- result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
- if (minus)
- return -result;
- else
- return result;
-}

/* Simple, portable version of dirname that does not modify its
argument. */
Index: gdb/utils.h
===================================================================
RCS file: /cvs/src/src/gdb/utils.h,v
retrieving revision 1.5
diff -u -p -r1.5 utils.h
--- gdb/utils.h 3 Feb 2013 15:54:17 -0000 1.5
+++ gdb/utils.h 22 Feb 2013 16:19:12 -0000
@@ -39,8 +39,6 @@ extern int streq (const char *, const ch

extern int subset_compare (char *, char *);

-ULONGEST strtoulst (const char *num, const char **trailer, int base);
-
int compare_positive_ints (const void *ap, const void *bp);
int compare_strings (const void *ap, const void *bp);

Index: gdb/common/common-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/common/common-utils.c,v
retrieving revision 1.5
diff -u -p -r1.5 common-utils.c
--- gdb/common/common-utils.c 14 Feb 2013 17:11:41 -0000 1.5
+++ gdb/common/common-utils.c 22 Feb 2013 16:19:12 -0000
@@ -19,6 +19,15 @@

#ifdef GDBSERVER
#include "server.h"
+
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT (sizeof (char) * 8)
+#endif /* ! TARGET_CHAR_BIT */
+
+#if !defined (HOST_CHAR_BIT)
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif /* ! HOST_CHAR_BIT */
+
#else
#include "defs.h"
#endif
@@ -28,6 +37,9 @@

#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>

/* The xmalloc() (libiberty.h) family of memory management routines.

@@ -161,3 +173,187 @@ savestring (const char *ptr, size_t len)
p[len] = 0;
return p;
}
+
+\f
+/* The bit offset of the highest byte in a ULONGEST, for overflow
+ checking. */
+
+#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
+
+
+/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
+ where 2 <= BASE <= 36. */
+
+static int
+is_digit_in_base (unsigned char digit, int base)
+{
+ if (!isalnum (digit))
+ return 0;
+ if (base <= 10)
+ return (isdigit (digit) && digit < base + '0');
+ else
+ return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
+}
+
+static int
+digit_to_int (unsigned char c)
+{
+ if (isdigit (c))
+ return c - '0';
+ else
+ return tolower (c) - 'a' + 10;
+}
+
+/* As for strtoul, but for ULONGEST results. */
+
+ULONGEST
+strtoulst (const char *num, const char **trailer, int base)
+{
+ unsigned int high_part;
+ ULONGEST result;
+ int minus = 0;
+ int i = 0;
+
+ /* Skip leading whitespace. */
+ while (isspace (num[i]))
+ i++;
+
+ /* Handle prefixes. */
+ if (num[i] == '+')
+ i++;
+ else if (num[i] == '-')
+ {
+ minus = 1;
+ i++;
+ }
+
+ if (base == 0 || base == 16)
+ {
+ if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X'))
+ {
+ i += 2;
+ if (base == 0)
+ base = 16;
+ }
+ }
+
+ if (base == 0 && num[i] == '0')
+ base = 8;
+
+ if (base == 0)
+ base = 10;
+
+ if (base < 2 || base > 36)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ result = high_part = 0;
+ for (; is_digit_in_base (num[i], base); i += 1)
+ {
+ result = result * base + digit_to_int (num[i]);
+ high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN);
+ result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
+ if (high_part > 0xff)
+ {
+ errno = ERANGE;
+ result = ~ (ULONGEST) 0;
+ high_part = 0;
+ minus = 0;
+ break;
+ }
+ }
+
+ if (trailer != NULL)
+ *trailer = &num[i];
+
+ result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
+ if (minus)
+ return -result;
+ else
+ return result;
+}
+
+\f
+
+static const char hchar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+
+/* Encode SIZE bytes from TEXT in hexadecimal format. Return
+ malloc allocated buffer of size SIZE * 2 + 1. */
+
+char *
+hex_encode (const void *const text, const size_t size)
+{
+ char *buf = xmalloc (size * 2 + 1);
+ size_t i;
+ const char *const t = text;
+
+ assert (text != NULL);
+
+ for (i = 0; i != size; ++i)
+ {
+ buf[i << 1] = hchar[(t[i] & 0xF0) >> 4];
+ buf[(i << 1) + 1] = hchar[t[i] & 0x0F];
+ }
+
+ buf[size * 2] = '\0';
+
+ return buf;
+}
+
+
+/* Helper function, decodes hex. char H into integer
+ integer value [0 - 15]. If H is not valid character
+ returns -1. */
+static int
+decode_hex_ch (const char h)
+{
+ if (h >= '0' && h <= '9')
+ return h - '0';
+
+ if (h >= 'a' && h <= 'f')
+ return h + 10 - 'a';
+
+ if (h >= 'A' && h <= 'F')
+ return h + 10 - 'A';
+
+ return -1;
+}
+
+/* Decode hex encoded HEXTEXT and return malloc allocated buffer
+ of size SZ. */
+
+void *
+hex_decode (const char *const hextext, size_t *sz)
+{
+ char *buf;
+ size_t len;
+ size_t i;
+
+ assert (hextext != NULL);
+ assert (sz != NULL);
+
+ len = strlen (hextext);
+ *sz = (len + 1) >> 1;
+ buf = xmalloc (*sz);
+
+ for (i = 0; i < len; i+=2)
+ {
+ int hi, lo;
+
+ hi = decode_hex_ch (hextext[i]);
+ lo = decode_hex_ch (hextext[i+1]);
+ if (hi < 0 || lo < 0)
+ {
+ /* Return only what was decoded so far. */
+ *sz = i >> 1; /* Successfully decoded bytes. */
+ break;
+ }
+ buf[i >> 1] = (hi << 4) | lo;
+ }
+
+ return buf;
+}
+
Index: gdb/common/common-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/common/common-utils.h,v
retrieving revision 1.5
diff -u -p -r1.5 common-utils.h
--- gdb/common/common-utils.h 14 Feb 2013 17:11:41 -0000 1.5
+++ gdb/common/common-utils.h 22 Feb 2013 16:19:12 -0000
@@ -53,4 +53,10 @@ int xsnprintf (char *str, size_t size, c

char *savestring (const char *ptr, size_t len);

+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+char *hex_encode (const void *text, size_t size);
+
+void *hex_decode (const char *hextext, size_t *size);
+
#endif
Index: gdb/common/linux-maps.c
===================================================================
RCS file: gdb/common/linux-maps.c
diff -N gdb/common/linux-maps.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/common/linux-maps.c 22 Feb 2013 16:19:12 -0000
@@ -0,0 +1,217 @@
+/* Linux-specific memory maps manipulation routines.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifdef GDBSERVER
+#include "server.h"
+#include "linux-maps.h"
+#include <fcntl.h>
+#include <unistd.h>
+#else /* ! GDBSERVER */
+#include "defs.h"
+#include "linux-maps.h"
+#include "target.h"
+#endif /* ! GDBSERVER */
+
+#include <ctype.h>
+
+
+#ifdef GDBSERVER
+static char *
+fileio_read_stralloc (const char *const filename)
+{
+ char *buf;
+ int fd;
+ size_t buf_alloc;
+ size_t buf_pos;
+ const size_t buf_alloc_inc = 2 * 4096;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ buf_pos = 0;
+
+ while (1)
+ {
+ ssize_t n;
+
+ n = pread (fd, &buf[buf_pos], buf_alloc - buf_pos, buf_pos);
+
+ if (n < 0)
+ {
+ xfree (buf);
+ buf = NULL;
+ break;
+ }
+ else if (n == 0)
+ {
+ if (buf_pos == 0)
+ {
+ xfree (buf);
+ buf = NULL;
+ }
+ break;
+ }
+ buf_pos += n;
+
+ if (buf_alloc < buf_pos + buf_alloc_inc)
+ {
+ buf_alloc += buf_alloc_inc;
+ buf = xrealloc (buf, buf_alloc);
+ }
+ }
+
+ if (close (fd) < 0)
+ warning (_("Error closing file descriptor: '%s'"), strerror (errno));
+
+ return buf;
+}
+
+#define target_fileio_read_stralloc(filename) fileio_read_stralloc (filename)
+
+#endif /* GDBSERVER */
+
+/* Service function for corefiles and info proc. */
+
+void
+read_mapping (const char *line,
+ ULONGEST *addr, ULONGEST *endaddr,
+ const char **permissions, size_t *permissions_len,
+ ULONGEST *offset,
+ const char **device, size_t *device_len,
+ ULONGEST *inode,
+ const char **filename)
+{
+ const char *p = line;
+
+ *addr = strtoulst (p, &p, 16);
+ if (*p == '-')
+ p++;
+ *endaddr = strtoulst (p, &p, 16);
+
+ while (*p && isspace (*p))
+ p++;
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ while (*p && isspace (*p))
+ p++;
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ while (*p && isspace (*p))
+ p++;
+ *filename = p;
+}
+
+/* List memory regions in the inferior.
+ Return nonzero on error. */
+
+int
+linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *obfd)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename,
+ "/proc/%d/smaps", pid);
+ data = target_fileio_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename,
+ "/proc/%d/maps", pid);
+ data = target_fileio_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+
+ line = strtok (data, "\n");
+ while (line)
+ {
+ ULONGEST addr, endaddr, offset, inode;
+ const char *permissions, *device, *filename;
+ size_t permissions_len, device_len;
+ int read, write, exec;
+ int modified = 0, has_anonymous = 0;
+ int ret;
+
+ read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
+ &offset, &device, &device_len, &inode, &filename);
+
+ /* Decode permissions. */
+ read = (memchr (permissions, 'r', permissions_len) != 0);
+ write = (memchr (permissions, 'w', permissions_len) != 0);
+ exec = (memchr (permissions, 'x', permissions_len) != 0);
+
+ /* Try to detect if region was modified by parsing smaps counters. */
+ for (line = strtok (NULL, "\n");
+ line && line[0] >= 'A' && line[0] <= 'Z';
+ line = strtok (NULL, "\n"))
+ {
+ char keyword[64 + 1];
+ unsigned long number;
+
+ if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
+ {
+ warning (_("Error parsing {s,}maps file '%s'"), filename);
+ break;
+ }
+ if (strcmp (keyword, "Anonymous:") == 0)
+ has_anonymous = 1;
+ if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
+ || strcmp (keyword, "Private_Dirty:") == 0
+ || strcmp (keyword, "Swap:") == 0
+ || strcmp (keyword, "Anonymous:") == 0))
+ modified = 1;
+ }
+
+ /* Older Linux kernels did not support the "Anonymous:" counter.
+ If it is missing, we can't be sure - dump all the pages. */
+ if (!has_anonymous)
+ modified = 1;
+
+ /* Invoke the callback function to create the corefile segment. */
+ ret = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, obfd);
+ if (ret)
+ break;
+ }
+
+ xfree (data);
+ return 0;
+ }
+
+ return 1;
+}
+
+
Index: gdb/common/linux-maps.h
===================================================================
RCS file: gdb/common/linux-maps.h
diff -N gdb/common/linux-maps.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/common/linux-maps.h 22 Feb 2013 16:19:12 -0000
@@ -0,0 +1,50 @@
+/* Linux-specific memory maps manipulation routines.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef COMMON_LINUX_MAPS_H
+#define COMMON_LINUX_MAPS_H
+
+/* Function type for linux_find_memory_regions_full function.
+
+ Non zero returned breaks loop in linux_find_memory_regions_full. */
+
+typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
+ ULONGEST offset, ULONGEST inode,
+ int read, int write,
+ int exec, int modified,
+ const char *filename,
+ void *data);
+
+/* A structure for passing information through
+ linux_find_memory_regions_full. */
+
+extern int linux_find_memory_regions_full (
+ pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *obfd);
+
+extern void read_mapping (const char *line,
+ ULONGEST *addr, ULONGEST *endaddr,
+ const char **permissions, size_t *permissions_len,
+ ULONGEST *offset,
+ const char **device, size_t *device_len,
+ ULONGEST *inode,
+ const char **filename);
+
+
+#endif /* COMMON_LINUX_MAPS_H */
Index: gdb/common/xml-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/common/xml-utils.h,v
retrieving revision 1.3
diff -u -p -r1.3 xml-utils.h
--- gdb/common/xml-utils.h 1 Jan 2013 06:32:54 -0000 1.3
+++ gdb/common/xml-utils.h 22 Feb 2013 16:19:12 -0000
@@ -25,4 +25,9 @@

extern char *xml_escape_text (const char *text);

+/* Return a xmalloc allocated string with hex-encoded SIZE bytes from
+ TEXT. */
+
+extern char *xml_hex_encode_text (const unsigned char *text, size_t size);
+
#endif
Index: gdb/config/i386/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux.mh,v
retrieving revision 1.27
diff -u -p -r1.27 linux.mh
--- gdb/config/i386/linux.mh 13 Mar 2012 15:00:33 -0000 1.27
+++ gdb/config/i386/linux.mh 22 Feb 2013 16:19:12 -0000
@@ -3,7 +3,7 @@
NAT_FILE= config/nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o i386-linux-nat.o \
- proc-service.o linux-thread-db.o \
+ proc-service.o linux-thread-db.o linux-maps.o \
linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o
NAT_CDEPS = $(srcdir)/proc-service.list

Index: gdb/config/i386/linux64.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux64.mh,v
retrieving revision 1.13
diff -u -p -r1.13 linux64.mh
--- gdb/config/i386/linux64.mh 13 Mar 2012 15:00:34 -0000 1.13
+++ gdb/config/i386/linux64.mh 22 Feb 2013 16:19:12 -0000
@@ -1,7 +1,7 @@
# Host: GNU/Linux x86-64
NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o amd64-nat.o amd64-linux-nat.o \
- linux-nat.o linux-osdata.o \
+ linux-maps.o linux-nat.o linux-osdata.o \
proc-service.o linux-thread-db.o linux-fork.o \
linux-procfs.o linux-ptrace.o
NAT_FILE= config/nm-linux.h
Index: gdb/features/library-list-svr4.dtd
===================================================================
RCS file: /cvs/src/src/gdb/features/library-list-svr4.dtd,v
retrieving revision 1.3
diff -u -p -r1.3 library-list-svr4.dtd
--- gdb/features/library-list-svr4.dtd 1 Jan 2013 06:32:58 -0000 1.3
+++ gdb/features/library-list-svr4.dtd 22 Feb 2013 16:19:14 -0000
@@ -14,3 +14,4 @@
<!ATTLIST library lm CDATA #REQUIRED>
<!ATTLIST library l_addr CDATA #REQUIRED>
<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library build-id CDATA #IMPLIED>
Index: gdb/gdbserver/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
retrieving revision 1.142
diff -u -p -r1.142 Makefile.in
--- gdb/gdbserver/Makefile.in 4 Feb 2013 18:20:04 -0000 1.142
+++ gdb/gdbserver/Makefile.in 22 Feb 2013 16:19:14 -0000
@@ -509,6 +509,9 @@ ax.o: ax.c
signals.o: ../common/signals.c
$(COMPILE) $<
$(POSTCOMPILE)
+linux-maps.o: ../common/linux-maps.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
linux-procfs.o: ../common/linux-procfs.c
$(COMPILE) $<
$(POSTCOMPILE)
Index: gdb/gdbserver/configure.srv
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.srv,v
retrieving revision 1.71
diff -u -p -r1.71 configure.srv
--- gdb/gdbserver/configure.srv 4 Feb 2013 18:20:05 -0000 1.71
+++ gdb/gdbserver/configure.srv 22 Feb 2013 16:19:14 -0000
@@ -46,6 +46,7 @@ case "${target}" in
srv_regobj="aarch64.o aarch64-without-fpu.o"
srv_tgtobj="linux-aarch64-low.o"
srv_tgtobj="${srv_tgtobj} linux-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-maps.o"
srv_tgtobj="${srv_tgtobj} linux-osdata.o"
srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
@@ -61,7 +62,9 @@ case "${target}" in
srv_regobj="${srv_regobj} arm-with-vfpv2.o"
srv_regobj="${srv_regobj} arm-with-vfpv3.o"
srv_regobj="${srv_regobj} arm-with-neon.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-arm-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-arm-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="arm-with-iwmmxt.xml"
srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
@@ -84,19 +87,25 @@ case "${target}" in
srv_mingwce=yes
;;
bfin-*-*linux*) srv_regobj=reg-bfin.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-bfin-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-bfin-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
crisv32-*-linux*) srv_regobj=reg-crisv32.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-crisv32-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-crisv32-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_thread_db=yes
;;
cris-*-linux*) srv_regobj=reg-cris.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-cris-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-cris-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
@@ -111,7 +120,10 @@ case "${target}" in
srv_regobj="$srv_regobj $srv_amd64_linux_regobj"
srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles"
fi
- srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-x86-low.o"
+ srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -146,12 +158,16 @@ case "${target}" in
srv_qnx="yes"
;;
ia64-*-linux*) srv_regobj=reg-ia64.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-ia64-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-ia64-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
;;
m32r*-*-linux*) srv_regobj=reg-m32r.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-m32r-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-m32r-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
@@ -161,7 +177,9 @@ case "${target}" in
else
srv_regobj=reg-m68k.o
fi
- srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-m68k-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -172,7 +190,9 @@ case "${target}" in
else
srv_regobj=reg-m68k.o
fi
- srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-m68k-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -182,7 +202,10 @@ case "${target}" in
srv_regobj="${srv_regobj} mips-dsp-linux.o"
srv_regobj="${srv_regobj} mips64-linux.o"
srv_regobj="${srv_regobj} mips64-dsp-linux.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o"
+ srv_tgtobj="${srv_tgtobj} linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-mips-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="mips-linux.xml"
srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
@@ -215,7 +238,9 @@ case "${target}" in
srv_regobj="${srv_regobj} powerpc-isa205-64l.o"
srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o"
srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-ppc-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-ppc-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="rs6000/powerpc-32l.xml"
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml"
@@ -261,7 +286,9 @@ case "${target}" in
srv_regobj="${srv_regobj} s390x-linux64.o"
srv_regobj="${srv_regobj} s390x-linux64v1.o"
srv_regobj="${srv_regobj} s390x-linux64v2.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-s390-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-s390-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="s390-linux32.xml"
srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml"
@@ -282,14 +309,18 @@ case "${target}" in
srv_linux_thread_db=yes
;;
sh*-*-linux*) srv_regobj=reg-sh.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-sh-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-sh-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
srv_linux_thread_db=yes
;;
sparc*-*-linux*) srv_regobj=reg-sparc64.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-sparc-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-sparc-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_thread_db=yes
@@ -306,14 +337,19 @@ case "${target}" in
srv_xmlfiles="${srv_xmlfiles} tic6x-core.xml"
srv_xmlfiles="${srv_xmlfiles} tic6x-gp.xml"
srv_xmlfiles="${srv_xmlfiles} tic6x-c6xp.xml"
- srv_tgtobj="linux-low.o linux-osdata.o linux-tic6x-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-tic6x-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
x86_64-*-linux*) srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj"
- srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-x86-low.o"
+ srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
srv_linux_usrregs=yes # This is for i386 progs.
@@ -328,12 +364,17 @@ case "${target}" in
;;

xtensa*-*-linux*) srv_regobj=reg-xtensa.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-xtensa-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-xtensa-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
;;
tilegx-*-linux*) srv_regobj=reg-tilegx.o
- srv_tgtobj="linux-low.o linux-tile-low.o linux-osdata.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o"
+ srv_tgtobj="${srv_tgtobj} linux-tile-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_thread_db=yes
Index: gdb/gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.231
diff -u -p -r1.231 linux-low.c
--- gdb/gdbserver/linux-low.c 4 Feb 2013 17:47:00 -0000 1.231
+++ gdb/gdbserver/linux-low.c 22 Feb 2013 16:19:16 -0000
@@ -20,6 +20,7 @@
#include "linux-low.h"
#include "linux-osdata.h"
#include "agent.h"
+#include "linux-maps.h"

#include "gdb_wait.h"
#include <stdio.h>
@@ -5633,6 +5634,142 @@ struct link_map_offsets
int l_prev_offset;
};

+
+
+
+
+struct find_memory_region_callback_data
+{
+ int is_elf64;
+ const char *soname;
+ CORE_ADDR l_addr;
+ size_t *build_idsz; /* Return. Meaningful iff *build_id != NULL. */
+ void **build_id; /* Return. malloc allocated memory. */
+};
+
+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 = NULL;
+#ifdef HDR
+#error "HDR macro redefinition detected"
+#endif /* HDR */
+#define HDR(hdr, fld) ((p->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+ if (linux_read_memory (vaddr, (unsigned char *)&ehdr, sizeof (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 (vaddr + 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)
+ {
+ nhdr = xmalloc (HDR(phdr, p_memsz));
+
+ if (linux_read_memory (p->l_addr + HDR (phdr, p_vaddr),
+ (unsigned char *)nhdr,
+ HDR (phdr, p_memsz)) != 0)
+ {
+ warning ("could not read note");
+ break;
+ }
+ if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ *p->build_idsz = HDR (phdr, p_memsz);
+ *p->build_id = (void*)nhdr;
+ break;
+ }
+ free (nhdr);
+ }
+ }
+ }
+ else
+ warning ("failed reading build-id\n");
+
+ 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;
+ void *raw_build_id = NULL;
+ size_t build_idsz;
+ 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 strdup ("");
+ }
+
+ data.is_elf64 = is_elf64;
+ data.soname = real_soname;
+ data.l_addr = l_addr;
+ data.build_idsz = &build_idsz;
+ data.build_id = &raw_build_id;
+
+ linux_find_memory_regions_full (lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback,
+ (void*)&data);
+ free (real_soname);
+ if (raw_build_id != NULL)
+ hex_build_id = hex_encode (raw_build_id, build_idsz);
+ else
+ hex_build_id = NULL;
+ free (raw_build_id);
+ return hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */

static int
@@ -5754,6 +5891,7 @@ linux_qxfer_libraries_svr4 (const char *
/* 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)
{
@@ -5762,7 +5900,12 @@ linux_qxfer_libraries_svr4 (const char *
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 + 215
+ + ((hex_enc_build_id != NULL)?
+ strlen (hex_enc_build_id) : 0))
{
/* Expand to guarantee sufficient storage. */
uintptr_t document_len = p - document;
@@ -5772,12 +5915,15 @@ linux_qxfer_libraries_svr4 (const char *
p = document + document_len;
}

- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
- "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+ "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, "%s", "/>");
free (name);
+ free (hex_enc_build_id);
}
else if (lm_prev == 0)
{

[-- Attachment #3: gdbserver-build-id-doc-201302221119.patch --]
[-- Type: text/x-patch, Size: 1433 bytes --]

Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.1054
diff -u -p -r1.1054 gdb.texinfo
--- gdb/doc/gdb.texinfo 21 Feb 2013 19:08:10 -0000 1.1054
+++ gdb/doc/gdb.texinfo 22 Feb 2013 16:19:14 -0000
@@ -40144,6 +40144,9 @@ memory address. It is a displacement of
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
@@ -40161,7 +40164,8 @@ looks like this:
<library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000"
l_ld="0xe4eefc"/>
<library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000"
- l_ld="0x152350"/>
+ l_ld="0x152350" build-id="040000001400000003000000474e5500\
+ 829afccf7cc41e62934766d96223fe72480854e"/>
</library-list-svr>
@end smallexample

@@ -40177,6 +40181,7 @@ The format of an SVR4 library list is de
<!ATTLIST library lm CDATA #REQUIRED>
<!ATTLIST library l_addr CDATA #REQUIRED>
<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library build-id CDATA #IMPLIED>
@end smallexample

@node Memory Map Format