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]

[patch] gdbserver build-id in qxfer_libraries reply


Hello,

This is related to: http://sourceware.org/ml/gdb-patches/2013-01/msg00748.html. Changes from this patch are needed to finish off the work started in that thread.

As per Jan's request, this patch adds 'build-id' to the gdbserver response. The value is hex encoded string representing .note.gnu.build-id section of the corresponding shared library.

Majority of the patch is refactoring to reuse code. The real change is in gdbserver/linux-low.c.

Thanks,

Aleksandar Ristovski
QNX Software Systems


ChangeLog:


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

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

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

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

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

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

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

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

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

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

* 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.
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1238
diff -u -p -r1.1238 Makefile.in
--- gdb/Makefile.in	8 Feb 2013 09:00:34 -0000	1.1238
+++ gdb/Makefile.in	22 Feb 2013 14:53:09 -0000
@@ -771,7 +771,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFI
 
 HFILES_NO_SRCDIR = \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-maps.h common/linux-ptrace.h \
 proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
 ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -1945,6 +1945,10 @@ format.o: ${srcdir}/common/format.c
 	$(COMPILE) $(srcdir)/common/format.c
 	$(POSTCOMPILE)
 
+linux-maps.o: ${srcdir}/common/linux-maps.c
+	$(COMPILE) $(srcdir)/common/linux-maps.c
+	$(POSTCOMPILE)
+
 linux-osdata.o: ${srcdir}/common/linux-osdata.c
 	$(COMPILE) $(srcdir)/common/linux-osdata.c
 	$(POSTCOMPILE)
Index: gdb/linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-tdep.c,v
retrieving revision 1.27
diff -u -p -r1.27 linux-tdep.c
--- gdb/linux-tdep.c	4 Feb 2013 18:40:41 -0000	1.27
+++ gdb/linux-tdep.c	22 Feb 2013 14:53:09 -0000
@@ -33,6 +33,7 @@
 #include "arch-utils.h"
 #include "gdb_obstack.h"
 #include "cli/cli-utils.h"
+#include "linux-maps.h"
 
 #include <ctype.h>
 
@@ -207,46 +208,7 @@ linux_core_pid_to_str (struct gdbarch *g
   return normal_pid_to_str (ptid);
 }
 
-/* Service function for corefiles and info proc.  */
 
-static void
-read_mapping (const char *line,
-	      ULONGEST *addr, ULONGEST *endaddr,
-	      const char **permissions, size_t *permissions_len,
-	      ULONGEST *offset,
-              const char **device, size_t *device_len,
-	      ULONGEST *inode,
-	      const char **filename)
-{
-  const char *p = line;
-
-  *addr = strtoulst (p, &p, 16);
-  if (*p == '-')
-    p++;
-  *endaddr = strtoulst (p, &p, 16);
-
-  while (*p && isspace (*p))
-    p++;
-  *permissions = p;
-  while (*p && !isspace (*p))
-    p++;
-  *permissions_len = p - *permissions;
-
-  *offset = strtoulst (p, &p, 16);
-
-  while (*p && isspace (*p))
-    p++;
-  *device = p;
-  while (*p && !isspace (*p))
-    p++;
-  *device_len = p - *device;
-
-  *inode = strtoulst (p, &p, 10);
-
-  while (*p && isspace (*p))
-    p++;
-  *filename = p;
-}
 
 /* Implement the "info proc" command.  */
 
@@ -666,101 +628,6 @@ linux_core_info_proc (struct gdbarch *gd
     error (_("unable to handle request"));
 }
 
-typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
-					    ULONGEST offset, ULONGEST inode,
-					    int read, int write,
-					    int exec, int modified,
-					    const char *filename,
-					    void *data);
-
-/* List memory regions in the inferior for a corefile.  */
-
-static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
-				linux_find_memory_region_ftype *func,
-				void *obfd)
-{
-  char filename[100];
-  gdb_byte *data;
-
-  /* We need to know the real target PID to access /proc.  */
-  if (current_inferior ()->fake_pid_p)
-    return 1;
-
-  xsnprintf (filename, sizeof filename,
-	     "/proc/%d/smaps", current_inferior ()->pid);
-  data = target_fileio_read_stralloc (filename);
-  if (data == NULL)
-    {
-      /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (filename, sizeof filename,
-		 "/proc/%d/maps", current_inferior ()->pid);
-      data = target_fileio_read_stralloc (filename);
-    }
-  if (data)
-    {
-      struct cleanup *cleanup = make_cleanup (xfree, data);
-      char *line;
-
-      line = strtok (data, "\n");
-      while (line)
-	{
-	  ULONGEST addr, endaddr, offset, inode;
-	  const char *permissions, *device, *filename;
-	  size_t permissions_len, device_len;
-	  int read, write, exec;
-	  int modified = 0, has_anonymous = 0;
-
-	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
-			&offset, &device, &device_len, &inode, &filename);
-
-	  /* Decode permissions.  */
-	  read = (memchr (permissions, 'r', permissions_len) != 0);
-	  write = (memchr (permissions, 'w', permissions_len) != 0);
-	  exec = (memchr (permissions, 'x', permissions_len) != 0);
-
-	  /* Try to detect if region was modified by parsing smaps counters.  */
-	  for (line = strtok (NULL, "\n");
-	       line && line[0] >= 'A' && line[0] <= 'Z';
-	       line = strtok (NULL, "\n"))
-	    {
-	      char keyword[64 + 1];
-	      unsigned long number;
-
-	      if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
-		{
-		  warning (_("Error parsing {s,}maps file '%s'"), filename);
-		  break;
-		}
-	      if (strcmp (keyword, "Anonymous:") == 0)
-		has_anonymous = 1;
-	      if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
-				  || strcmp (keyword, "Private_Dirty:") == 0
-				  || strcmp (keyword, "Swap:") == 0
-				  || strcmp (keyword, "Anonymous:") == 0))
-		modified = 1;
-	    }
-
-	  /* Older Linux kernels did not support the "Anonymous:" counter.
-	     If it is missing, we can't be sure - dump all the pages.  */
-	  if (!has_anonymous)
-	    modified = 1;
-
-	  /* Invoke the callback function to create the corefile segment.  */
-	  func (addr, endaddr - addr, offset, inode,
-		read, write, exec, modified, filename, obfd);
-	}
-
-      do_cleanups (cleanup);
-      return 0;
-    }
-
-  return 1;
-}
-
-/* A structure for passing information through
-   linux_find_memory_regions_full.  */
-
 struct linux_find_memory_regions_data
 {
   /* The original callback.  */
@@ -798,7 +665,10 @@ linux_find_memory_regions (struct gdbarc
   data.func = func;
   data.obfd = obfd;
 
-  return linux_find_memory_regions_full (gdbarch,
+  if (current_inferior ()->fake_pid_p)
+    return 1;
+
+  return linux_find_memory_regions_full (current_inferior ()->pid,
 					 linux_find_memory_regions_thunk,
 					 &data);
 }
@@ -982,8 +852,10 @@ linux_make_mappings_corefile_notes (stru
   pack_long (buf, long_type, 1);
   obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));
 
-  linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback,
-				  &mapping_data);
+  if (!current_inferior ()->fake_pid_p)
+    linux_find_memory_regions_full (current_inferior ()->pid,
+				    linux_make_mappings_callback,
+				    &mapping_data);
 
   if (mapping_data.file_count != 0)
     {
Index: gdb/utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.292
diff -u -p -r1.292 utils.c
--- gdb/utils.c	14 Feb 2013 17:11:41 -0000	1.292
+++ gdb/utils.c	22 Feb 2013 14:53:09 -0000
@@ -3309,104 +3309,6 @@ dummy_obstack_deallocate (void *object, 
   return;
 }
 
-/* The bit offset of the highest byte in a ULONGEST, for overflow
-   checking.  */
-
-#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
-
-/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
-   where 2 <= BASE <= 36.  */
-
-static int
-is_digit_in_base (unsigned char digit, int base)
-{
-  if (!isalnum (digit))
-    return 0;
-  if (base <= 10)
-    return (isdigit (digit) && digit < base + '0');
-  else
-    return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
-}
-
-static int
-digit_to_int (unsigned char c)
-{
-  if (isdigit (c))
-    return c - '0';
-  else
-    return tolower (c) - 'a' + 10;
-}
-
-/* As for strtoul, but for ULONGEST results.  */
-
-ULONGEST
-strtoulst (const char *num, const char **trailer, int base)
-{
-  unsigned int high_part;
-  ULONGEST result;
-  int minus = 0;
-  int i = 0;
-
-  /* Skip leading whitespace.  */
-  while (isspace (num[i]))
-    i++;
-
-  /* Handle prefixes.  */
-  if (num[i] == '+')
-    i++;
-  else if (num[i] == '-')
-    {
-      minus = 1;
-      i++;
-    }
-
-  if (base == 0 || base == 16)
-    {
-      if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X'))
-	{
-	  i += 2;
-	  if (base == 0)
-	    base = 16;
-	}
-    }
-
-  if (base == 0 && num[i] == '0')
-    base = 8;
-
-  if (base == 0)
-    base = 10;
-
-  if (base < 2 || base > 36)
-    {
-      errno = EINVAL;
-      return 0;
-    }
-
-  result = high_part = 0;
-  for (; is_digit_in_base (num[i], base); i += 1)
-    {
-      result = result * base + digit_to_int (num[i]);
-      high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN);
-      result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
-      if (high_part > 0xff)
-	{
-	  errno = ERANGE;
-	  result = ~ (ULONGEST) 0;
-	  high_part = 0;
-	  minus = 0;
-	  break;
-	}
-    }
-
-  if (trailer != NULL)
-    *trailer = &num[i];
-
-  result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
-  if (minus)
-    return -result;
-  else
-    return result;
-}
 
 /* Simple, portable version of dirname that does not modify its
    argument.  */
Index: gdb/utils.h
===================================================================
RCS file: /cvs/src/src/gdb/utils.h,v
retrieving revision 1.5
diff -u -p -r1.5 utils.h
--- gdb/utils.h	3 Feb 2013 15:54:17 -0000	1.5
+++ gdb/utils.h	22 Feb 2013 14:53:09 -0000
@@ -39,8 +39,6 @@ extern int streq (const char *, const ch
 
 extern int subset_compare (char *, char *);
 
-ULONGEST strtoulst (const char *num, const char **trailer, int base);
-
 int compare_positive_ints (const void *ap, const void *bp);
 int compare_strings (const void *ap, const void *bp);
 
Index: gdb/common/common-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/common/common-utils.c,v
retrieving revision 1.5
diff -u -p -r1.5 common-utils.c
--- gdb/common/common-utils.c	14 Feb 2013 17:11:41 -0000	1.5
+++ gdb/common/common-utils.c	22 Feb 2013 14:53:09 -0000
@@ -19,6 +19,15 @@
 
 #ifdef GDBSERVER
 #include "server.h"
+
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT (sizeof (char) * 8)
+#endif /* ! TARGET_CHAR_BIT  */
+
+#if !defined (HOST_CHAR_BIT)
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif /* ! HOST_CHAR_BIT */
+
 #else
 #include "defs.h"
 #endif
@@ -28,6 +37,9 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
 
 /* The xmalloc() (libiberty.h) family of memory management routines.
 
@@ -161,3 +173,187 @@ savestring (const char *ptr, size_t len)
   p[len] = 0;
   return p;
 }
+
+
+/* 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;
+}
+
+
+
+static const char hchar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+			      'a', 'b', 'c', 'd', 'e', 'f' };
+
+/* Encode SIZE bytes from TEXT in hexadecimal format.  Return
+   malloc allocated buffer of size SIZE * 2 + 1.  */
+
+char *
+hex_encode (const void *const text, const size_t size)
+{
+  char *buf = xmalloc (size * 2 + 1);
+  size_t i;
+  const char *const t = text;
+
+  assert (text != NULL);
+
+  for (i = 0; i != size; ++i)
+    {
+      buf[i << 1] = hchar[(t[i] & 0xF0) >> 4];
+      buf[(i << 1) + 1] = hchar[t[i] & 0x0F];
+    }
+
+  buf[size * 2] = '\0';
+
+  return buf;
+}
+
+
+/* Helper function, decodes hex. char H into integer
+   integer value [0 - 15].  If H is not valid character
+   returns -1.  */
+static int
+decode_hex_ch (const char h)
+{
+  if (h >= '0' && h <= '9')
+    return h - '0';
+
+  if (h >= 'a' && h <= 'f')
+    return h + 10 - 'a';
+
+  if (h >= 'A' && h <= 'F')
+    return h + 10 - 'A';
+
+  return -1;
+}
+
+/* Decode hex encoded HEXTEXT and return malloc allocated buffer
+   of size SZ.  */
+
+void *
+hex_decode (const char *const hextext, size_t *sz)
+{
+  char *buf;
+  size_t len;
+  size_t i;
+
+  assert (hextext != NULL);
+  assert (sz != NULL);
+
+  len = strlen (hextext);
+  *sz = (len + 1) >> 1;
+  buf = xmalloc (*sz);
+
+  for (i = 0; i < len; i+=2)
+    {
+      int hi, lo;
+
+      hi = decode_hex_ch (hextext[i]);
+      lo = decode_hex_ch (hextext[i+1]);
+      if (hi < 0 || lo < 0)
+	{
+	  /* Return only what was decoded so far. */
+	  *sz = i >> 1; /* Successfully decoded bytes.  */
+	  break;
+	}
+      buf[i >> 1] = (hi << 4) | lo;
+    }
+
+  return buf;
+}
+
Index: gdb/common/common-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/common/common-utils.h,v
retrieving revision 1.5
diff -u -p -r1.5 common-utils.h
--- gdb/common/common-utils.h	14 Feb 2013 17:11:41 -0000	1.5
+++ gdb/common/common-utils.h	22 Feb 2013 14:53:09 -0000
@@ -53,4 +53,10 @@ int xsnprintf (char *str, size_t size, c
 
 char *savestring (const char *ptr, size_t len);
 
+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+char *hex_encode (const void *text, size_t size);
+
+void *hex_decode (const char *hextext, size_t *size);
+
 #endif
Index: gdb/common/linux-maps.c
===================================================================
RCS file: gdb/common/linux-maps.c
diff -N gdb/common/linux-maps.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/common/linux-maps.c	22 Feb 2013 14:53:09 -0000
@@ -0,0 +1,217 @@
+/* Linux-specific memory maps manipulation routines.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#ifdef GDBSERVER
+#include "server.h"
+#include "linux-maps.h"
+#include <fcntl.h>
+#include <unistd.h>
+#else	/* ! GDBSERVER */
+#include "defs.h"
+#include "linux-maps.h"
+#include "target.h"
+#endif	/* ! GDBSERVER */
+
+#include <ctype.h>
+
+
+#ifdef GDBSERVER
+static char *
+fileio_read_stralloc (const char *const filename)
+{
+  char *buf;
+  int fd;
+  size_t buf_alloc;
+  size_t buf_pos;
+  const size_t buf_alloc_inc = 2 * 4096;
+
+  fd = open (filename, O_RDONLY);
+  if (fd == -1)
+    return NULL;
+
+  buf_alloc = 4096;
+  buf = xmalloc (buf_alloc);
+  buf_pos = 0;
+
+  while (1)
+    {
+      ssize_t n;
+
+      n = pread (fd, &buf[buf_pos], buf_alloc - buf_pos, buf_pos);
+
+      if (n < 0)
+	{
+	  xfree (buf);
+	  buf = NULL;
+	  break;
+	}
+      else if (n == 0)
+	{
+	  if (buf_pos == 0)
+	    {
+	      xfree (buf);
+	      buf = NULL;
+	    }
+	  break;
+	}
+      buf_pos += n;
+
+      if (buf_alloc < buf_pos + buf_alloc_inc)
+	{
+	  buf_alloc += buf_alloc_inc;
+	  buf = xrealloc (buf, buf_alloc);
+	}
+    }
+
+  if (close (fd) < 0)
+    warning (_("Error closing file descriptor: '%s'"), strerror (errno));
+
+  return buf;
+}
+
+#define target_fileio_read_stralloc(filename) fileio_read_stralloc (filename)
+
+#endif	/* GDBSERVER */
+
+/* Service function for corefiles and info proc.  */
+
+void
+read_mapping (const char *line,
+	      ULONGEST *addr, ULONGEST *endaddr,
+	      const char **permissions, size_t *permissions_len,
+	      ULONGEST *offset,
+              const char **device, size_t *device_len,
+	      ULONGEST *inode,
+	      const char **filename)
+{
+  const char *p = line;
+
+  *addr = strtoulst (p, &p, 16);
+  if (*p == '-')
+    p++;
+  *endaddr = strtoulst (p, &p, 16);
+
+  while (*p && isspace (*p))
+    p++;
+  *permissions = p;
+  while (*p && !isspace (*p))
+    p++;
+  *permissions_len = p - *permissions;
+
+  *offset = strtoulst (p, &p, 16);
+
+  while (*p && isspace (*p))
+    p++;
+  *device = p;
+  while (*p && !isspace (*p))
+    p++;
+  *device_len = p - *device;
+
+  *inode = strtoulst (p, &p, 10);
+
+  while (*p && isspace (*p))
+    p++;
+  *filename = p;
+}
+
+/* List memory regions in the inferior.
+   Return nonzero on error.  */
+
+int
+linux_find_memory_regions_full (pid_t pid,
+				linux_find_memory_region_ftype *func,
+				void *obfd)
+{
+  char filename[100];
+  char *data;
+
+  xsnprintf (filename, sizeof filename,
+	     "/proc/%d/smaps", pid);
+  data = target_fileio_read_stralloc (filename);
+  if (data == NULL)
+    {
+      /* Older Linux kernels did not support /proc/PID/smaps.  */
+      xsnprintf (filename, sizeof filename,
+		 "/proc/%d/maps", pid);
+      data = target_fileio_read_stralloc (filename);
+    }
+  if (data)
+    {
+      char *line;
+
+      line = strtok (data, "\n");
+      while (line)
+	{
+	  ULONGEST addr, endaddr, offset, inode;
+	  const char *permissions, *device, *filename;
+	  size_t permissions_len, device_len;
+	  int read, write, exec;
+	  int modified = 0, has_anonymous = 0;
+	  int ret;
+
+	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
+			&offset, &device, &device_len, &inode, &filename);
+
+	  /* Decode permissions.  */
+	  read = (memchr (permissions, 'r', permissions_len) != 0);
+	  write = (memchr (permissions, 'w', permissions_len) != 0);
+	  exec = (memchr (permissions, 'x', permissions_len) != 0);
+
+	  /* Try to detect if region was modified by parsing smaps counters.  */
+	  for (line = strtok (NULL, "\n");
+	       line && line[0] >= 'A' && line[0] <= 'Z';
+	       line = strtok (NULL, "\n"))
+	    {
+	      char keyword[64 + 1];
+	      unsigned long number;
+
+	      if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
+		{
+		  warning (_("Error parsing {s,}maps file '%s'"), filename);
+		  break;
+		}
+	      if (strcmp (keyword, "Anonymous:") == 0)
+		has_anonymous = 1;
+	      if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
+				  || strcmp (keyword, "Private_Dirty:") == 0
+				  || strcmp (keyword, "Swap:") == 0
+				  || strcmp (keyword, "Anonymous:") == 0))
+		modified = 1;
+	    }
+
+	  /* Older Linux kernels did not support the "Anonymous:" counter.
+	     If it is missing, we can't be sure - dump all the pages.  */
+	  if (!has_anonymous)
+	    modified = 1;
+
+	  /* Invoke the callback function to create the corefile segment.  */
+	  ret = func (addr, endaddr - addr, offset, inode,
+		      read, write, exec, modified, filename, obfd);
+	  if (ret)
+	    break;
+	}
+
+      xfree (data);
+      return 0;
+    }
+
+  return 1;
+}
+
+
Index: gdb/common/linux-maps.h
===================================================================
RCS file: gdb/common/linux-maps.h
diff -N gdb/common/linux-maps.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/common/linux-maps.h	22 Feb 2013 14:53:09 -0000
@@ -0,0 +1,50 @@
+/* Linux-specific memory maps manipulation routines.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef COMMON_LINUX_MAPS_H
+#define COMMON_LINUX_MAPS_H
+
+/* Function type for linux_find_memory_regions_full function.
+
+   Non zero returned breaks loop in linux_find_memory_regions_full.  */
+
+typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
+					    ULONGEST offset, ULONGEST inode,
+					    int read, int write,
+					    int exec, int modified,
+					    const char *filename,
+					    void *data);
+
+/* A structure for passing information through
+   linux_find_memory_regions_full.  */
+
+extern int linux_find_memory_regions_full (
+    pid_t pid,
+    linux_find_memory_region_ftype *func,
+    void *obfd);
+
+extern void read_mapping (const char *line,
+			  ULONGEST *addr, ULONGEST *endaddr,
+			  const char **permissions, size_t *permissions_len,
+			  ULONGEST *offset,
+			  const char **device, size_t *device_len,
+			  ULONGEST *inode,
+			  const char **filename);
+
+
+#endif /* COMMON_LINUX_MAPS_H */
Index: gdb/common/xml-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/common/xml-utils.h,v
retrieving revision 1.3
diff -u -p -r1.3 xml-utils.h
--- gdb/common/xml-utils.h	1 Jan 2013 06:32:54 -0000	1.3
+++ gdb/common/xml-utils.h	22 Feb 2013 14:53:09 -0000
@@ -25,4 +25,9 @@
 
 extern char *xml_escape_text (const char *text);
 
+/* Return a xmalloc allocated string with hex-encoded SIZE bytes from
+   TEXT.  */
+
+extern char *xml_hex_encode_text (const unsigned char *text, size_t size);
+
 #endif
Index: gdb/config/i386/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux.mh,v
retrieving revision 1.27
diff -u -p -r1.27 linux.mh
--- gdb/config/i386/linux.mh	13 Mar 2012 15:00:33 -0000	1.27
+++ gdb/config/i386/linux.mh	22 Feb 2013 14:53:09 -0000
@@ -3,7 +3,7 @@
 NAT_FILE= config/nm-linux.h
 NATDEPFILES= inf-ptrace.o fork-child.o \
 	i386-nat.o i386-linux-nat.o \
-	proc-service.o linux-thread-db.o \
+	proc-service.o linux-thread-db.o linux-maps.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o
 NAT_CDEPS = $(srcdir)/proc-service.list
 
Index: gdb/config/i386/linux64.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux64.mh,v
retrieving revision 1.13
diff -u -p -r1.13 linux64.mh
--- gdb/config/i386/linux64.mh	13 Mar 2012 15:00:34 -0000	1.13
+++ gdb/config/i386/linux64.mh	22 Feb 2013 14:53:09 -0000
@@ -1,7 +1,7 @@
 # Host: GNU/Linux x86-64
 NATDEPFILES= inf-ptrace.o fork-child.o \
 	i386-nat.o amd64-nat.o amd64-linux-nat.o \
-	linux-nat.o linux-osdata.o \
+	linux-maps.o linux-nat.o linux-osdata.o \
 	proc-service.o linux-thread-db.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o
 NAT_FILE= config/nm-linux.h
Index: gdb/gdbserver/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
retrieving revision 1.142
diff -u -p -r1.142 Makefile.in
--- gdb/gdbserver/Makefile.in	4 Feb 2013 18:20:04 -0000	1.142
+++ gdb/gdbserver/Makefile.in	22 Feb 2013 14:53:09 -0000
@@ -509,6 +509,9 @@ ax.o: ax.c
 signals.o: ../common/signals.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+linux-maps.o: ../common/linux-maps.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 linux-procfs.o: ../common/linux-procfs.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
Index: gdb/gdbserver/configure.srv
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.srv,v
retrieving revision 1.71
diff -u -p -r1.71 configure.srv
--- gdb/gdbserver/configure.srv	4 Feb 2013 18:20:05 -0000	1.71
+++ gdb/gdbserver/configure.srv	22 Feb 2013 14:53:09 -0000
@@ -46,6 +46,7 @@ case "${target}" in
 			srv_regobj="aarch64.o aarch64-without-fpu.o"
 			srv_tgtobj="linux-aarch64-low.o"
 			srv_tgtobj="${srv_tgtobj} linux-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-maps.o"
 			srv_tgtobj="${srv_tgtobj} linux-osdata.o"
 			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
@@ -61,7 +62,9 @@ case "${target}" in
 			srv_regobj="${srv_regobj} arm-with-vfpv2.o"
 			srv_regobj="${srv_regobj} arm-with-vfpv3.o"
 			srv_regobj="${srv_regobj} arm-with-neon.o"
-			srv_tgtobj="linux-low.o linux-osdata.o linux-arm-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+		        srv_tgtobj="${srv_tgtobj} linux-arm-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_xmlfiles="arm-with-iwmmxt.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
@@ -84,19 +87,25 @@ case "${target}" in
 			srv_mingwce=yes
 			;;
   bfin-*-*linux*)	srv_regobj=reg-bfin.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-bfin-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-bfin-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
 			srv_linux_thread_db=yes
 			;;
   crisv32-*-linux*)	srv_regobj=reg-crisv32.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-crisv32-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-crisv32-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
 			;;
   cris-*-linux*)	srv_regobj=reg-cris.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-cris-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-cris-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
 			srv_linux_thread_db=yes
@@ -111,7 +120,10 @@ case "${target}" in
 			    srv_regobj="$srv_regobj $srv_amd64_linux_regobj"
 			    srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles"
 			fi
-			srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-x86-low.o"
+			srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
@@ -146,12 +158,16 @@ case "${target}" in
 			srv_qnx="yes"
 			;;
   ia64-*-linux*)	srv_regobj=reg-ia64.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-ia64-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-ia64-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
 			;;
   m32r*-*-linux*)	srv_regobj=reg-m32r.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-m32r-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-m32r-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
  			srv_linux_thread_db=yes
@@ -161,7 +177,9 @@ case "${target}" in
                         else
                           srv_regobj=reg-m68k.o
                         fi
-			srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-m68k-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
@@ -172,7 +190,9 @@ case "${target}" in
                         else
                           srv_regobj=reg-m68k.o
                         fi
-			srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-m68k-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
@@ -182,7 +202,10 @@ case "${target}" in
 			srv_regobj="${srv_regobj} mips-dsp-linux.o"
 			srv_regobj="${srv_regobj} mips64-linux.o"
 			srv_regobj="${srv_regobj} mips64-dsp-linux.o"
-			srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o"
+			srv_tgtobj="${srv_tgtobj} linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-mips-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_xmlfiles="mips-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
@@ -215,7 +238,9 @@ case "${target}" in
 			srv_regobj="${srv_regobj} powerpc-isa205-64l.o"
 			srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o"
 			srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o"
-			srv_tgtobj="linux-low.o linux-osdata.o linux-ppc-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-ppc-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_xmlfiles="rs6000/powerpc-32l.xml"
 			srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml"
@@ -261,7 +286,9 @@ case "${target}" in
 			srv_regobj="${srv_regobj} s390x-linux64.o"
 			srv_regobj="${srv_regobj} s390x-linux64v1.o"
 			srv_regobj="${srv_regobj} s390x-linux64v2.o"
-			srv_tgtobj="linux-low.o linux-osdata.o linux-s390-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-s390-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_xmlfiles="s390-linux32.xml"
 			srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml"
@@ -282,14 +309,18 @@ case "${target}" in
 			srv_linux_thread_db=yes
 			;;
   sh*-*-linux*)		srv_regobj=reg-sh.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-sh-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-sh-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
 			;;
   sparc*-*-linux*)	srv_regobj=reg-sparc64.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-sparc-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-sparc-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
@@ -306,14 +337,19 @@ case "${target}" in
 			srv_xmlfiles="${srv_xmlfiles} tic6x-core.xml"
 			srv_xmlfiles="${srv_xmlfiles} tic6x-gp.xml"
 			srv_xmlfiles="${srv_xmlfiles} tic6x-c6xp.xml"
-  			srv_tgtobj="linux-low.o linux-osdata.o linux-tic6x-low.o linux-procfs.o"
+  			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-tic6x-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_regsets=yes
 			srv_linux_usrregs=yes
 			srv_linux_thread_db=yes
 			;;
   x86_64-*-linux*)	srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj"
-			srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-x86-low.o"
+			srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
 			srv_linux_usrregs=yes # This is for i386 progs.
@@ -328,12 +364,17 @@ case "${target}" in
 			;;
 
   xtensa*-*-linux*)	srv_regobj=reg-xtensa.o
-			srv_tgtobj="linux-low.o linux-osdata.o linux-xtensa-low.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-xtensa-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_regsets=yes
 			;;
   tilegx-*-linux*)	srv_regobj=reg-tilegx.o
-			srv_tgtobj="linux-low.o linux-tile-low.o linux-osdata.o linux-procfs.o"
+			srv_tgtobj="linux-low.o linux-maps.o"
+			srv_tgtobj="${srv_tgtobj} linux-tile-low.o"
+			srv_tgtobj="${srv_tgtobj} linux-osdata.o"
+			srv_tgtobj="${srv_tgtobj} linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
Index: gdb/gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.231
diff -u -p -r1.231 linux-low.c
--- gdb/gdbserver/linux-low.c	4 Feb 2013 17:47:00 -0000	1.231
+++ gdb/gdbserver/linux-low.c	22 Feb 2013 14:53:09 -0000
@@ -20,6 +20,7 @@
 #include "linux-low.h"
 #include "linux-osdata.h"
 #include "agent.h"
+#include "linux-maps.h"
 
 #include "gdb_wait.h"
 #include <stdio.h>
@@ -5633,6 +5634,142 @@ struct link_map_offsets
     int l_prev_offset;
   };
 
+
+
+
+
+struct find_memory_region_callback_data
+{
+  int is_elf64;
+  const char *soname;
+  CORE_ADDR l_addr;
+  size_t *build_idsz; /* Return.  Meaningful iff *build_id != NULL.  */
+  void **build_id; /* Return.  malloc allocated memory.  */
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size,
+			     ULONGEST offset, ULONGEST inode,
+			     int read, int write,
+			     int exec, int modified,
+			     const char *filename,
+			     void *data)
+{
+  struct find_memory_region_callback_data *p = data;
+
+  if (filename != NULL && strcmp (filename, p->soname) == 0)
+    {
+      union ElfXX_Ehdr
+	{
+	  Elf32_Ehdr _32;
+	  Elf64_Ehdr _64;
+	} ehdr;
+      union ElfXX_Phdr
+	{
+	  Elf32_Phdr _32;
+	  Elf64_Phdr _64;
+	} phdr;
+      union ElfXX_Nhdr
+	{
+	  Elf32_Nhdr _32;
+	  Elf64_Nhdr _64;
+	} *nhdr = NULL;
+#ifdef HDR
+#error "HDR macro redefinition detected"
+#endif /* HDR */
+#define HDR(hdr, fld) ((p->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+      if (linux_read_memory (vaddr, (unsigned char *)&ehdr, sizeof (ehdr))
+	  == 0
+	  && HDR(ehdr, e_ident[EI_MAG0]) == ELFMAG0
+	  && HDR(ehdr, e_ident[EI_MAG1]) == ELFMAG1
+	  && HDR(ehdr, e_ident[EI_MAG2]) == ELFMAG2
+	  && HDR(ehdr, e_ident[EI_MAG3]) == ELFMAG3)
+	{
+	  unsigned i;
+
+	  for (i = 0; i != HDR (ehdr, e_phnum); ++i)
+	    {
+	      if (linux_read_memory (vaddr + HDR (ehdr, e_phoff)
+				     + HDR (ehdr, e_phentsize) * i,
+				     (unsigned char *) &phdr,
+				     HDR (ehdr, e_phentsize)) != 0)
+		{
+		  warning ("could not read program header");
+		  break;
+		}
+	      if (HDR(phdr, p_type) == PT_NOTE)
+		{
+	          nhdr = xmalloc (HDR(phdr, p_memsz));
+
+		  if (linux_read_memory (p->l_addr + HDR (phdr, p_vaddr),
+					 (unsigned char *)nhdr,
+					 HDR (phdr, p_memsz)) != 0)
+		    {
+		      warning ("could not read note");
+		      break;
+		    }
+		  if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+		    {
+		      *p->build_idsz = HDR (phdr, p_memsz);
+		      *p->build_id = (void*)nhdr;
+		      break;
+		    }
+		  free (nhdr);
+		}
+	    }
+	}
+      else
+	warning ("failed reading build-id\n");
+
+      return 1;
+    }
+#undef HDR
+  return 0;
+}
+
+
+/* Return malloc allocated buffer.  User must free it.
+
+   NULL may be returned if build-id could not be
+   fetched.  */
+
+static char *
+get_hex_build_id (const char *const soname, const int is_elf64,
+		  const CORE_ADDR l_addr)
+{
+  struct find_memory_region_callback_data data;
+  void *raw_build_id = NULL;
+  size_t build_idsz;
+  char *hex_build_id;
+  char *real_soname = realpath (soname, NULL);
+
+  if (real_soname == NULL)
+    {
+      fprintf (stderr, "Failed to get realpath of %s (%s)\n", soname,
+	       strerror (errno));
+      return strdup ("");
+    }
+
+  data.is_elf64 = is_elf64;
+  data.soname = real_soname;
+  data.l_addr = l_addr;
+  data.build_idsz = &build_idsz;
+  data.build_id = &raw_build_id;
+
+  linux_find_memory_regions_full (lwpid_of (get_thread_lwp (current_inferior)),
+				  find_memory_region_callback,
+				  (void*)&data);
+  free (real_soname);
+  if (raw_build_id != NULL)
+    hex_build_id = hex_encode (raw_build_id, build_idsz);
+  else
+    hex_build_id = NULL;
+  free (raw_build_id);
+  return hex_build_id;
+}
+
 /* Construct qXfer:libraries-svr4:read reply.  */
 
 static int
@@ -5754,6 +5891,7 @@ linux_qxfer_libraries_svr4 (const char *
 	      /* 6x the size for xml_escape_text below.  */
 	      size_t len = 6 * strlen ((char *) libname);
 	      char *name;
+	      char *hex_enc_build_id;
 
 	      if (!header_done)
 		{
@@ -5762,7 +5900,12 @@ linux_qxfer_libraries_svr4 (const char *
 		  header_done = 1;
 		}
 
-	      while (allocated < p - document + len + 200)
+	      name = xml_escape_text ((char *) libname);
+	      hex_enc_build_id = get_hex_build_id (name, is_elf64, l_addr);
+
+	      while (allocated < p - document + len + 215
+				 + ((hex_enc_build_id != NULL)?
+				    strlen (hex_enc_build_id) : 0))
 		{
 		  /* Expand to guarantee sufficient storage.  */
 		  uintptr_t document_len = p - document;
@@ -5772,12 +5915,15 @@ linux_qxfer_libraries_svr4 (const char *
 		  p = document + document_len;
 		}
 
-	      name = xml_escape_text ((char *) libname);
 	      p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
-			       "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+			       "l_addr=\"0x%lx\" l_ld=\"0x%lx\" "
+			       "build-id=\"%s\"/>",
 			    name, (unsigned long) lm_addr,
-			    (unsigned long) l_addr, (unsigned long) l_ld);
+			    (unsigned long) l_addr, (unsigned long) l_ld,
+			    (hex_enc_build_id? hex_enc_build_id : ""));
+
 	      free (name);
+	      free (hex_enc_build_id);
 	    }
 	  else if (lm_prev == 0)
 	    {

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