This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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.


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;
 }
+
+
+/* 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;
+}
+
+
+/* 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;
-}
 
 /* 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

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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]