Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Aleksandar Ristovski <aristovski@qnx.com>
To: Pedro Alves <palves@redhat.com>
Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>,
	Jan Kratochvil	<jan.kratochvil@redhat.com>
Subject: Re: [patch] gdbserver build-id in qxfer_libraries reply
Date: Wed, 27 Feb 2013 17:25:00 -0000	[thread overview]
Message-ID: <512E4169.7080506@qnx.com> (raw)
In-Reply-To: <512CA419.7020806@redhat.com>

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

On 13-02-26 07:01 AM, Pedro Alves wrote:
> Hi Aleksandar,
>
> Thanks for the patch.

Thanks for looking at the patch.

>
> On 02/22/2013 06:38 PM, Aleksandar Ristovski wrote:
>>>
>>> Majority of the patch is refactoring to reuse code.
>
> I'm reading the patch, but one immediate question I have
> is where did hex_encode/hex_decode and friends got refactored
> from?  It seems we end up with multiple functions to do the same
> in both gdb and gdbserver, given the existence of bin2hex etc
> in gdb and unhexify/hexify in gdbserver?

apparently I was grepping *h files. I moved bin2hex and hex2bin to 
common-utils. New patch attached, along with documentation patch.

Note there is a small change in linux-low.c in that new patch passes 
exactly note size instead of using PT_NOTE pheaders p_memsz.

>
>>   The real change is
>>> in gdbserver/linux-low.c.
>

---
Aleksandar



ChangeLog followed by doc/ChangeLog


     DATE  Aleksandar Ristovski  <aristovski@qnx.com>

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

     	* 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.
     	(fromhex): Moved from remote.c.
     	(hex2bin): Ditto.
     	(tohex): Ditto.
     	(bin2hex): Ditto.

     	* common/common-utils.h (strtoulst): Moved from utils.h.
     	(tohex): New declaration.
     	(fromhex): Ditto.
     	(hex2bin): Ditto.
     	(bin2hex): Ditto.

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

     	* config/i386/linux.mk (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.

     	* remote-utils.c (common-utils.h): Include.
     	(fromhex): Moved to common-utils.c.
     	(unhexify): Use hex2bin.
     	(tohex): Moved to common-utils.c.
     	(hexify): Use bin2hex.

     	* 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.

     	* remote.c (tohex): Remove forward declaration.
     	(fromhex): Ditto.
     	(hex2bin): Ditto.
     	(bin2hex): Ditto.
     	(fromhex): Move implementation to common-utils.c
     	(hex2bin): Ditto.
     	(tohex): Ditto.
     	(bin2hex): Ditto.

     	* tracepoint.c (hex2bin): Remove declaration.
     	(bin2hex): 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.



doc/ChangeLog:
     DATE  Aleksandar Ristovski  <aristovski@qnx.com>

         * 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-in-qxfer_libraries-reply-201302271218.patch --]
[-- Type: text/x-patch, Size: 42623 bytes --]

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ed30db5..dae451b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -771,7 +771,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
 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)
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 4204abf..780ba09 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -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,175 @@ 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
+/* Convert hex digit A to a number.  */
+
+int
+fromhex (int a)
+{
+  if (a >= '0' && a <= '9')
+    return a - '0';
+  else if (a >= 'a' && a <= 'f')
+    return a - 'a' + 10;
+  else if (a >= 'A' && a <= 'F')
+    return a - 'A' + 10;
+  return -1;
+}
+
+size_t
+hex2bin (const char *hex, gdb_byte *bin, size_t count)
+{
+  size_t i;
+
+  for (i = 0; i < count; i++)
+    {
+      int hi, lo;
+
+      if (hex[0] == 0 || hex[1] == 0
+	  || (hi = fromhex (hex[0])) < 0
+	  || (lo = fromhex (hex[1])) < 0)
+	{
+	  /* Hex string is short, or of uneven length or malformed.
+	     Return the count that has been converted so far.  */
+	  warning (_("Malformed hex encoded string: '%s'\n"), hex);
+	  return i;
+	}
+
+      *bin++ = hi * 16 + lo;
+      hex += 2;
+    }
+  return i;
+}
+
+
+/* Convert number NIB to a hex digit.  */
+
+int
+tohex (int nib)
+{
+  if (nib < 10)
+    return '0' + nib;
+  else
+    return 'a' + nib - 10;
+}
+
+size_t
+bin2hex (const gdb_byte *bin, char *hex, size_t count)
+{
+  size_t i;
+
+  /* May use a length, or a nul-terminated string as input.  */
+  if (count == 0)
+    count = strlen ((char *) bin);
+
+  for (i = 0; i < count; i++)
+    {
+      *hex++ = tohex ((*bin >> 4) & 0xf);
+      *hex++ = tohex (*bin++ & 0xf);
+    }
+  *hex = 0;
+  return i;
+}
+
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 9b659d8..9ce5da2 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -53,4 +53,14 @@ int xsnprintf (char *str, size_t size, const char *format, ...)
 
 char *savestring (const char *ptr, size_t len);
 
+extern ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+extern int tohex (int nib);
+
+extern int fromhex (int a);
+
+extern size_t hex2bin (const char *hex, gdb_byte *bin, size_t count);
+
+extern size_t bin2hex (const gdb_byte *bin, char *hex, size_t count);
+
 #endif
diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c
new file mode 100644
index 0000000..c1af63d
--- /dev/null
+++ b/gdb/common/linux-maps.c
@@ -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;
+}
+
+
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
new file mode 100644
index 0000000..b8725ab
--- /dev/null
+++ b/gdb/common/linux-maps.h
@@ -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 */
diff --git a/gdb/common/xml-utils.h b/gdb/common/xml-utils.h
index ea4ab53..3c42183 100644
--- a/gdb/common/xml-utils.h
+++ b/gdb/common/xml-utils.h
@@ -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
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 8316d87..dd5cbd8 100644
--- a/gdb/config/i386/linux.mh
+++ b/gdb/config/i386/linux.mh
@@ -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
 
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index d2b95fd..b1f83a8 100644
--- a/gdb/config/i386/linux64.mh
+++ b/gdb/config/i386/linux64.mh
@@ -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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..5f4c956 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -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>
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index dffe8ae..744af57 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -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)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 93c499c..1fd2203 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -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
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index c52cd2e..1b60821 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 <stdio.h>
@@ -5633,6 +5634,154 @@ 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 (*nhdr, n_namesz)
+				       + HDR (*nhdr, n_descsz)
+				       + (p->is_elf64 ? sizeof (nhdr->_64)
+						      : sizeof (nhdr->_32));
+		      gdb_assert (*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 = 0;
+  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;
+  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 = xmalloc (build_idsz * 2 + 1);
+      if (bin2hex (raw_build_id, hex_build_id, build_idsz) != 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 (raw_build_id);
+  return hex_build_id;
+}
+
 /* Construct qXfer:libraries-svr4:read reply.  */
 
 static int
@@ -5754,6 +5903,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)
 		{
@@ -5762,7 +5912,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 + 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 +5927,15 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
 		  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);
+	      xfree (hex_enc_build_id);
 	    }
 	  else if (lm_prev == 0)
 	    {
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 42c6a54..4828140 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -20,6 +20,7 @@
 #include "terminal.h"
 #include "target.h"
 #include "gdbthread.h"
+#include "common-utils.h"
 #include <stdio.h>
 #include <string.h>
 #if HAVE_SYS_IOCTL_H
@@ -418,18 +419,6 @@ remote_close (void)
 
 /* Convert hex digit A to a number.  */
 
-static int
-fromhex (int a)
-{
-  if (a >= '0' && a <= '9')
-    return a - '0';
-  else if (a >= 'a' && a <= 'f')
-    return a - 'a' + 10;
-  else
-    error ("Reply contains invalid hex digit");
-  return 0;
-}
-
 #endif
 
 static const char hexchars[] = "0123456789abcdef";
@@ -460,20 +449,7 @@ ishex (int ch, int *val)
 int
 unhexify (char *bin, const char *hex, int count)
 {
-  int i;
-
-  for (i = 0; i < count; i++)
-    {
-      if (hex[0] == 0 || hex[1] == 0)
-	{
-	  /* Hex string is short, or of uneven length.
-	     Return the count that has been converted so far. */
-	  return i;
-	}
-      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
-      hex += 2;
-    }
-  return i;
+  return hex2bin (hex, (gdb_byte*)bin, count);
 }
 
 void
@@ -511,35 +487,13 @@ decode_address_to_semicolon (CORE_ADDR *addrp, const char *start)
 
 #endif
 
-/* Convert number NIB to a hex digit.  */
-
-static int
-tohex (int nib)
-{
-  if (nib < 10)
-    return '0' + nib;
-  else
-    return 'a' + nib - 10;
-}
 
 #ifndef IN_PROCESS_AGENT
 
 int
 hexify (char *hex, const char *bin, int count)
 {
-  int i;
-
-  /* May use a length, or a nul-terminated string as input. */
-  if (count == 0)
-    count = strlen (bin);
-
-  for (i = 0; i < count; i++)
-    {
-      *hex++ = tohex ((*bin >> 4) & 0xf);
-      *hex++ = tohex (*bin++ & 0xf);
-    }
-  *hex = 0;
-  return i;
+  return bin2hex ((gdb_byte*)bin, hex, count);
 }
 
 /* Convert BUFFER, binary data at least LEN bytes long, into escaped
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 04afbb1..22dc4f0 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -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 *gdbarch, ptid_t ptid)
   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 *gdbarch, char *args,
     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 gdbarch *gdbarch,
   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 (struct gdbarch *gdbarch, bfd *obfd,
   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)
     {
diff --git a/gdb/remote.c b/gdb/remote.c
index 88a57c8..cf5755d 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -123,8 +123,6 @@ static int readchar (int timeout);
 
 static void remote_kill (struct target_ops *ops);
 
-static int tohex (int nib);
-
 static int remote_can_async_p (void);
 
 static int remote_is_async_p (void);
@@ -181,12 +179,6 @@ static void remote_find_new_threads (void);
 
 static void record_currthread (ptid_t currthread);
 
-static int fromhex (int a);
-
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
 static int putpkt_binary (char *buf, int cnt);
 
 static void check_binary_download (CORE_ADDR addr);
@@ -4550,68 +4542,6 @@ extended_remote_attach (struct target_ops *ops, char *args, int from_tty)
   extended_remote_attach_1 (ops, args, from_tty);
 }
 
-/* Convert hex digit A to a number.  */
-
-static int
-fromhex (int a)
-{
-  if (a >= '0' && a <= '9')
-    return a - '0';
-  else if (a >= 'a' && a <= 'f')
-    return a - 'a' + 10;
-  else if (a >= 'A' && a <= 'F')
-    return a - 'A' + 10;
-  else
-    error (_("Reply contains invalid hex digit %d"), a);
-}
-
-int
-hex2bin (const char *hex, gdb_byte *bin, int count)
-{
-  int i;
-
-  for (i = 0; i < count; i++)
-    {
-      if (hex[0] == 0 || hex[1] == 0)
-	{
-	  /* Hex string is short, or of uneven length.
-	     Return the count that has been converted so far.  */
-	  return i;
-	}
-      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
-      hex += 2;
-    }
-  return i;
-}
-
-/* Convert number NIB to a hex digit.  */
-
-static int
-tohex (int nib)
-{
-  if (nib < 10)
-    return '0' + nib;
-  else
-    return 'a' + nib - 10;
-}
-
-int
-bin2hex (const gdb_byte *bin, char *hex, int count)
-{
-  int i;
-
-  /* May use a length, or a nul-terminated string as input.  */
-  if (count == 0)
-    count = strlen ((char *) bin);
-
-  for (i = 0; i < count; i++)
-    {
-      *hex++ = tohex ((*bin >> 4) & 0xf);
-      *hex++ = tohex (*bin++ & 0xf);
-    }
-  *hex = 0;
-  return i;
-}
 \f
 /* Check for the availability of vCont.  This function should also check
    the response.  */
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index ca104aa..c4e6034 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -69,9 +69,6 @@
 #define O_LARGEFILE 0
 #endif
 
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
 /* Maximum length of an agent aexpression.
    This accounts for the fact that packets are limited to 400 bytes
    (which includes everything -- including the checksum), and assumes
diff --git a/gdb/utils.c b/gdb/utils.c
index eb99f4b..484402c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3309,104 +3309,6 @@ dummy_obstack_deallocate (void *object, void *data)
   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.  */
diff --git a/gdb/utils.h b/gdb/utils.h
index 52bcaff..a5b643c 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -39,8 +39,6 @@ extern int streq (const char *, const char *);
 
 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);
 
-- 
1.7.10.4


[-- Attachment #3: gdbserver-doc-201302271220.patch --]
[-- Type: text/x-patch, Size: 1313 bytes --]

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5f39d2e..32e63e1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40144,6 +40144,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
@@ -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 described by this DTD:
 <!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

WARNING: multiple messages have this Message-ID
From: Aleksandar Ristovski <aristovski@qnx.com>
To: gdb-patches@sourceware.org
Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>,
	 Jan Kratochvil <jan.kratochvil@redhat.com>
Subject: Re: [patch] gdbserver build-id in qxfer_libraries reply
Date: Wed, 27 Feb 2013 17:31:00 -0000	[thread overview]
Message-ID: <512E4169.7080506@qnx.com> (raw)
Message-ID: <20130227173100.EyD87XcSypQtn1AH0f1DPXQ8CNGYW9VlkSHV-QBbaTo@z> (raw)
In-Reply-To: <512CA419.7020806@redhat.com>

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

On 13-02-26 07:01 AM, Pedro Alves wrote:
> Hi Aleksandar,
>
> Thanks for the patch.

Thanks for looking at the patch.

>
> On 02/22/2013 06:38 PM, Aleksandar Ristovski wrote:
>>>
>>> Majority of the patch is refactoring to reuse code.
>
> I'm reading the patch, but one immediate question I have
> is where did hex_encode/hex_decode and friends got refactored
> from?  It seems we end up with multiple functions to do the same
> in both gdb and gdbserver, given the existence of bin2hex etc
> in gdb and unhexify/hexify in gdbserver?

apparently I was grepping *h files. I moved bin2hex and hex2bin to 
common-utils. New patch attached, along with documentation patch.

Note there is a small change in linux-low.c in that new patch passes 
exactly note size instead of using PT_NOTE pheaders p_memsz.

>
>>   The real change is
>>> in gdbserver/linux-low.c.
>

---
Aleksandar



ChangeLog followed by doc/ChangeLog


     DATE  Aleksandar Ristovski  <aristovski@qnx.com>

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

     	* 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.
     	(fromhex): Moved from remote.c.
     	(hex2bin): Ditto.
     	(tohex): Ditto.
     	(bin2hex): Ditto.

     	* common/common-utils.h (strtoulst): Moved from utils.h.
     	(tohex): New declaration.
     	(fromhex): Ditto.
     	(hex2bin): Ditto.
     	(bin2hex): Ditto.

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

     	* config/i386/linux.mk (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.

     	* remote-utils.c (common-utils.h): Include.
     	(fromhex): Moved to common-utils.c.
     	(unhexify): Use hex2bin.
     	(tohex): Moved to common-utils.c.
     	(hexify): Use bin2hex.

     	* 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.

     	* remote.c (tohex): Remove forward declaration.
     	(fromhex): Ditto.
     	(hex2bin): Ditto.
     	(bin2hex): Ditto.
     	(fromhex): Move implementation to common-utils.c
     	(hex2bin): Ditto.
     	(tohex): Ditto.
     	(bin2hex): Ditto.

     	* tracepoint.c (hex2bin): Remove declaration.
     	(bin2hex): 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.



doc/ChangeLog:
     DATE  Aleksandar Ristovski  <aristovski@qnx.com>

         * 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-in-qxfer_libraries-reply-201302271218.patch --]
[-- Type: text/x-patch, Size: 42623 bytes --]

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ed30db5..dae451b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -771,7 +771,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
 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)
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 4204abf..780ba09 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -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,175 @@ 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
+/* Convert hex digit A to a number.  */
+
+int
+fromhex (int a)
+{
+  if (a >= '0' && a <= '9')
+    return a - '0';
+  else if (a >= 'a' && a <= 'f')
+    return a - 'a' + 10;
+  else if (a >= 'A' && a <= 'F')
+    return a - 'A' + 10;
+  return -1;
+}
+
+size_t
+hex2bin (const char *hex, gdb_byte *bin, size_t count)
+{
+  size_t i;
+
+  for (i = 0; i < count; i++)
+    {
+      int hi, lo;
+
+      if (hex[0] == 0 || hex[1] == 0
+	  || (hi = fromhex (hex[0])) < 0
+	  || (lo = fromhex (hex[1])) < 0)
+	{
+	  /* Hex string is short, or of uneven length or malformed.
+	     Return the count that has been converted so far.  */
+	  warning (_("Malformed hex encoded string: '%s'\n"), hex);
+	  return i;
+	}
+
+      *bin++ = hi * 16 + lo;
+      hex += 2;
+    }
+  return i;
+}
+
+
+/* Convert number NIB to a hex digit.  */
+
+int
+tohex (int nib)
+{
+  if (nib < 10)
+    return '0' + nib;
+  else
+    return 'a' + nib - 10;
+}
+
+size_t
+bin2hex (const gdb_byte *bin, char *hex, size_t count)
+{
+  size_t i;
+
+  /* May use a length, or a nul-terminated string as input.  */
+  if (count == 0)
+    count = strlen ((char *) bin);
+
+  for (i = 0; i < count; i++)
+    {
+      *hex++ = tohex ((*bin >> 4) & 0xf);
+      *hex++ = tohex (*bin++ & 0xf);
+    }
+  *hex = 0;
+  return i;
+}
+
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 9b659d8..9ce5da2 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -53,4 +53,14 @@ int xsnprintf (char *str, size_t size, const char *format, ...)
 
 char *savestring (const char *ptr, size_t len);
 
+extern ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+extern int tohex (int nib);
+
+extern int fromhex (int a);
+
+extern size_t hex2bin (const char *hex, gdb_byte *bin, size_t count);
+
+extern size_t bin2hex (const gdb_byte *bin, char *hex, size_t count);
+
 #endif
diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c
new file mode 100644
index 0000000..c1af63d
--- /dev/null
+++ b/gdb/common/linux-maps.c
@@ -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;
+}
+
+
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
new file mode 100644
index 0000000..b8725ab
--- /dev/null
+++ b/gdb/common/linux-maps.h
@@ -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 */
diff --git a/gdb/common/xml-utils.h b/gdb/common/xml-utils.h
index ea4ab53..3c42183 100644
--- a/gdb/common/xml-utils.h
+++ b/gdb/common/xml-utils.h
@@ -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
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 8316d87..dd5cbd8 100644
--- a/gdb/config/i386/linux.mh
+++ b/gdb/config/i386/linux.mh
@@ -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
 
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index d2b95fd..b1f83a8 100644
--- a/gdb/config/i386/linux64.mh
+++ b/gdb/config/i386/linux64.mh
@@ -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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..5f4c956 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -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>
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index dffe8ae..744af57 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -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)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 93c499c..1fd2203 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -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
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index c52cd2e..1b60821 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 <stdio.h>
@@ -5633,6 +5634,154 @@ 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 (*nhdr, n_namesz)
+				       + HDR (*nhdr, n_descsz)
+				       + (p->is_elf64 ? sizeof (nhdr->_64)
+						      : sizeof (nhdr->_32));
+		      gdb_assert (*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 = 0;
+  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;
+  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 = xmalloc (build_idsz * 2 + 1);
+      if (bin2hex (raw_build_id, hex_build_id, build_idsz) != 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 (raw_build_id);
+  return hex_build_id;
+}
+
 /* Construct qXfer:libraries-svr4:read reply.  */
 
 static int
@@ -5754,6 +5903,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)
 		{
@@ -5762,7 +5912,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 + 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 +5927,15 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
 		  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);
+	      xfree (hex_enc_build_id);
 	    }
 	  else if (lm_prev == 0)
 	    {
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 42c6a54..4828140 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -20,6 +20,7 @@
 #include "terminal.h"
 #include "target.h"
 #include "gdbthread.h"
+#include "common-utils.h"
 #include <stdio.h>
 #include <string.h>
 #if HAVE_SYS_IOCTL_H
@@ -418,18 +419,6 @@ remote_close (void)
 
 /* Convert hex digit A to a number.  */
 
-static int
-fromhex (int a)
-{
-  if (a >= '0' && a <= '9')
-    return a - '0';
-  else if (a >= 'a' && a <= 'f')
-    return a - 'a' + 10;
-  else
-    error ("Reply contains invalid hex digit");
-  return 0;
-}
-
 #endif
 
 static const char hexchars[] = "0123456789abcdef";
@@ -460,20 +449,7 @@ ishex (int ch, int *val)
 int
 unhexify (char *bin, const char *hex, int count)
 {
-  int i;
-
-  for (i = 0; i < count; i++)
-    {
-      if (hex[0] == 0 || hex[1] == 0)
-	{
-	  /* Hex string is short, or of uneven length.
-	     Return the count that has been converted so far. */
-	  return i;
-	}
-      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
-      hex += 2;
-    }
-  return i;
+  return hex2bin (hex, (gdb_byte*)bin, count);
 }
 
 void
@@ -511,35 +487,13 @@ decode_address_to_semicolon (CORE_ADDR *addrp, const char *start)
 
 #endif
 
-/* Convert number NIB to a hex digit.  */
-
-static int
-tohex (int nib)
-{
-  if (nib < 10)
-    return '0' + nib;
-  else
-    return 'a' + nib - 10;
-}
 
 #ifndef IN_PROCESS_AGENT
 
 int
 hexify (char *hex, const char *bin, int count)
 {
-  int i;
-
-  /* May use a length, or a nul-terminated string as input. */
-  if (count == 0)
-    count = strlen (bin);
-
-  for (i = 0; i < count; i++)
-    {
-      *hex++ = tohex ((*bin >> 4) & 0xf);
-      *hex++ = tohex (*bin++ & 0xf);
-    }
-  *hex = 0;
-  return i;
+  return bin2hex ((gdb_byte*)bin, hex, count);
 }
 
 /* Convert BUFFER, binary data at least LEN bytes long, into escaped
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 04afbb1..22dc4f0 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -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 *gdbarch, ptid_t ptid)
   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 *gdbarch, char *args,
     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 gdbarch *gdbarch,
   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 (struct gdbarch *gdbarch, bfd *obfd,
   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)
     {
diff --git a/gdb/remote.c b/gdb/remote.c
index 88a57c8..cf5755d 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -123,8 +123,6 @@ static int readchar (int timeout);
 
 static void remote_kill (struct target_ops *ops);
 
-static int tohex (int nib);
-
 static int remote_can_async_p (void);
 
 static int remote_is_async_p (void);
@@ -181,12 +179,6 @@ static void remote_find_new_threads (void);
 
 static void record_currthread (ptid_t currthread);
 
-static int fromhex (int a);
-
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
 static int putpkt_binary (char *buf, int cnt);
 
 static void check_binary_download (CORE_ADDR addr);
@@ -4550,68 +4542,6 @@ extended_remote_attach (struct target_ops *ops, char *args, int from_tty)
   extended_remote_attach_1 (ops, args, from_tty);
 }
 
-/* Convert hex digit A to a number.  */
-
-static int
-fromhex (int a)
-{
-  if (a >= '0' && a <= '9')
-    return a - '0';
-  else if (a >= 'a' && a <= 'f')
-    return a - 'a' + 10;
-  else if (a >= 'A' && a <= 'F')
-    return a - 'A' + 10;
-  else
-    error (_("Reply contains invalid hex digit %d"), a);
-}
-
-int
-hex2bin (const char *hex, gdb_byte *bin, int count)
-{
-  int i;
-
-  for (i = 0; i < count; i++)
-    {
-      if (hex[0] == 0 || hex[1] == 0)
-	{
-	  /* Hex string is short, or of uneven length.
-	     Return the count that has been converted so far.  */
-	  return i;
-	}
-      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
-      hex += 2;
-    }
-  return i;
-}
-
-/* Convert number NIB to a hex digit.  */
-
-static int
-tohex (int nib)
-{
-  if (nib < 10)
-    return '0' + nib;
-  else
-    return 'a' + nib - 10;
-}
-
-int
-bin2hex (const gdb_byte *bin, char *hex, int count)
-{
-  int i;
-
-  /* May use a length, or a nul-terminated string as input.  */
-  if (count == 0)
-    count = strlen ((char *) bin);
-
-  for (i = 0; i < count; i++)
-    {
-      *hex++ = tohex ((*bin >> 4) & 0xf);
-      *hex++ = tohex (*bin++ & 0xf);
-    }
-  *hex = 0;
-  return i;
-}
 \f
 /* Check for the availability of vCont.  This function should also check
    the response.  */
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index ca104aa..c4e6034 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -69,9 +69,6 @@
 #define O_LARGEFILE 0
 #endif
 
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
 /* Maximum length of an agent aexpression.
    This accounts for the fact that packets are limited to 400 bytes
    (which includes everything -- including the checksum), and assumes
diff --git a/gdb/utils.c b/gdb/utils.c
index eb99f4b..484402c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3309,104 +3309,6 @@ dummy_obstack_deallocate (void *object, void *data)
   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.  */
diff --git a/gdb/utils.h b/gdb/utils.h
index 52bcaff..a5b643c 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -39,8 +39,6 @@ extern int streq (const char *, const char *);
 
 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);
 
-- 
1.7.10.4


[-- Attachment #3: gdbserver-doc-201302271220.patch --]
[-- Type: text/x-patch, Size: 1313 bytes --]

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5f39d2e..32e63e1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40144,6 +40144,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
@@ -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 described by this DTD:
 <!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

  reply	other threads:[~2013-02-27 17:25 UTC|newest]

Thread overview: 79+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-22 15:07 Aleksandar Ristovski
2013-02-22 18:39 ` Aleksandar Ristovski
2013-02-26 12:01   ` Pedro Alves
2013-02-27 17:25     ` Aleksandar Ristovski [this message]
2013-02-27 17:31       ` Aleksandar Ristovski
2013-02-27 18:44       ` Eli Zaretskii
2013-03-10 21:07 ` [draft patch 0/6] Split FYI and some review notes Jan Kratochvil
2013-03-11 14:25   ` Aleksandar Ristovski
2013-03-11 15:07     ` Jan Kratochvil
2013-03-14 18:43       ` Gary Benson
2013-03-14 19:55         ` Tom Tromey
2013-03-15 15:35         ` Aleksandar Ristovski
2013-03-15 15:44   ` Aleksandar Ristovski
2013-03-15 15:38     ` Aleksandar Ristovski
2013-03-15 16:28     ` Jan Kratochvil
2013-03-15 16:43       ` Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 2/6] Merge multiple hex conversions Jan Kratochvil
2013-03-22 13:05   ` [patch " Aleksandar Ristovski
2013-04-05 16:07     ` Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 1/6] Move utility functions to common/ Jan Kratochvil
2013-03-22 13:13   ` [patch " Aleksandar Ristovski
2013-03-22 13:05     ` Aleksandar Ristovski
2013-04-07 18:54     ` Aleksandar Ristovski
2013-04-05 13:06       ` Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 3/6] Create empty common/linux-maps.[ch] Jan Kratochvil
2013-03-22 14:54   ` [patch " Aleksandar Ristovski
2013-03-22 13:06     ` Aleksandar Ristovski
2013-04-05 13:25     ` Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 4/6] Prepare linux_find_memory_regions_full & co. for move Jan Kratochvil
2013-03-22 13:34   ` [patch " Aleksandar Ristovski
2013-03-22 13:54     ` Aleksandar Ristovski
2013-03-26 18:11     ` Jan Kratochvil
2013-03-27 20:44       ` Aleksandar Ristovski
2013-03-27 21:54         ` Aleksandar Ristovski
2013-03-28 23:02         ` Jan Kratochvil
2013-03-29  0:26           ` Aleksandar Ristovski
2013-03-29  0:29             ` Pedro Alves
2013-04-01 22:39           ` Aleksandar Ristovski
2013-04-01 21:13             ` Aleksandar Ristovski
2013-04-02 13:41             ` Jan Kratochvil
2013-04-02 13:41               ` Aleksandar Ristovski
2013-04-02 13:41                 ` Jan Kratochvil
2013-04-05 15:37                   ` Aleksandar Ristovski
2013-04-07 14:28                     ` Aleksandar Ristovski
2013-03-10 21:09 ` [draft patch 5/6] Move linux_find_memory_regions_full & co Jan Kratochvil
2013-03-22 13:05   ` [patch " Aleksandar Ristovski
2013-03-22 13:34     ` Aleksandar Ristovski
2013-03-26 18:27     ` Jan Kratochvil
2013-03-27 21:25       ` Aleksandar Ristovski
2013-03-28 22:38         ` Jan Kratochvil
2013-04-01 23:19           ` Aleksandar Ristovski
2013-04-02  2:33             ` Aleksandar Ristovski
2013-04-02  2:33             ` Jan Kratochvil
2013-04-07 18:54               ` Aleksandar Ristovski
2013-04-05 15:37                 ` Aleksandar Ristovski
2013-03-10 21:09 ` [draft patch 6/6] gdbserver build-id attribute generator (unfixed) Jan Kratochvil
2013-03-10 22:04   ` Eli Zaretskii
2013-03-22 13:05   ` [patch 6/6] gdbserver build-id attribute generator Aleksandar Ristovski
2013-03-22 15:19     ` Aleksandar Ristovski
2013-03-22 17:24     ` Eli Zaretskii
2013-03-26 23:45     ` Jan Kratochvil
2013-03-27 17:54       ` Aleksandar Ristovski
2013-03-27 18:08         ` Jan Kratochvil
2013-03-27 18:12           ` Eli Zaretskii
2013-03-27 20:46           ` Aleksandar Ristovski
2013-03-29  0:13             ` Aleksandar Ristovski
2013-03-29  0:20               ` Aleksandar Ristovski
2013-03-29 16:19               ` Jan Kratochvil
     [not found]               ` <20130331174322.GB21374@host2.jankratochvil.net>
2013-04-02 17:18                 ` Aleksandar Ristovski
2013-04-04  2:22                   ` Jan Kratochvil
2013-04-05 15:05                     ` Aleksandar Ristovski
2013-04-09 15:28                       ` Gary Benson
2013-04-09 15:28                         ` Aleksandar Ristovski
2013-04-09 19:26                           ` Gary Benson
2013-04-12 15:28                             ` Jan Kratochvil
2013-04-09 15:28                         ` Jan Kratochvil
2013-04-09 15:29                           ` Aleksandar Ristovski
2013-04-09 15:29                           ` Gary Benson
2013-04-04 16:08 ` [patch] gdbserver build-id in qxfer_libraries reply Jan Kratochvil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=512E4169.7080506@qnx.com \
    --to=aristovski@qnx.com \
    --cc=gdb-patches@sourceware.org \
    --cc=jan.kratochvil@redhat.com \
    --cc=palves@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox