* [patch] gdbserver build-id in qxfer_libraries reply
@ 2013-02-22 15:07 Aleksandar Ristovski
2013-02-22 18:39 ` Aleksandar Ristovski
` (8 more replies)
0 siblings, 9 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-02-22 15:07 UTC (permalink / raw)
Cc: gdb-patches, Jan Kratochvil
[-- Attachment #1: Type: text/plain, Size: 2304 bytes --]
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.
[-- Attachment #2: gdbserver-build-id-201302220835.patch --]
[-- Type: text/x-patch, Size: 39414 bytes --]
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1238
diff -u -p -r1.1238 Makefile.in
--- gdb/Makefile.in 8 Feb 2013 09:00:34 -0000 1.1238
+++ gdb/Makefile.in 22 Feb 2013 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;
}
+
+\f
+/* The bit offset of the highest byte in a ULONGEST, for overflow
+ checking. */
+
+#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
+
+
+/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
+ where 2 <= BASE <= 36. */
+
+static int
+is_digit_in_base (unsigned char digit, int base)
+{
+ if (!isalnum (digit))
+ return 0;
+ if (base <= 10)
+ return (isdigit (digit) && digit < base + '0');
+ else
+ return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
+}
+
+static int
+digit_to_int (unsigned char c)
+{
+ if (isdigit (c))
+ return c - '0';
+ else
+ return tolower (c) - 'a' + 10;
+}
+
+/* As for strtoul, but for ULONGEST results. */
+
+ULONGEST
+strtoulst (const char *num, const char **trailer, int base)
+{
+ unsigned int high_part;
+ ULONGEST result;
+ int minus = 0;
+ int i = 0;
+
+ /* Skip leading whitespace. */
+ while (isspace (num[i]))
+ i++;
+
+ /* Handle prefixes. */
+ if (num[i] == '+')
+ i++;
+ else if (num[i] == '-')
+ {
+ minus = 1;
+ i++;
+ }
+
+ if (base == 0 || base == 16)
+ {
+ if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X'))
+ {
+ i += 2;
+ if (base == 0)
+ base = 16;
+ }
+ }
+
+ if (base == 0 && num[i] == '0')
+ base = 8;
+
+ if (base == 0)
+ base = 10;
+
+ if (base < 2 || base > 36)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ result = high_part = 0;
+ for (; is_digit_in_base (num[i], base); i += 1)
+ {
+ result = result * base + digit_to_int (num[i]);
+ high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN);
+ result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
+ if (high_part > 0xff)
+ {
+ errno = ERANGE;
+ result = ~ (ULONGEST) 0;
+ high_part = 0;
+ minus = 0;
+ break;
+ }
+ }
+
+ if (trailer != NULL)
+ *trailer = &num[i];
+
+ result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
+ if (minus)
+ return -result;
+ else
+ return result;
+}
+
+\f
+
+static const char hchar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+
+/* Encode SIZE bytes from TEXT in hexadecimal format. Return
+ malloc allocated buffer of size SIZE * 2 + 1. */
+
+char *
+hex_encode (const void *const text, const size_t size)
+{
+ char *buf = xmalloc (size * 2 + 1);
+ size_t i;
+ const char *const t = text;
+
+ assert (text != NULL);
+
+ for (i = 0; i != size; ++i)
+ {
+ buf[i << 1] = hchar[(t[i] & 0xF0) >> 4];
+ buf[(i << 1) + 1] = hchar[t[i] & 0x0F];
+ }
+
+ buf[size * 2] = '\0';
+
+ return buf;
+}
+
+
+/* Helper function, decodes hex. char H into integer
+ integer value [0 - 15]. If H is not valid character
+ returns -1. */
+static int
+decode_hex_ch (const char h)
+{
+ if (h >= '0' && h <= '9')
+ return h - '0';
+
+ if (h >= 'a' && h <= 'f')
+ return h + 10 - 'a';
+
+ if (h >= 'A' && h <= 'F')
+ return h + 10 - 'A';
+
+ return -1;
+}
+
+/* Decode hex encoded HEXTEXT and return malloc allocated buffer
+ of size SZ. */
+
+void *
+hex_decode (const char *const hextext, size_t *sz)
+{
+ char *buf;
+ size_t len;
+ size_t i;
+
+ assert (hextext != NULL);
+ assert (sz != NULL);
+
+ len = strlen (hextext);
+ *sz = (len + 1) >> 1;
+ buf = xmalloc (*sz);
+
+ for (i = 0; i < len; i+=2)
+ {
+ int hi, lo;
+
+ hi = decode_hex_ch (hextext[i]);
+ lo = decode_hex_ch (hextext[i+1]);
+ if (hi < 0 || lo < 0)
+ {
+ /* Return only what was decoded so far. */
+ *sz = i >> 1; /* Successfully decoded bytes. */
+ break;
+ }
+ buf[i >> 1] = (hi << 4) | lo;
+ }
+
+ return buf;
+}
+
Index: gdb/common/common-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/common/common-utils.h,v
retrieving revision 1.5
diff -u -p -r1.5 common-utils.h
--- gdb/common/common-utils.h 14 Feb 2013 17:11:41 -0000 1.5
+++ gdb/common/common-utils.h 22 Feb 2013 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)
{
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch] gdbserver build-id in qxfer_libraries reply
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
@ 2013-02-22 18:39 ` Aleksandar Ristovski
2013-02-26 12:01 ` Pedro Alves
2013-03-10 21:07 ` [draft patch 0/6] Split FYI and some review notes Jan Kratochvil
` (7 subsequent siblings)
8 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-02-22 18:39 UTC (permalink / raw)
Cc: gdb-patches, Jan Kratochvil
[-- Attachment #1: Type: text/plain, Size: 3025 bytes --]
On 13-02-22 10:06 AM, Aleksandar Ristovski wrote:
> Hello,
>
> This is related to:
> http://sourceware.org/ml/gdb-patches/2013-01/msg00748.html. Changes from
> this patch are needed to finish off the work started in that thread.
>
> As per Jan's request, this patch adds 'build-id' to the gdbserver
> response. The value is hex encoded string representing
> .note.gnu.build-id section of the corresponding shared library.
>
> Majority of the patch is refactoring to reuse code. The real change is
> in gdbserver/linux-low.c.
Something I missed in the original post: the intent was to make build-id
optional; however, I missed to augument library-list-svr4.dtd, which is
rectified in this patch. Also, added doc changes (separate patch also
attached).
The code difference between the original and this patch is in
linux-low.c, build-id is now emitted only if build-id could be retrieved
from the binary.
---
Aleksandar
New ChangeLog (added entry for library-list-svr4.dtd) followed by
ChangeLog for doc:
* Makefile.in (HFILES_NO_SRCDIR): Add linux-maps.h and linux-maps.c.
* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to linux-maps.c.
(linux_find_memory_region_ftype): Moved to linux-maps.h.
(linux_find_memory_regions_full): Moved to linux-maps.c.
(linux_find_memory_regions): Check for fake_pid_p to match
functionality of original linux_find_memory_regions_full.
(linux_make_mappings_corefile_notes): Ditto.
* utils.c (HIGH_BYTE_POSN): Moved to common-utils.c.
(is_digit_in_base): Ditto.
(digit_to_int): Ditto.
(strtoulst): Ditto.
* utils.h (strtoulst): Moved to common-utils.h.
* common/common-utils.c (TARGET_CHAR_BIT): Define if not defined.
(HOST_CHAR_BIT): Ditto.
(ctype.h): Include.
(string.h): Include.
(assert.h): Include.
(HIGH_BYTE_POSN): Moved from utils.c.
(is_digit_in_base): Ditto.
(digit_to_int): Ditto.
(strtoulst): Ditto.
(hchar): Hex charset for hex_encode.
(hex_encode): New function.
(decode_hex_ch): Ditto.
(hex_decode): Ditto.
* common/common-utils.h (strtoulst): Moved from utils.h.
(hex_encode): New declaration.
(hex_decode): Ditto.
* common/linux-maps.c: New file.
* common/linux-maps.h: New file.
* common/xml-utils.h (xml_hex_encode_text): Declare.
* config/i386/linux.mh (NATDEPFILES): Add linux-maps.o.
* config/i386/linux64.mh (NATDEPFILES): Add linux-maps.o.
* features/library-list-svr4.dtd (build-id): New attribute.
* gdbserver/Makefile.in (linux-maps.o): New.
* gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o.
* gdbserver/linux-low.c (linux-maps.h): Include.
(find_memory_region_callback_data): New structure definition.
(find_memory_region_callback): New forward declaration.
(find_memory_region_callback): New function.
(get_hex_build_id): New function.
(linux_qxfer_libraries_svr4): Add hex encoded build-id to the reply.
Doc ChangeLog:
* gdb.texinfo (Library List Format for SVR4 Targets): New
'build-id'
attribute, add it to the example and document it in DTD.
[-- Attachment #2: gdbserver-build-id-201302221119.patch --]
[-- Type: text/x-patch, Size: 40022 bytes --]
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1238
diff -u -p -r1.1238 Makefile.in
--- gdb/Makefile.in 8 Feb 2013 09:00:34 -0000 1.1238
+++ gdb/Makefile.in 22 Feb 2013 16:19:11 -0000
@@ -771,7 +771,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFI
HFILES_NO_SRCDIR = \
common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-maps.h common/linux-ptrace.h \
proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -1945,6 +1945,10 @@ format.o: ${srcdir}/common/format.c
$(COMPILE) $(srcdir)/common/format.c
$(POSTCOMPILE)
+linux-maps.o: ${srcdir}/common/linux-maps.c
+ $(COMPILE) $(srcdir)/common/linux-maps.c
+ $(POSTCOMPILE)
+
linux-osdata.o: ${srcdir}/common/linux-osdata.c
$(COMPILE) $(srcdir)/common/linux-osdata.c
$(POSTCOMPILE)
Index: gdb/linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-tdep.c,v
retrieving revision 1.27
diff -u -p -r1.27 linux-tdep.c
--- gdb/linux-tdep.c 4 Feb 2013 18:40:41 -0000 1.27
+++ gdb/linux-tdep.c 22 Feb 2013 16:19:11 -0000
@@ -33,6 +33,7 @@
#include "arch-utils.h"
#include "gdb_obstack.h"
#include "cli/cli-utils.h"
+#include "linux-maps.h"
#include <ctype.h>
@@ -207,46 +208,7 @@ linux_core_pid_to_str (struct gdbarch *g
return normal_pid_to_str (ptid);
}
-/* Service function for corefiles and info proc. */
-static void
-read_mapping (const char *line,
- ULONGEST *addr, ULONGEST *endaddr,
- const char **permissions, size_t *permissions_len,
- ULONGEST *offset,
- const char **device, size_t *device_len,
- ULONGEST *inode,
- const char **filename)
-{
- const char *p = line;
-
- *addr = strtoulst (p, &p, 16);
- if (*p == '-')
- p++;
- *endaddr = strtoulst (p, &p, 16);
-
- while (*p && isspace (*p))
- p++;
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- while (*p && isspace (*p))
- p++;
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- while (*p && isspace (*p))
- p++;
- *filename = p;
-}
/* Implement the "info proc" command. */
@@ -666,101 +628,6 @@ linux_core_info_proc (struct gdbarch *gd
error (_("unable to handle request"));
}
-typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
- ULONGEST offset, ULONGEST inode,
- int read, int write,
- int exec, int modified,
- const char *filename,
- void *data);
-
-/* List memory regions in the inferior for a corefile. */
-
-static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
-{
- char filename[100];
- gdb_byte *data;
-
- /* We need to know the real target PID to access /proc. */
- if (current_inferior ()->fake_pid_p)
- return 1;
-
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
- data = target_fileio_read_stralloc (filename);
- if (data == NULL)
- {
- /* Older Linux kernels did not support /proc/PID/smaps. */
- xsnprintf (filename, sizeof filename,
- "/proc/%d/maps", current_inferior ()->pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- struct cleanup *cleanup = make_cleanup (xfree, data);
- char *line;
-
- line = strtok (data, "\n");
- while (line)
- {
- ULONGEST addr, endaddr, offset, inode;
- const char *permissions, *device, *filename;
- size_t permissions_len, device_len;
- int read, write, exec;
- int modified = 0, has_anonymous = 0;
-
- read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
- &offset, &device, &device_len, &inode, &filename);
-
- /* Decode permissions. */
- read = (memchr (permissions, 'r', permissions_len) != 0);
- write = (memchr (permissions, 'w', permissions_len) != 0);
- exec = (memchr (permissions, 'x', permissions_len) != 0);
-
- /* Try to detect if region was modified by parsing smaps counters. */
- for (line = strtok (NULL, "\n");
- line && line[0] >= 'A' && line[0] <= 'Z';
- line = strtok (NULL, "\n"))
- {
- char keyword[64 + 1];
- unsigned long number;
-
- if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
- {
- warning (_("Error parsing {s,}maps file '%s'"), filename);
- break;
- }
- if (strcmp (keyword, "Anonymous:") == 0)
- has_anonymous = 1;
- if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
- || strcmp (keyword, "Private_Dirty:") == 0
- || strcmp (keyword, "Swap:") == 0
- || strcmp (keyword, "Anonymous:") == 0))
- modified = 1;
- }
-
- /* Older Linux kernels did not support the "Anonymous:" counter.
- If it is missing, we can't be sure - dump all the pages. */
- if (!has_anonymous)
- modified = 1;
-
- /* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
- }
-
- do_cleanups (cleanup);
- return 0;
- }
-
- return 1;
-}
-
-/* A structure for passing information through
- linux_find_memory_regions_full. */
-
struct linux_find_memory_regions_data
{
/* The original callback. */
@@ -798,7 +665,10 @@ linux_find_memory_regions (struct gdbarc
data.func = func;
data.obfd = obfd;
- return linux_find_memory_regions_full (gdbarch,
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ return linux_find_memory_regions_full (current_inferior ()->pid,
linux_find_memory_regions_thunk,
&data);
}
@@ -982,8 +852,10 @@ linux_make_mappings_corefile_notes (stru
pack_long (buf, long_type, 1);
obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));
- linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback,
- &mapping_data);
+ if (!current_inferior ()->fake_pid_p)
+ linux_find_memory_regions_full (current_inferior ()->pid,
+ linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
Index: gdb/utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.292
diff -u -p -r1.292 utils.c
--- gdb/utils.c 14 Feb 2013 17:11:41 -0000 1.292
+++ gdb/utils.c 22 Feb 2013 16:19:12 -0000
@@ -3309,104 +3309,6 @@ dummy_obstack_deallocate (void *object,
return;
}
-/* The bit offset of the highest byte in a ULONGEST, for overflow
- checking. */
-
-#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
-
-/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
- where 2 <= BASE <= 36. */
-
-static int
-is_digit_in_base (unsigned char digit, int base)
-{
- if (!isalnum (digit))
- return 0;
- if (base <= 10)
- return (isdigit (digit) && digit < base + '0');
- else
- return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
-}
-
-static int
-digit_to_int (unsigned char c)
-{
- if (isdigit (c))
- return c - '0';
- else
- return tolower (c) - 'a' + 10;
-}
-
-/* As for strtoul, but for ULONGEST results. */
-
-ULONGEST
-strtoulst (const char *num, const char **trailer, int base)
-{
- unsigned int high_part;
- ULONGEST result;
- int minus = 0;
- int i = 0;
-
- /* Skip leading whitespace. */
- while (isspace (num[i]))
- i++;
-
- /* Handle prefixes. */
- if (num[i] == '+')
- i++;
- else if (num[i] == '-')
- {
- minus = 1;
- i++;
- }
-
- if (base == 0 || base == 16)
- {
- if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X'))
- {
- i += 2;
- if (base == 0)
- base = 16;
- }
- }
-
- if (base == 0 && num[i] == '0')
- base = 8;
-
- if (base == 0)
- base = 10;
-
- if (base < 2 || base > 36)
- {
- errno = EINVAL;
- return 0;
- }
-
- result = high_part = 0;
- for (; is_digit_in_base (num[i], base); i += 1)
- {
- result = result * base + digit_to_int (num[i]);
- high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN);
- result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
- if (high_part > 0xff)
- {
- errno = ERANGE;
- result = ~ (ULONGEST) 0;
- high_part = 0;
- minus = 0;
- break;
- }
- }
-
- if (trailer != NULL)
- *trailer = &num[i];
-
- result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
- if (minus)
- return -result;
- else
- return result;
-}
/* Simple, portable version of dirname that does not modify its
argument. */
Index: gdb/utils.h
===================================================================
RCS file: /cvs/src/src/gdb/utils.h,v
retrieving revision 1.5
diff -u -p -r1.5 utils.h
--- gdb/utils.h 3 Feb 2013 15:54:17 -0000 1.5
+++ gdb/utils.h 22 Feb 2013 16:19:12 -0000
@@ -39,8 +39,6 @@ extern int streq (const char *, const ch
extern int subset_compare (char *, char *);
-ULONGEST strtoulst (const char *num, const char **trailer, int base);
-
int compare_positive_ints (const void *ap, const void *bp);
int compare_strings (const void *ap, const void *bp);
Index: gdb/common/common-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/common/common-utils.c,v
retrieving revision 1.5
diff -u -p -r1.5 common-utils.c
--- gdb/common/common-utils.c 14 Feb 2013 17:11:41 -0000 1.5
+++ gdb/common/common-utils.c 22 Feb 2013 16:19:12 -0000
@@ -19,6 +19,15 @@
#ifdef GDBSERVER
#include "server.h"
+
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT (sizeof (char) * 8)
+#endif /* ! TARGET_CHAR_BIT */
+
+#if !defined (HOST_CHAR_BIT)
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif /* ! HOST_CHAR_BIT */
+
#else
#include "defs.h"
#endif
@@ -28,6 +37,9 @@
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
/* The xmalloc() (libiberty.h) family of memory management routines.
@@ -161,3 +173,187 @@ savestring (const char *ptr, size_t len)
p[len] = 0;
return p;
}
+
+\f
+/* The bit offset of the highest byte in a ULONGEST, for overflow
+ checking. */
+
+#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
+
+
+/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
+ where 2 <= BASE <= 36. */
+
+static int
+is_digit_in_base (unsigned char digit, int base)
+{
+ if (!isalnum (digit))
+ return 0;
+ if (base <= 10)
+ return (isdigit (digit) && digit < base + '0');
+ else
+ return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
+}
+
+static int
+digit_to_int (unsigned char c)
+{
+ if (isdigit (c))
+ return c - '0';
+ else
+ return tolower (c) - 'a' + 10;
+}
+
+/* As for strtoul, but for ULONGEST results. */
+
+ULONGEST
+strtoulst (const char *num, const char **trailer, int base)
+{
+ unsigned int high_part;
+ ULONGEST result;
+ int minus = 0;
+ int i = 0;
+
+ /* Skip leading whitespace. */
+ while (isspace (num[i]))
+ i++;
+
+ /* Handle prefixes. */
+ if (num[i] == '+')
+ i++;
+ else if (num[i] == '-')
+ {
+ minus = 1;
+ i++;
+ }
+
+ if (base == 0 || base == 16)
+ {
+ if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X'))
+ {
+ i += 2;
+ if (base == 0)
+ base = 16;
+ }
+ }
+
+ if (base == 0 && num[i] == '0')
+ base = 8;
+
+ if (base == 0)
+ base = 10;
+
+ if (base < 2 || base > 36)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ result = high_part = 0;
+ for (; is_digit_in_base (num[i], base); i += 1)
+ {
+ result = result * base + digit_to_int (num[i]);
+ high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN);
+ result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
+ if (high_part > 0xff)
+ {
+ errno = ERANGE;
+ result = ~ (ULONGEST) 0;
+ high_part = 0;
+ minus = 0;
+ break;
+ }
+ }
+
+ if (trailer != NULL)
+ *trailer = &num[i];
+
+ result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
+ if (minus)
+ return -result;
+ else
+ return result;
+}
+
+\f
+
+static const char hchar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+
+/* Encode SIZE bytes from TEXT in hexadecimal format. Return
+ malloc allocated buffer of size SIZE * 2 + 1. */
+
+char *
+hex_encode (const void *const text, const size_t size)
+{
+ char *buf = xmalloc (size * 2 + 1);
+ size_t i;
+ const char *const t = text;
+
+ assert (text != NULL);
+
+ for (i = 0; i != size; ++i)
+ {
+ buf[i << 1] = hchar[(t[i] & 0xF0) >> 4];
+ buf[(i << 1) + 1] = hchar[t[i] & 0x0F];
+ }
+
+ buf[size * 2] = '\0';
+
+ return buf;
+}
+
+
+/* Helper function, decodes hex. char H into integer
+ integer value [0 - 15]. If H is not valid character
+ returns -1. */
+static int
+decode_hex_ch (const char h)
+{
+ if (h >= '0' && h <= '9')
+ return h - '0';
+
+ if (h >= 'a' && h <= 'f')
+ return h + 10 - 'a';
+
+ if (h >= 'A' && h <= 'F')
+ return h + 10 - 'A';
+
+ return -1;
+}
+
+/* Decode hex encoded HEXTEXT and return malloc allocated buffer
+ of size SZ. */
+
+void *
+hex_decode (const char *const hextext, size_t *sz)
+{
+ char *buf;
+ size_t len;
+ size_t i;
+
+ assert (hextext != NULL);
+ assert (sz != NULL);
+
+ len = strlen (hextext);
+ *sz = (len + 1) >> 1;
+ buf = xmalloc (*sz);
+
+ for (i = 0; i < len; i+=2)
+ {
+ int hi, lo;
+
+ hi = decode_hex_ch (hextext[i]);
+ lo = decode_hex_ch (hextext[i+1]);
+ if (hi < 0 || lo < 0)
+ {
+ /* Return only what was decoded so far. */
+ *sz = i >> 1; /* Successfully decoded bytes. */
+ break;
+ }
+ buf[i >> 1] = (hi << 4) | lo;
+ }
+
+ return buf;
+}
+
Index: gdb/common/common-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/common/common-utils.h,v
retrieving revision 1.5
diff -u -p -r1.5 common-utils.h
--- gdb/common/common-utils.h 14 Feb 2013 17:11:41 -0000 1.5
+++ gdb/common/common-utils.h 22 Feb 2013 16:19:12 -0000
@@ -53,4 +53,10 @@ int xsnprintf (char *str, size_t size, c
char *savestring (const char *ptr, size_t len);
+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+char *hex_encode (const void *text, size_t size);
+
+void *hex_decode (const char *hextext, size_t *size);
+
#endif
Index: gdb/common/linux-maps.c
===================================================================
RCS file: gdb/common/linux-maps.c
diff -N gdb/common/linux-maps.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/common/linux-maps.c 22 Feb 2013 16:19:12 -0000
@@ -0,0 +1,217 @@
+/* Linux-specific memory maps manipulation routines.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifdef GDBSERVER
+#include "server.h"
+#include "linux-maps.h"
+#include <fcntl.h>
+#include <unistd.h>
+#else /* ! GDBSERVER */
+#include "defs.h"
+#include "linux-maps.h"
+#include "target.h"
+#endif /* ! GDBSERVER */
+
+#include <ctype.h>
+
+
+#ifdef GDBSERVER
+static char *
+fileio_read_stralloc (const char *const filename)
+{
+ char *buf;
+ int fd;
+ size_t buf_alloc;
+ size_t buf_pos;
+ const size_t buf_alloc_inc = 2 * 4096;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ buf_pos = 0;
+
+ while (1)
+ {
+ ssize_t n;
+
+ n = pread (fd, &buf[buf_pos], buf_alloc - buf_pos, buf_pos);
+
+ if (n < 0)
+ {
+ xfree (buf);
+ buf = NULL;
+ break;
+ }
+ else if (n == 0)
+ {
+ if (buf_pos == 0)
+ {
+ xfree (buf);
+ buf = NULL;
+ }
+ break;
+ }
+ buf_pos += n;
+
+ if (buf_alloc < buf_pos + buf_alloc_inc)
+ {
+ buf_alloc += buf_alloc_inc;
+ buf = xrealloc (buf, buf_alloc);
+ }
+ }
+
+ if (close (fd) < 0)
+ warning (_("Error closing file descriptor: '%s'"), strerror (errno));
+
+ return buf;
+}
+
+#define target_fileio_read_stralloc(filename) fileio_read_stralloc (filename)
+
+#endif /* GDBSERVER */
+
+/* Service function for corefiles and info proc. */
+
+void
+read_mapping (const char *line,
+ ULONGEST *addr, ULONGEST *endaddr,
+ const char **permissions, size_t *permissions_len,
+ ULONGEST *offset,
+ const char **device, size_t *device_len,
+ ULONGEST *inode,
+ const char **filename)
+{
+ const char *p = line;
+
+ *addr = strtoulst (p, &p, 16);
+ if (*p == '-')
+ p++;
+ *endaddr = strtoulst (p, &p, 16);
+
+ while (*p && isspace (*p))
+ p++;
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ while (*p && isspace (*p))
+ p++;
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ while (*p && isspace (*p))
+ p++;
+ *filename = p;
+}
+
+/* List memory regions in the inferior.
+ Return nonzero on error. */
+
+int
+linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *obfd)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename,
+ "/proc/%d/smaps", pid);
+ data = target_fileio_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename,
+ "/proc/%d/maps", pid);
+ data = target_fileio_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+
+ line = strtok (data, "\n");
+ while (line)
+ {
+ ULONGEST addr, endaddr, offset, inode;
+ const char *permissions, *device, *filename;
+ size_t permissions_len, device_len;
+ int read, write, exec;
+ int modified = 0, has_anonymous = 0;
+ int ret;
+
+ read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
+ &offset, &device, &device_len, &inode, &filename);
+
+ /* Decode permissions. */
+ read = (memchr (permissions, 'r', permissions_len) != 0);
+ write = (memchr (permissions, 'w', permissions_len) != 0);
+ exec = (memchr (permissions, 'x', permissions_len) != 0);
+
+ /* Try to detect if region was modified by parsing smaps counters. */
+ for (line = strtok (NULL, "\n");
+ line && line[0] >= 'A' && line[0] <= 'Z';
+ line = strtok (NULL, "\n"))
+ {
+ char keyword[64 + 1];
+ unsigned long number;
+
+ if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
+ {
+ warning (_("Error parsing {s,}maps file '%s'"), filename);
+ break;
+ }
+ if (strcmp (keyword, "Anonymous:") == 0)
+ has_anonymous = 1;
+ if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
+ || strcmp (keyword, "Private_Dirty:") == 0
+ || strcmp (keyword, "Swap:") == 0
+ || strcmp (keyword, "Anonymous:") == 0))
+ modified = 1;
+ }
+
+ /* Older Linux kernels did not support the "Anonymous:" counter.
+ If it is missing, we can't be sure - dump all the pages. */
+ if (!has_anonymous)
+ modified = 1;
+
+ /* Invoke the callback function to create the corefile segment. */
+ ret = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, obfd);
+ if (ret)
+ break;
+ }
+
+ xfree (data);
+ return 0;
+ }
+
+ return 1;
+}
+
+
Index: gdb/common/linux-maps.h
===================================================================
RCS file: gdb/common/linux-maps.h
diff -N gdb/common/linux-maps.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/common/linux-maps.h 22 Feb 2013 16:19:12 -0000
@@ -0,0 +1,50 @@
+/* Linux-specific memory maps manipulation routines.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef COMMON_LINUX_MAPS_H
+#define COMMON_LINUX_MAPS_H
+
+/* Function type for linux_find_memory_regions_full function.
+
+ Non zero returned breaks loop in linux_find_memory_regions_full. */
+
+typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
+ ULONGEST offset, ULONGEST inode,
+ int read, int write,
+ int exec, int modified,
+ const char *filename,
+ void *data);
+
+/* A structure for passing information through
+ linux_find_memory_regions_full. */
+
+extern int linux_find_memory_regions_full (
+ pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *obfd);
+
+extern void read_mapping (const char *line,
+ ULONGEST *addr, ULONGEST *endaddr,
+ const char **permissions, size_t *permissions_len,
+ ULONGEST *offset,
+ const char **device, size_t *device_len,
+ ULONGEST *inode,
+ const char **filename);
+
+
+#endif /* COMMON_LINUX_MAPS_H */
Index: gdb/common/xml-utils.h
===================================================================
RCS file: /cvs/src/src/gdb/common/xml-utils.h,v
retrieving revision 1.3
diff -u -p -r1.3 xml-utils.h
--- gdb/common/xml-utils.h 1 Jan 2013 06:32:54 -0000 1.3
+++ gdb/common/xml-utils.h 22 Feb 2013 16:19:12 -0000
@@ -25,4 +25,9 @@
extern char *xml_escape_text (const char *text);
+/* Return a xmalloc allocated string with hex-encoded SIZE bytes from
+ TEXT. */
+
+extern char *xml_hex_encode_text (const unsigned char *text, size_t size);
+
#endif
Index: gdb/config/i386/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux.mh,v
retrieving revision 1.27
diff -u -p -r1.27 linux.mh
--- gdb/config/i386/linux.mh 13 Mar 2012 15:00:33 -0000 1.27
+++ gdb/config/i386/linux.mh 22 Feb 2013 16:19:12 -0000
@@ -3,7 +3,7 @@
NAT_FILE= config/nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o i386-linux-nat.o \
- proc-service.o linux-thread-db.o \
+ proc-service.o linux-thread-db.o linux-maps.o \
linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o
NAT_CDEPS = $(srcdir)/proc-service.list
Index: gdb/config/i386/linux64.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux64.mh,v
retrieving revision 1.13
diff -u -p -r1.13 linux64.mh
--- gdb/config/i386/linux64.mh 13 Mar 2012 15:00:34 -0000 1.13
+++ gdb/config/i386/linux64.mh 22 Feb 2013 16:19:12 -0000
@@ -1,7 +1,7 @@
# Host: GNU/Linux x86-64
NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o amd64-nat.o amd64-linux-nat.o \
- linux-nat.o linux-osdata.o \
+ linux-maps.o linux-nat.o linux-osdata.o \
proc-service.o linux-thread-db.o linux-fork.o \
linux-procfs.o linux-ptrace.o
NAT_FILE= config/nm-linux.h
Index: gdb/features/library-list-svr4.dtd
===================================================================
RCS file: /cvs/src/src/gdb/features/library-list-svr4.dtd,v
retrieving revision 1.3
diff -u -p -r1.3 library-list-svr4.dtd
--- gdb/features/library-list-svr4.dtd 1 Jan 2013 06:32:58 -0000 1.3
+++ gdb/features/library-list-svr4.dtd 22 Feb 2013 16:19:14 -0000
@@ -14,3 +14,4 @@
<!ATTLIST library lm CDATA #REQUIRED>
<!ATTLIST library l_addr CDATA #REQUIRED>
<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library build-id CDATA #IMPLIED>
Index: gdb/gdbserver/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
retrieving revision 1.142
diff -u -p -r1.142 Makefile.in
--- gdb/gdbserver/Makefile.in 4 Feb 2013 18:20:04 -0000 1.142
+++ gdb/gdbserver/Makefile.in 22 Feb 2013 16:19:14 -0000
@@ -509,6 +509,9 @@ ax.o: ax.c
signals.o: ../common/signals.c
$(COMPILE) $<
$(POSTCOMPILE)
+linux-maps.o: ../common/linux-maps.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
linux-procfs.o: ../common/linux-procfs.c
$(COMPILE) $<
$(POSTCOMPILE)
Index: gdb/gdbserver/configure.srv
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.srv,v
retrieving revision 1.71
diff -u -p -r1.71 configure.srv
--- gdb/gdbserver/configure.srv 4 Feb 2013 18:20:05 -0000 1.71
+++ gdb/gdbserver/configure.srv 22 Feb 2013 16:19:14 -0000
@@ -46,6 +46,7 @@ case "${target}" in
srv_regobj="aarch64.o aarch64-without-fpu.o"
srv_tgtobj="linux-aarch64-low.o"
srv_tgtobj="${srv_tgtobj} linux-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-maps.o"
srv_tgtobj="${srv_tgtobj} linux-osdata.o"
srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
@@ -61,7 +62,9 @@ case "${target}" in
srv_regobj="${srv_regobj} arm-with-vfpv2.o"
srv_regobj="${srv_regobj} arm-with-vfpv3.o"
srv_regobj="${srv_regobj} arm-with-neon.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-arm-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-arm-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="arm-with-iwmmxt.xml"
srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
@@ -84,19 +87,25 @@ case "${target}" in
srv_mingwce=yes
;;
bfin-*-*linux*) srv_regobj=reg-bfin.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-bfin-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-bfin-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
crisv32-*-linux*) srv_regobj=reg-crisv32.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-crisv32-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-crisv32-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_thread_db=yes
;;
cris-*-linux*) srv_regobj=reg-cris.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-cris-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-cris-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
@@ -111,7 +120,10 @@ case "${target}" in
srv_regobj="$srv_regobj $srv_amd64_linux_regobj"
srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles"
fi
- srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-x86-low.o"
+ srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -146,12 +158,16 @@ case "${target}" in
srv_qnx="yes"
;;
ia64-*-linux*) srv_regobj=reg-ia64.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-ia64-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-ia64-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
;;
m32r*-*-linux*) srv_regobj=reg-m32r.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-m32r-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-m32r-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
@@ -161,7 +177,9 @@ case "${target}" in
else
srv_regobj=reg-m68k.o
fi
- srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-m68k-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -172,7 +190,9 @@ case "${target}" in
else
srv_regobj=reg-m68k.o
fi
- srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-m68k-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -182,7 +202,10 @@ case "${target}" in
srv_regobj="${srv_regobj} mips-dsp-linux.o"
srv_regobj="${srv_regobj} mips64-linux.o"
srv_regobj="${srv_regobj} mips64-dsp-linux.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o"
+ srv_tgtobj="${srv_tgtobj} linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-mips-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="mips-linux.xml"
srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
@@ -215,7 +238,9 @@ case "${target}" in
srv_regobj="${srv_regobj} powerpc-isa205-64l.o"
srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o"
srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-ppc-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-ppc-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="rs6000/powerpc-32l.xml"
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml"
@@ -261,7 +286,9 @@ case "${target}" in
srv_regobj="${srv_regobj} s390x-linux64.o"
srv_regobj="${srv_regobj} s390x-linux64v1.o"
srv_regobj="${srv_regobj} s390x-linux64v2.o"
- srv_tgtobj="linux-low.o linux-osdata.o linux-s390-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-s390-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="s390-linux32.xml"
srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml"
@@ -282,14 +309,18 @@ case "${target}" in
srv_linux_thread_db=yes
;;
sh*-*-linux*) srv_regobj=reg-sh.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-sh-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-sh-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
srv_linux_thread_db=yes
;;
sparc*-*-linux*) srv_regobj=reg-sparc64.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-sparc-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-sparc-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_thread_db=yes
@@ -306,14 +337,19 @@ case "${target}" in
srv_xmlfiles="${srv_xmlfiles} tic6x-core.xml"
srv_xmlfiles="${srv_xmlfiles} tic6x-gp.xml"
srv_xmlfiles="${srv_xmlfiles} tic6x-c6xp.xml"
- srv_tgtobj="linux-low.o linux-osdata.o linux-tic6x-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-tic6x-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
x86_64-*-linux*) srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj"
- srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-x86-low.o"
+ srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
srv_linux_usrregs=yes # This is for i386 progs.
@@ -328,12 +364,17 @@ case "${target}" in
;;
xtensa*-*-linux*) srv_regobj=reg-xtensa.o
- srv_tgtobj="linux-low.o linux-osdata.o linux-xtensa-low.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-xtensa-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
;;
tilegx-*-linux*) srv_regobj=reg-tilegx.o
- srv_tgtobj="linux-low.o linux-tile-low.o linux-osdata.o linux-procfs.o"
+ srv_tgtobj="linux-low.o linux-maps.o"
+ srv_tgtobj="${srv_tgtobj} linux-tile-low.o"
+ srv_tgtobj="${srv_tgtobj} linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-procfs.o"
srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
srv_linux_regsets=yes
srv_linux_thread_db=yes
Index: gdb/gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.231
diff -u -p -r1.231 linux-low.c
--- gdb/gdbserver/linux-low.c 4 Feb 2013 17:47:00 -0000 1.231
+++ gdb/gdbserver/linux-low.c 22 Feb 2013 16:19:16 -0000
@@ -20,6 +20,7 @@
#include "linux-low.h"
#include "linux-osdata.h"
#include "agent.h"
+#include "linux-maps.h"
#include "gdb_wait.h"
#include <stdio.h>
@@ -5633,6 +5634,142 @@ struct link_map_offsets
int l_prev_offset;
};
+
+
+
+
+struct find_memory_region_callback_data
+{
+ int is_elf64;
+ const char *soname;
+ CORE_ADDR l_addr;
+ size_t *build_idsz; /* Return. Meaningful iff *build_id != NULL. */
+ void **build_id; /* Return. malloc allocated memory. */
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size,
+ ULONGEST offset, ULONGEST inode,
+ int read, int write,
+ int exec, int modified,
+ const char *filename,
+ void *data)
+{
+ struct find_memory_region_callback_data *p = data;
+
+ if (filename != NULL && strcmp (filename, p->soname) == 0)
+ {
+ union ElfXX_Ehdr
+ {
+ Elf32_Ehdr _32;
+ Elf64_Ehdr _64;
+ } ehdr;
+ union ElfXX_Phdr
+ {
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+ } phdr;
+ union ElfXX_Nhdr
+ {
+ Elf32_Nhdr _32;
+ Elf64_Nhdr _64;
+ } *nhdr = NULL;
+#ifdef HDR
+#error "HDR macro redefinition detected"
+#endif /* HDR */
+#define HDR(hdr, fld) ((p->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+ if (linux_read_memory (vaddr, (unsigned char *)&ehdr, sizeof (ehdr))
+ == 0
+ && HDR(ehdr, e_ident[EI_MAG0]) == ELFMAG0
+ && HDR(ehdr, e_ident[EI_MAG1]) == ELFMAG1
+ && HDR(ehdr, e_ident[EI_MAG2]) == ELFMAG2
+ && HDR(ehdr, e_ident[EI_MAG3]) == ELFMAG3)
+ {
+ unsigned i;
+
+ for (i = 0; i != HDR (ehdr, e_phnum); ++i)
+ {
+ if (linux_read_memory (vaddr + HDR (ehdr, e_phoff)
+ + HDR (ehdr, e_phentsize) * i,
+ (unsigned char *) &phdr,
+ HDR (ehdr, e_phentsize)) != 0)
+ {
+ warning ("could not read program header");
+ break;
+ }
+ if (HDR(phdr, p_type) == PT_NOTE)
+ {
+ nhdr = xmalloc (HDR(phdr, p_memsz));
+
+ if (linux_read_memory (p->l_addr + HDR (phdr, p_vaddr),
+ (unsigned char *)nhdr,
+ HDR (phdr, p_memsz)) != 0)
+ {
+ warning ("could not read note");
+ break;
+ }
+ if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ *p->build_idsz = HDR (phdr, p_memsz);
+ *p->build_id = (void*)nhdr;
+ break;
+ }
+ free (nhdr);
+ }
+ }
+ }
+ else
+ warning ("failed reading build-id\n");
+
+ return 1;
+ }
+#undef HDR
+ return 0;
+}
+
+
+/* Return malloc allocated buffer. User must free it.
+
+ NULL may be returned if build-id could not be
+ fetched. */
+
+static char *
+get_hex_build_id (const char *const soname, const int is_elf64,
+ const CORE_ADDR l_addr)
+{
+ struct find_memory_region_callback_data data;
+ void *raw_build_id = NULL;
+ size_t build_idsz;
+ char *hex_build_id;
+ char *real_soname = realpath (soname, NULL);
+
+ if (real_soname == NULL)
+ {
+ fprintf (stderr, "Failed to get realpath of %s (%s)\n", soname,
+ strerror (errno));
+ return strdup ("");
+ }
+
+ data.is_elf64 = is_elf64;
+ data.soname = real_soname;
+ data.l_addr = l_addr;
+ data.build_idsz = &build_idsz;
+ data.build_id = &raw_build_id;
+
+ linux_find_memory_regions_full (lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback,
+ (void*)&data);
+ free (real_soname);
+ if (raw_build_id != NULL)
+ hex_build_id = hex_encode (raw_build_id, build_idsz);
+ else
+ hex_build_id = NULL;
+ free (raw_build_id);
+ return hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5754,6 +5891,7 @@ linux_qxfer_libraries_svr4 (const char *
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ char *hex_enc_build_id;
if (!header_done)
{
@@ -5762,7 +5900,12 @@ linux_qxfer_libraries_svr4 (const char *
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ hex_enc_build_id = get_hex_build_id (name, is_elf64, l_addr);
+
+ while (allocated < p - document + len + 215
+ + ((hex_enc_build_id != NULL)?
+ strlen (hex_enc_build_id) : 0))
{
/* Expand to guarantee sufficient storage. */
uintptr_t document_len = p - document;
@@ -5772,12 +5915,15 @@ linux_qxfer_libraries_svr4 (const char *
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
- "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+ "l_addr=\"0x%lx\" l_ld=\"0x%lx\"",
name, (unsigned long) lm_addr,
(unsigned long) l_addr, (unsigned long) l_ld);
+ if (hex_enc_build_id != NULL)
+ p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id);
+ p += sprintf(p, "%s", "/>");
free (name);
+ free (hex_enc_build_id);
}
else if (lm_prev == 0)
{
[-- Attachment #3: gdbserver-build-id-doc-201302221119.patch --]
[-- Type: text/x-patch, Size: 1433 bytes --]
Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.1054
diff -u -p -r1.1054 gdb.texinfo
--- gdb/doc/gdb.texinfo 21 Feb 2013 19:08:10 -0000 1.1054
+++ gdb/doc/gdb.texinfo 22 Feb 2013 16:19:14 -0000
@@ -40144,6 +40144,9 @@ memory address. It is a displacement of
address the file was prelinked to during the library load.
@item
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
+@item
+@code{build-id}, hex encoded @code{.note.gnu.build-id} section, if such
+section exists.
@end itemize
Additionally the single @code{main-lm} attribute specifies address of
@@ -40161,7 +40164,8 @@ looks like this:
<library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000"
l_ld="0xe4eefc"/>
<library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000"
- l_ld="0x152350"/>
+ l_ld="0x152350" build-id="040000001400000003000000474e5500\
+ 829afccf7cc41e62934766d96223fe72480854e"/>
</library-list-svr>
@end smallexample
@@ -40177,6 +40181,7 @@ The format of an SVR4 library list is de
<!ATTLIST library lm CDATA #REQUIRED>
<!ATTLIST library l_addr CDATA #REQUIRED>
<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library build-id CDATA #IMPLIED>
@end smallexample
@node Memory Map Format
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch] gdbserver build-id in qxfer_libraries reply
2013-02-22 18:39 ` Aleksandar Ristovski
@ 2013-02-26 12:01 ` Pedro Alves
2013-02-27 17:25 ` Aleksandar Ristovski
0 siblings, 1 reply; 79+ messages in thread
From: Pedro Alves @ 2013-02-26 12:01 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches, Jan Kratochvil
Hi Aleksandar,
Thanks for 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?
> The real change is
>> in gdbserver/linux-low.c.
--
Pedro Alves
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch] gdbserver build-id in qxfer_libraries reply
2013-02-26 12:01 ` Pedro Alves
@ 2013-02-27 17:25 ` Aleksandar Ristovski
2013-02-27 17:31 ` Aleksandar Ristovski
2013-02-27 18:44 ` Eli Zaretskii
0 siblings, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-02-27 17:25 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, Jan Kratochvil
[-- 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
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch] gdbserver build-id in qxfer_libraries reply
2013-02-27 17:25 ` Aleksandar Ristovski
@ 2013-02-27 17:31 ` Aleksandar Ristovski
2013-02-27 18:44 ` Eli Zaretskii
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-02-27 17:31 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches, Jan Kratochvil
[-- 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
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch] gdbserver build-id in qxfer_libraries reply
2013-02-27 17:25 ` Aleksandar Ristovski
2013-02-27 17:31 ` Aleksandar Ristovski
@ 2013-02-27 18:44 ` Eli Zaretskii
1 sibling, 0 replies; 79+ messages in thread
From: Eli Zaretskii @ 2013-02-27 18:44 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: palves, gdb-patches, jan.kratochvil
> Date: Wed, 27 Feb 2013 12:24:57 -0500
> From: Aleksandar Ristovski <aristovski@qnx.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>, Jan Kratochvil <jan.kratochvil@redhat.com>
>
> New patch attached, along with documentation patch.
The documentation part is OK. Thanks.
^ permalink raw reply [flat|nested] 79+ messages in thread
* [draft patch 0/6] Split FYI and some review notes
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
2013-02-22 18:39 ` Aleksandar Ristovski
@ 2013-03-10 21:07 ` Jan Kratochvil
2013-03-11 14:25 ` Aleksandar Ristovski
2013-03-15 15:44 ` Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 3/6] Create empty common/linux-maps.[ch] Jan Kratochvil
` (6 subsequent siblings)
8 siblings, 2 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-10 21:07 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
Hello Aleksandar,
to send something here is some draft, there will be still some changes.
I had first difficulties to apply it to FSF GDB HEAD as it has some conflicts
so I had to rebase it first.
It is not a normal review as your patch has merged code moves + code
modifications which is unreviewable. Moves and modifications need to be in
separate patches so that one can see what has changed in the diff.
fileio_read_stralloc you have reimplemented for gdbserver; I have rather
chosen to generalize the gdb/ variant and call the same common/ code from both
gdb and gdbserver. One may ask whether it is not more complicated than its
reimplementation, not sure.
By moving linux_find_memory_regions_full you have dropped make_cleanup there.
Its use from GDB may now leak memory as its called FUNC may throw an
exception. I have put there 'void **memory_to_free_ptr' to make it reusable
from both gdb and gdbserver.
I tried to make the patches similar to your code so that one can diff the
result against your patch.
There were many code formatting little changes and also needless casts
(probably from C++).
For the last [draft patch 6/6] - things not done there yet:
get_dynamic already parses/scans PHDRs, you introduce new PHDR parser, they
should be merged.
get_hex_build_id must not be based on soname, moreover playing with realname
on it, it is too fragile. It should be based on addresses, you know that l_ld
is absolute address inside the library. So find maps/smaps entry containing
l_ld, subtract its file offset from vaddr and you have the ELF header address.
Do not run get_hex_build_id quadratically - currently for each library you
open and scan maps/smaps again. Probably the best approach is to scan all
l_ld addresses from r_debug first, then qsort them and then linearly match
them to the maps/smaps entries. I am not sure but I guess they still should
be returned to GDB in their original order from r_debug for some backward and
solib-svr4.c compatibility. Also Gary Benson is working on incremental shlib
transfers from gdbserver so that it does not clash too much (it will anyway).
While just quadratic computation would be in real world acceptable all the
open/read/close syscalls I find really needlessly expensive.
PT_NOTE segment contains arbitrary number of notes, up to its size. You check
only the first entry there.
On Fri, 22 Feb 2013 16:06:44 +0100, Aleksandar Ristovski wrote:
> 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.
gdbserver reports PT_NOTE segment, not any section. gdbserver is dependent on
runtime information (segments), it cannot rely on debug/link information
(sections).
BTW ping me (possibly off-list) whether you plan to work on it now yourself or
whether I should be doing more of the changes described above; I sure have
also enough other work...
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* [draft patch 3/6] Create empty common/linux-maps.[ch]
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
2013-02-22 18:39 ` Aleksandar Ristovski
2013-03-10 21:07 ` [draft patch 0/6] Split FYI and some review notes Jan Kratochvil
@ 2013-03-10 21:08 ` Jan Kratochvil
2013-03-22 14:54 ` [patch " Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 4/6] Prepare linux_find_memory_regions_full & co. for move Jan Kratochvil
` (5 subsequent siblings)
8 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-10 21:08 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
--- 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)
--- /dev/null
+++ b/gdb/common/linux-maps.c
@@ -0,0 +1,25 @@
+/* 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"
+#else
+#include "defs.h"
+#endif
+
+#include "linux-maps.h"
--- /dev/null
+++ b/gdb/common/linux-maps.h
@@ -0,0 +1,22 @@
+/* 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
+
+#endif /* COMMON_LINUX_MAPS_H */
--- 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
--- 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
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -510,6 +510,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)
--- 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.
@@ -332,13 +368,18 @@ 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_regobj="${srv_regobj} reg-tilegx32.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
^ permalink raw reply [flat|nested] 79+ messages in thread
* [draft patch 2/6] Merge multiple hex conversions
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
` (4 preceding siblings ...)
2013-03-10 21:08 ` [draft patch 1/6] Move utility functions to common/ Jan Kratochvil
@ 2013-03-10 21:08 ` Jan Kratochvil
2013-03-22 13:05 ` [patch " Aleksandar Ristovski
2013-03-10 21:09 ` [draft patch 6/6] gdbserver build-id attribute generator (unfixed) Jan Kratochvil
` (2 subsequent siblings)
8 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-10 21:08 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -264,7 +264,7 @@ strtoulst (const char *num, const char **trailer, int base)
/* Convert hex digit A to a number. */
-static int
+int
fromhex (int a)
{
if (a >= '0' && a <= '9')
@@ -274,7 +274,7 @@ fromhex (int a)
else if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
else
- error (_("Reply contains invalid hex digit %d"), a);
+ error (_("Invalid hex digit %d"), a);
}
int
@@ -298,7 +298,7 @@ hex2bin (const char *hex, gdb_byte *bin, int count)
/* Convert number NIB to a hex digit. */
-static int
+int
tohex (int nib)
{
if (nib < 10)
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -74,6 +74,10 @@ char *savestring (const char *ptr, size_t len);
ULONGEST strtoulst (const char *num, const char **trailer, int base);
+extern int fromhex (int a);
+
+extern int tohex (int nib);
+
extern int hex2bin (const char *hex, gdb_byte *bin, int count);
extern int bin2hex (const gdb_byte *bin, char *hex, int count);
--- a/gdb/gdbserver/gdbreplay.c
+++ b/gdb/gdbserver/gdbreplay.c
@@ -273,7 +273,7 @@ remote_open (char *name)
}
static int
-tohex (int ch)
+fromhex (int ch)
{
if (ch >= '0' && ch <= '9')
{
@@ -336,11 +336,11 @@ logchar (FILE *fp)
ch2 = fgetc (fp);
fputc (ch2, stdout);
fflush (stdout);
- ch = tohex (ch2) << 4;
+ ch = fromhex (ch2) << 4;
ch2 = fgetc (fp);
fputc (ch2, stdout);
fflush (stdout);
- ch |= tohex (ch2);
+ ch |= fromhex (ch2);
break;
default:
/* Treat any other char as just itself */
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -416,20 +416,6 @@ remote_close (void)
reset_readchar ();
}
-/* 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";
@@ -457,25 +443,6 @@ ishex (int ch, int *val)
#ifndef IN_PROCESS_AGENT
-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;
-}
-
void
decode_address (CORE_ADDR *addrp, const char *start, int len)
{
@@ -511,37 +478,8 @@ 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;
-}
-
/* Convert BUFFER, binary data at least LEN bytes long, into escaped
binary data in OUT_BUF. Set *OUT_LEN to the length of the data
encoded in OUT_BUF, and return the number of bytes in OUT_BUF
@@ -1608,7 +1546,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
/* Send the request. */
strcpy (own_buf, "qSymbol:");
- hexify (own_buf + strlen ("qSymbol:"), name, strlen (name));
+ bin2hex ((const gdb_byte *) name, own_buf + strlen ("qSymbol:"),
+ strlen (name));
if (putpkt (own_buf) < 0)
return -1;
@@ -1770,7 +1709,7 @@ monitor_output (const char *msg)
char *buf = xmalloc (strlen (msg) * 2 + 2);
buf[0] = 'O';
- hexify (buf + 1, msg, 0);
+ bin2hex ((const gdb_byte *) msg, buf + 1, 0);
putpkt (buf);
free (buf);
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1751,7 +1751,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
return;
}
- if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2)
+ if ((len % 2) != 0
+ || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2)
{
write_enn (own_buf);
free (mon);
@@ -2045,7 +2046,7 @@ handle_v_run (char *own_buf)
{
/* FIXME: Fail request if out of memory instead of dying. */
new_argv[i] = xmalloc (1 + (next_p - p) / 2);
- unhexify (new_argv[i], p, (next_p - p) / 2);
+ hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
new_argv[i][(next_p - p) / 2] = '\0';
}
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -322,8 +322,6 @@ int decode_search_memory_packet (const char *buf, int packet_len,
gdb_byte *pattern,
unsigned int *pattern_lenp);
-int unhexify (char *bin, const char *hex, int count);
-int hexify (char *hex, const char *bin, int count);
int remote_escape_output (const gdb_byte *buffer, int len,
gdb_byte *out_buf, int *out_len,
int out_maxlen);
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -2679,7 +2679,7 @@ cmd_qtdpsrc (char *own_buf)
packet = unpack_varlen_hex (packet, &slen);
++packet; /* skip a colon */
src = xmalloc (slen + 1);
- nbytes = unhexify (src, packet, strlen (packet) / 2);
+ nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2);
src[nbytes] = '\0';
newlast = xmalloc (sizeof (struct source_string));
@@ -2721,7 +2721,7 @@ cmd_qtdv (char *own_buf)
nbytes = strlen (packet) / 2;
varname = xmalloc (nbytes + 1);
- nbytes = unhexify (varname, packet, nbytes);
+ nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes);
varname[nbytes] = '\0';
tsv = create_trace_state_variable (num, 1);
@@ -3594,17 +3594,17 @@ cmd_qtstatus (char *packet)
str = (tracing_user_name ? tracing_user_name : "");
slen = strlen (str);
buf1 = (char *) alloca (slen * 2 + 1);
- hexify (buf1, str, slen);
+ bin2hex ((const gdb_byte *) str, buf1, slen);
str = (tracing_notes ? tracing_notes : "");
slen = strlen (str);
buf2 = (char *) alloca (slen * 2 + 1);
- hexify (buf2, str, slen);
+ bin2hex ((const gdb_byte *) str, buf2, slen);
str = (tracing_stop_note ? tracing_stop_note : "");
slen = strlen (str);
buf3 = (char *) alloca (slen * 2 + 1);
- hexify (buf3, str, slen);
+ bin2hex ((const gdb_byte *) str, buf3, slen);
trace_debug ("Returning trace status as %d, stop reason %s",
tracing, tracing_stop_reason);
@@ -4078,7 +4078,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
user = xmalloc (nbytes + 1);
- nbytes = unhexify (user, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) user, nbytes);
user[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("User is '%s'", user);
@@ -4092,7 +4092,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
notes = xmalloc (nbytes + 1);
- nbytes = unhexify (notes, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes);
notes[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("Notes is '%s'", notes);
@@ -4106,7 +4106,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
stopnote = xmalloc (nbytes + 1);
- nbytes = unhexify (stopnote, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes);
stopnote[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("tstop note is '%s'", stopnote);
--- a/gdb/monitor.c
+++ b/gdb/monitor.c
@@ -226,21 +226,6 @@ monitor_error (char *function, char *message,
message, safe_string);
}
-/* 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 (_("Invalid hex digit %d"), a);
-}
-
/* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses
This function exists to get around the problem that many host platforms
--- 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,8 +179,6 @@ static void remote_find_new_threads (void);
static void record_currthread (ptid_t currthread);
-static int fromhex (int a);
-
static int putpkt_binary (char *buf, int cnt);
static void check_binary_download (CORE_ADDR addr);
@@ -4548,32 +4544,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);
-}
-
-/* Convert number NIB to a hex digit. */
-
-static int
-tohex (int nib)
-{
- if (nib < 10)
- return '0' + nib;
- else
- return 'a' + nib - 10;
-}
\f
/* Check for the availability of vCont. This function should also check
the response. */
^ permalink raw reply [flat|nested] 79+ messages in thread
* [draft patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
` (2 preceding siblings ...)
2013-03-10 21:08 ` [draft patch 3/6] Create empty common/linux-maps.[ch] Jan Kratochvil
@ 2013-03-10 21:08 ` Jan Kratochvil
2013-03-22 13:34 ` [patch " Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 1/6] Move utility functions to common/ Jan Kratochvil
` (4 subsequent siblings)
8 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-10 21:08 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3444,55 +3444,73 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
- {
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
- xfree (buf);
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
else
*buf_p = buf;
- return buf_pos;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3503,11 +3521,31 @@ target_fileio_read_alloc_1 (const char *filename,
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
}
-
- QUIT;
}
}
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ do_cleanups (close_cleanup);
+ return retval;
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and return
the size of the transferred data. See the declaration in "target.h"
function for more information about the return value. */
@@ -3524,14 +3562,16 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
char *buffer;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename,
- (gdb_byte **) &buffer, 1);
+ transferred = func (filename, (gdb_byte **) &buffer, 1);
if (transferred < 0)
return NULL;
@@ -3554,6 +3594,11 @@ target_fileio_read_stralloc (const char *filename)
return buffer;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
^ permalink raw reply [flat|nested] 79+ messages in thread
* [draft patch 1/6] Move utility functions to common/
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
` (3 preceding siblings ...)
2013-03-10 21:08 ` [draft patch 4/6] Prepare linux_find_memory_regions_full & co. for move Jan Kratochvil
@ 2013-03-10 21:08 ` Jan Kratochvil
2013-03-22 13:13 ` [patch " Aleksandar Ristovski
2013-03-10 21:08 ` [draft patch 2/6] Merge multiple hex conversions Jan Kratochvil
` (3 subsequent siblings)
8 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-10 21:08 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -214,30 +214,6 @@ number_is_in_list (char *list, int number)
/* See documentation in cli-utils.h. */
char *
-skip_spaces (char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* A const-correct version of the above. */
-
-const char *
-skip_spaces_const (const char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* See documentation in cli-utils.h. */
-
-char *
skip_to_space (char *chp)
{
if (chp == NULL)
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -89,15 +89,6 @@ extern int get_number_or_range (struct get_number_or_range_state *state);
extern int number_is_in_list (char *list, int number);
-/* Skip leading whitespace characters in INP, returning an updated
- pointer. If INP is NULL, return NULL. */
-
-extern char *skip_spaces (char *inp);
-
-/* A const-correct version of the above. */
-
-extern const char *skip_spaces_const (const char *inp);
-
/* Skip leading non-whitespace characters in INP, returning an updated
pointer. If INP is NULL, return NULL. */
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
/* The xmalloc() (libiberty.h) family of memory management routines.
@@ -161,3 +162,189 @@ 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. */
+
+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;
+}
+
+/* See documentation in cli-utils.h. */
+
+char *
+skip_spaces (char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
+
+/* A const-correct version of the above. */
+
+const char *
+skip_spaces_const (const char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -25,6 +25,25 @@
#include <stddef.h>
#include <stdarg.h>
+/* Static target-system-dependent parameters for GDB. */
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) then use it to set
+ the number of bits in a host char. If not, use the same size
+ as the target. */
+
+#if defined (CHAR_BIT)
+#define HOST_CHAR_BIT CHAR_BIT
+#else
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif
+
extern void malloc_failure (long size) ATTRIBUTE_NORETURN;
extern void internal_error (const char *file, int line, const char *, ...)
ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 4);
@@ -53,4 +72,19 @@ int xsnprintf (char *str, size_t size, const char *format, ...)
char *savestring (const char *ptr, size_t len);
+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+extern int hex2bin (const char *hex, gdb_byte *bin, int count);
+
+extern int bin2hex (const gdb_byte *bin, char *hex, int count);
+
+/* Skip leading whitespace characters in INP, returning an updated
+ pointer. If INP is NULL, return NULL. */
+
+extern char *skip_spaces (char *inp);
+
+/* A const-correct version of the above. */
+
+extern const char *skip_spaces_const (const char *inp);
+
#endif
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -648,25 +648,6 @@ extern void *alloca ();
enum { MAX_REGISTER_SIZE = 64 };
-/* Static target-system-dependent parameters for GDB. */
-
-/* Number of bits in a char or unsigned char for the target machine.
- Just like CHAR_BIT in <limits.h> but describes the target machine. */
-#if !defined (TARGET_CHAR_BIT)
-#define TARGET_CHAR_BIT 8
-#endif
-
-/* If we picked up a copy of CHAR_BIT from a configuration file
- (which may get it by including <limits.h>) then use it to set
- the number of bits in a host char. If not, use the same size
- as the target. */
-
-#if defined (CHAR_BIT)
-#define HOST_CHAR_BIT CHAR_BIT
-#else
-#define HOST_CHAR_BIT TARGET_CHAR_BIT
-#endif
-
/* In findvar.c. */
extern LONGEST extract_signed_integer (const gdb_byte *, int,
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4564,25 +4564,6 @@ fromhex (int a)
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
@@ -4593,24 +4574,6 @@ tohex (int 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. */
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -39,10 +39,6 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever);
extern int putpkt (char *buf);
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
extern void async_remote_interrupt_twice (void *arg);
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3318,105 +3318,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. */
--- 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);
^ permalink raw reply [flat|nested] 79+ messages in thread
* [draft patch 5/6] Move linux_find_memory_regions_full & co.
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
` (6 preceding siblings ...)
2013-03-10 21:09 ` [draft patch 6/6] gdbserver build-id attribute generator (unfixed) Jan Kratochvil
@ 2013-03-10 21:09 ` Jan Kratochvil
2013-03-22 13:05 ` [patch " Aleksandar Ristovski
2013-04-04 16:08 ` [patch] gdbserver build-id in qxfer_libraries reply Jan Kratochvil
8 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-10 21:09 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -348,3 +348,93 @@ skip_spaces_const (const char *chp)
chp++;
return chp;
}
+
+LONGEST
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
+{
+ size_t buf_alloc, buf_pos;
+ gdb_byte *buf;
+ LONGEST n;
+ int target_errno;
+
+ /* Start by reading up to 4K at a time. The target will throttle
+ this number down if necessary. */
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
+ buf_pos = 0;
+ while (1)
+ {
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
+ {
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
+ else
+ *buf_p = buf;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
+ }
+
+ buf_pos += n;
+
+ /* If the buffer is filling up, expand it. */
+ if (buf_alloc < buf_pos * 2)
+ {
+ buf_alloc *= 2;
+ buf = xrealloc (buf, buf_alloc);
+ }
+ }
+}
+
+char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
+{
+ char *buffer;
+ LONGEST i, transferred;
+
+ transferred = func (filename, (gdb_byte **) &buffer, 1);
+
+ if (transferred < 0)
+ return NULL;
+
+ if (transferred == 0)
+ return xstrdup ("");
+
+ buffer[transferred] = 0;
+
+ /* Check for embedded NUL bytes; but allow trailing NULs. */
+ for (i = strlen (buffer); i < transferred; i++)
+ if (buffer[i] != 0)
+ {
+ warning (_("target file %s "
+ "contained unexpected null characters"),
+ filename);
+ break;
+ }
+
+ return buffer;
+}
+
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -91,4 +91,15 @@ extern char *skip_spaces (char *inp);
extern const char *skip_spaces_const (const char *inp);
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
+ read_alloc_pread_ftype *pread_func, int padding,
+ void **memory_to_free_ptr);
+
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+extern char *read_stralloc (const char *filename,
+ read_stralloc_func_ftype *func);
+
#endif
--- a/gdb/common/linux-maps.c
+++ b/gdb/common/linux-maps.c
@@ -18,8 +18,194 @@
#ifdef GDBSERVER
#include "server.h"
+#include <fcntl.h>
+#include <unistd.h>
#else
#include "defs.h"
+#include "target.h"
#endif
#include "linux-maps.h"
+#include "gdb_assert.h"
+#include <ctype.h>
+#include <string.h>
+
+/* 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);
+
+ p = skip_spaces_const (p);
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ p = skip_spaces_const (p);
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ p = skip_spaces_const (p);
+ *filename = p;
+}
+
+#ifdef GDBSERVER
+
+static int
+linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf,
+ int len, ULONGEST offset,
+ int *target_errno)
+{
+ int retval = pread (handle, read_buf, len, offset);
+
+ *target_errno = errno;
+ return retval;
+}
+
+static LONGEST
+linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p,
+ int padding)
+{
+ int fd;
+ LONGEST retval;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread,
+ padding, NULL);
+
+ close (fd);
+
+ return retval;
+}
+
+#endif /* GDBSERVER */
+
+static char *
+linux_find_memory_read_stralloc (const char *filename)
+{
+#ifndef GDBSERVER
+ return target_fileio_read_stralloc (filename);
+#else /* GDBSERVER */
+ return read_stralloc (filename, linux_find_memory_read_stralloc_1);
+#endif /* GDBSERVER */
+}
+
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
+
+int
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
+
+ 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. */
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
+ }
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
+ }
+
+ return -1;
+}
--- a/gdb/common/linux-maps.h
+++ b/gdb/common/linux-maps.h
@@ -19,4 +19,29 @@
#ifndef COMMON_LINUX_MAPS_H
#define COMMON_LINUX_MAPS_H
+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);
+
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
+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);
+
+extern int
+ linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr);
+
#endif /* COMMON_LINUX_MAPS_H */
--- 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,44 +208,6 @@ 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);
-
- p = skip_spaces_const (p);
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- p = skip_spaces_const (p);
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- p = skip_spaces_const (p);
- *filename = p;
-}
-
/* Implement the "info proc" command. */
static void
@@ -661,115 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
-/* Callback function for linux_find_memory_regions_full. If it returns
- non-zero linux_find_memory_regions_full returns immediately with that
- value. */
-
-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 PID for a corefile. Call FUNC
- with FUNC_DATA for each such region. Return immediately with the
- value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
- be registered to be freed automatically if called FUNC throws an
- exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
- not used. Return -1 if error occurs, 0 if all memory regions have
- been processed or return the value from FUNC if FUNC returns
- non-zero. */
-
-static int
-linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
- void *func_data, void **memory_to_free_ptr)
-{
- char filename[100];
- char *data;
-
- xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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", (int) pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- char *line;
- int retval = 0;
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = data;
- }
-
- 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. */
- retval = func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, func_data);
- if (retval != 0)
- break;
- }
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (data == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (data);
- return retval;
- }
-
- return -1;
-}
-
/* A structure for passing information through
linux_find_memory_regions_full. */
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3461,69 +3461,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
target_fileio_read_alloc; see the declaration of that function for more
information. */
-typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
- ULONGEST offset, int *target_errno);
-
-static LONGEST
-read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
- int padding, void **memory_to_free_ptr)
-{
- size_t buf_alloc, buf_pos;
- gdb_byte *buf;
- LONGEST n;
- int target_errno;
-
- /* Start by reading up to 4K at a time. The target will throttle
- this number down if necessary. */
- buf_alloc = 4096;
- buf = xmalloc (buf_alloc);
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = buf;
- }
- buf_pos = 0;
- while (1)
- {
- n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
- buf_pos, &target_errno);
- if (n <= 0)
- {
- if (n < 0 || (n == 0 && buf_pos == 0))
- {
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (buf == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (buf);
- }
- else
- *buf_p = buf;
-
- if (n < 0)
- {
- /* An error occurred. */
- return -1;
- }
- else
- {
- /* Read all there was. */
- return buf_pos;
- }
- }
-
- buf_pos += n;
-
- /* If the buffer is filling up, expand it. */
- if (buf_alloc < buf_pos * 2)
- {
- buf_alloc *= 2;
- buf = xrealloc (buf, buf_alloc);
- }
- }
-}
-
static LONGEST
target_fileio_read_alloc_1 (const char *filename,
gdb_byte **buf_p, int padding)
@@ -3562,38 +3499,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
- gdb_byte **buf_p, int padding);
-
-static char *
-read_stralloc (const char *filename, read_stralloc_func_ftype *func)
-{
- char *buffer;
- LONGEST i, transferred;
-
- transferred = func (filename, (gdb_byte **) &buffer, 1);
-
- if (transferred < 0)
- return NULL;
-
- if (transferred == 0)
- return xstrdup ("");
-
- buffer[transferred] = 0;
-
- /* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (buffer); i < transferred; i++)
- if (buffer[i] != 0)
- {
- warning (_("target file %s "
- "contained unexpected null characters"),
- filename);
- break;
- }
-
- return buffer;
-}
-
char *
target_fileio_read_stralloc (const char *filename)
{
^ permalink raw reply [flat|nested] 79+ messages in thread
* [draft patch 6/6] gdbserver build-id attribute generator (unfixed)
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
` (5 preceding siblings ...)
2013-03-10 21:08 ` [draft patch 2/6] Merge multiple hex conversions Jan Kratochvil
@ 2013-03-10 21:09 ` 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-10 21:09 ` [draft patch 5/6] Move linux_find_memory_regions_full & co Jan Kratochvil
2013-04-04 16:08 ` [patch] gdbserver build-id in qxfer_libraries reply Jan Kratochvil
8 siblings, 2 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-10 21:09 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40179,6 +40179,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
@@ -40196,7 +40199,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40212,6 +40215,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
--- 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>
--- 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>
@@ -5639,6 +5640,149 @@ struct link_map_offsets
int l_prev_offset;
};
+struct find_memory_region_callback_data
+{
+ unsigned is_elf64 : 1;
+ const char *soname;
+ CORE_ADDR l_addr;
+
+ /* Return. Meaningful iff *build_id != NULL. */
+ size_t build_idsz;
+
+ /* Return. malloc allocated memory. */
+ void *build_id;
+};
+
+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;
+#define HDR(p, hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+ if (linux_read_memory (vaddr, (unsigned char *) &ehdr, sizeof (ehdr))
+ == 0
+ && HDR (p, ehdr, e_ident[EI_MAG0]) == ELFMAG0
+ && HDR (p, ehdr, e_ident[EI_MAG1]) == ELFMAG1
+ && HDR (p, ehdr, e_ident[EI_MAG2]) == ELFMAG2
+ && HDR (p, ehdr, e_ident[EI_MAG3]) == ELFMAG3)
+ {
+ unsigned i;
+
+ for (i = 0; i < HDR (p, ehdr, e_phnum); ++i)
+ {
+ if (linux_read_memory (vaddr + HDR (p, ehdr, e_phoff)
+ + HDR (p, ehdr, e_phentsize) * i,
+ (unsigned char *) &phdr,
+ HDR (p, ehdr, e_phentsize)) != 0)
+ {
+ warning ("Could not read program header.");
+ break;
+ }
+ if (HDR (p, phdr, p_type) == PT_NOTE)
+ {
+ nhdr = xmalloc (HDR (p, phdr, p_memsz));
+
+ if (linux_read_memory (p->l_addr + HDR (p, phdr, p_vaddr),
+ (unsigned char *) nhdr,
+ HDR (p, phdr, p_memsz)) != 0)
+ {
+ warning ("Could not read note.");
+ break;
+ }
+ if (HDR (p, *nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ p->build_idsz = (HDR (p, *nhdr, n_namesz)
+ + HDR (p, *nhdr, n_descsz)
+ + (p->is_elf64
+ ? sizeof (nhdr->_64)
+ : sizeof (nhdr->_32)));
+ if (p->build_idsz > HDR (p, phdr, p_memsz))
+ {
+ warning ("NT_GNU_BUILD_ID has invalid size..");
+ break;
+ }
+ p->build_id = nhdr;
+ break;
+ }
+ free (nhdr);
+ }
+ }
+ }
+ else
+ warning ("Reading build-id failed.");
+
+ 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;
+ 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 != 0;
+ data.soname = real_soname;
+ data.l_addr = l_addr;
+ data.build_idsz = 0;
+ data.build_id = NULL;
+
+ linux_find_memory_regions_full (lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback, &data, NULL);
+ free (real_soname);
+ if (data.build_id != NULL)
+ {
+ hex_build_id = xmalloc (data->build_idsz * 2 + 1);
+ if (bin2hex (data.build_id, hex_build_id, data->build_idsz)
+ != data->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 (data.build_id);
+ return hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5760,6 +5904,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)
{
@@ -5768,7 +5913,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 + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
uintptr_t document_len = p - document;
@@ -5778,12 +5928,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, "/>");
free (name);
+ xfree (hex_enc_build_id);
}
else if (lm_prev == 0)
{
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 6/6] gdbserver build-id attribute generator (unfixed)
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
1 sibling, 0 replies; 79+ messages in thread
From: Eli Zaretskii @ 2013-03-10 22:04 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: aristovski, gdb-patches
> Date: Sun, 10 Mar 2013 22:08:43 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
>
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
OK for this part, thanks.
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
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-15 15:44 ` Aleksandar Ristovski
1 sibling, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-11 14:25 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-03-10 05:07 PM, Jan Kratochvil wrote:
> Hello Aleksandar,
Hello Jan,
>
> to send something here is some draft, there will be still some changes.
>
> I had first difficulties to apply it to FSF GDB HEAD as it has some conflicts
> so I had to rebase it first.
It applied cleanly when I posted it, I rebased it and made sure it
applies to cleanly cvs checked out tree. Sorry if you had difficulties
applying the patch, I could have rebased it for you.
>
> It is not a normal review as your patch has merged code moves + code
> modifications which is unreviewable. Moves and modifications need to be in
> separate patches so that one can see what has changed in the diff.
I thought it is better to keep the whole change as a single blob so it
can be easily reverted should there be any problems. But I can continue
with the sequence of patches as you broked them down.
>
> fileio_read_stralloc you have reimplemented for gdbserver; I have rather
> chosen to generalize the gdb/ variant and call the same common/ code from both
> gdb and gdbserver. One may ask whether it is not more complicated than its
> reimplementation, not sure.
>
> By moving linux_find_memory_regions_full you have dropped make_cleanup there.
> Its use from GDB may now leak memory as its called FUNC may throw an
> exception. I have put there 'void **memory_to_free_ptr' to make it reusable
> from both gdb and gdbserver.
>
> I tried to make the patches similar to your code so that one can diff the
> result against your patch.
>
> There were many code formatting little changes and also needless casts
> (probably from C++).
>
> For the last [draft patch 6/6] - things not done there yet:
>
> get_dynamic already parses/scans PHDRs, you introduce new PHDR parser, they
> should be merged.
>
> get_hex_build_id must not be based on soname, moreover playing with realname
> on it, it is too fragile. It should be based on addresses, you know that l_ld
> is absolute address inside the library. So find maps/smaps entry containing
> l_ld, subtract its file offset from vaddr and you have the ELF header address.
>
> Do not run get_hex_build_id quadratically - currently for each library you
> open and scan maps/smaps again. Probably the best approach is to scan all
> l_ld addresses from r_debug first, then qsort them and then linearly match
> them to the maps/smaps entries. I am not sure but I guess they still should
> be returned to GDB in their original order from r_debug for some backward and
> solib-svr4.c compatibility. Also Gary Benson is working on incremental shlib
> transfers from gdbserver so that it does not clash too much (it will anyway).
> While just quadratic computation would be in real world acceptable all the
> open/read/close syscalls I find really needlessly expensive.
I thought it would be an overkill to make it any more optimal. Ideal
situation would be to send "library loaded"/ "library unloaded" events
instead of sending the whole list each time.
But sure, I'll do the qsort.
>
> PT_NOTE segment contains arbitrary number of notes, up to its size. You check
> only the first entry there.
Ok.
>
> On Fri, 22 Feb 2013 16:06:44 +0100, Aleksandar Ristovski wrote:
>> 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.
>
> gdbserver reports PT_NOTE segment, not any section. gdbserver is dependent on
> runtime information (segments), it cannot rely on debug/link information
> (sections).
My references to the sections is to denote we are dealing with the
contents of the section (which is mapped to the segment).
>
> BTW ping me (possibly off-list) whether you plan to work on it now yourself or
> whether I should be doing more of the changes described above; I sure have
> also enough other work...
If you feel strongly, you can take it over. Otherwise, I will finish it.
I plan some follow up changes to all this.
If you want the patches to be attributed to you, that is also fine by
me, let me know.
>
>
> Thanks,
> Jan
>
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
2013-03-11 14:25 ` Aleksandar Ristovski
@ 2013-03-11 15:07 ` Jan Kratochvil
2013-03-14 18:43 ` Gary Benson
0 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-11 15:07 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches, Gary Benson
On Mon, 11 Mar 2013 15:25:13 +0100, Aleksandar Ristovski wrote:
> On 13-03-10 05:07 PM, Jan Kratochvil wrote:
> > Do not run get_hex_build_id quadratically - currently for each library you
> > open and scan maps/smaps again. Probably the best approach is to scan all
> > l_ld addresses from r_debug first, then qsort them and then linearly match
> > them to the maps/smaps entries. I am not sure but I guess they still should
> > be returned to GDB in their original order from r_debug for some backward and
> > solib-svr4.c compatibility. Also Gary Benson is working on incremental shlib
> > transfers from gdbserver so that it does not clash too much (it will anyway).
> > While just quadratic computation would be in real world acceptable all the
> > open/read/close syscalls I find really needlessly expensive.
>
> I thought it would be an overkill to make it any more optimal. Ideal
> situation would be to send "library loaded"/ "library unloaded"
> events instead of sending the whole list each time.
>
> But sure, I'll do the qsort.
Particularly this shared library list handling has been proven to be
performance critical. All the performance improvements by Gary Benson target
this issue, including sending the '"library loaded"/ "library unloaded"
events' (being worked on).
Ccing Gary as the qsort by l_ld in gdbserver apparently has to clash with his
patch being cooked.
> If you feel strongly, you can take it over. Otherwise, I will finish
> it. I plan some follow up changes to all this.
OK, great, so leaving next update on you now.
> If you want the patches to be attributed to you, that is also fine
> by me, let me know.
I mostly only reformatted your code, I do not mind either way.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
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
0 siblings, 2 replies; 79+ messages in thread
From: Gary Benson @ 2013-03-14 18:43 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Aleksandar Ristovski, gdb-patches
Jan Kratochvil wrote:
> On Mon, 11 Mar 2013 15:25:13 +0100, Aleksandar Ristovski wrote:
> > On 13-03-10 05:07 PM, Jan Kratochvil wrote:
> > > Do not run get_hex_build_id quadratically - currently for each
> > > library you open and scan maps/smaps again. Probably the best
> > > approach is to scan all l_ld addresses from r_debug first, then
> > > qsort them and then linearly match them to the maps/smaps
> > > entries. I am not sure but I guess they still should be
> > > returned to GDB in their original order from r_debug for some
> > > backward and solib-svr4.c compatibility. Also Gary Benson is
> > > working on incremental shlib transfers from gdbserver so that it
> > > does not clash too much (it will anyway). While just quadratic
> > > computation would be in real world acceptable all the
> > > open/read/close syscalls I find really needlessly expensive.
> >
> > I thought it would be an overkill to make it any more
> > optimal. Ideal situation would be to send "library loaded"/
> > "library unloaded" events instead of sending the whole list
> > each time.
> >
> > But sure, I'll do the qsort.
>
> Particularly this shared library list handling has been proven to
> be performance critical. All the performance improvements by Gary
> Benson target this issue, including sending the '"library loaded"/
> "library unloaded" events' (being worked on).
It's definitely performance critical on the GDB side. There are
people out there debugging apps with 4000+ shared libraries, and
that exposes all kinds of issues :)
Per your suggestion of gdbserver sending events... I've spent some
time thinking about this. I think the direction of the protocol is
correct, in that GDB asks for the library list when it wants it.
What exactly is transferred is open to change (whole list vs deltas)
but I don't know whether anybody is actually having issues with
performance stemming from the size of the transferred list. I can
certainly imagine scenarios where it would be the bottleneck, but
I don't know if these exist in the real world.
Note that since Tom's ambiguous linespec work went in GDB needs to
update its list at every change. You could seriously speed things up
if you could eliminate this need--I considered making it asynchronous
at one point, but couldn't get around it.
> Ccing Gary as the qsort by l_ld in gdbserver apparently has to clash
> with his patch being cooked.
I think they do need to be transferred to GDB in the order they were
read from r_debug. Thank you Jan for spotting this.
Thanks,
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
2013-03-14 18:43 ` Gary Benson
@ 2013-03-14 19:55 ` Tom Tromey
2013-03-15 15:35 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Tom Tromey @ 2013-03-14 19:55 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Aleksandar Ristovski, gdb-patches
>>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
Gary> Note that since Tom's ambiguous linespec work went in GDB needs to
Gary> update its list at every change. You could seriously speed things up
Gary> if you could eliminate this need--I considered making it asynchronous
Gary> at one point, but couldn't get around it.
The plan is for the itset work to help with this; plus also perhaps
making a new objfile-limiting linespec, like "break libwhatever.so:function".
itsets will let us restrict the lookups to a given set of program
spaces; those left out will not have to have libraries loaded.
The linespec change will let us avoid loading debuginfo for other
libraries.
This may also need fine-grained breakpoint re-setting. I filed this in
bugzilla recently. I think the linespec thing is in there somewhere
too.
This approach assumes that the user knows about these things and cares
about gdb performance. So maybe another tradeoff is better. On balance
I tend to still like the ambiguous linespec approach, since I tend to
think predictability and uniformity is more important to more users than
debugger performance.
FWIW if you have patches to improve laziness, you can maybe test them by
arranging for your test program to crash -- don't set any breakpoints at
all.
Tom
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
2013-03-14 18:43 ` Gary Benson
2013-03-14 19:55 ` Tom Tromey
@ 2013-03-15 15:35 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-15 15:35 UTC (permalink / raw)
To: gdb-patches
On 13-03-14 02:43 PM, Gary Benson wrote:
> It's definitely performance critical on the GDB side. There are
> people out there debugging apps with 4000+ shared libraries, and
> that exposes all kinds of issues:)
>
> Per your suggestion of gdbserver sending events... I've spent some
> time thinking about this. I think the direction of the protocol is
> correct, in that GDB asks for the library list when it wants it.
> What exactly is transferred is open to change (whole list vs deltas)
> but I don't know whether anybody is actually having issues with
> performance stemming from the size of the transferred list. I can
> certainly imagine scenarios where it would be the bottleneck, but
> I don't know if these exist in the real world.
If the reference for apps with 4000+ shared libraries comes from 'real
world' then I can imagine passing all 4000+ each time would be one of
the "all kinds of issues" that would be exposed :-)
Events would be 'natural' and in accordance with many other events. It
doesn't mean gdb could not query for the whole list (e.g. when attaching
to an already running process).
---
Aleksandar
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
2013-03-15 15:44 ` Aleksandar Ristovski
@ 2013-03-15 15:38 ` Aleksandar Ristovski
2013-03-15 16:28 ` Jan Kratochvil
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-15 15:38 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-03-10 05:07 PM, Jan Kratochvil wrote:
> get_hex_build_id must not be based on soname, moreover playing with realname
> on it, it is too fragile. It should be based on addresses, you know that l_ld
> is absolute address inside the library. So find maps/smaps entry containing
> l_ld, subtract its file offset from vaddr and you have the ELF header address.
Thinking about this, we have to do a real name on this as maps/smaps
contain name as requested initially, not pathname as resolved.
While we can determine entry that corresponds to the given l_ld, the
name sent to gdb needs to be realname as that is what gdb expects.
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
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-15 15:44 ` Aleksandar Ristovski
2013-03-15 15:38 ` Aleksandar Ristovski
2013-03-15 16:28 ` Jan Kratochvil
1 sibling, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-15 15:44 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
On 13-03-10 05:07 PM, Jan Kratochvil wrote:
> get_hex_build_id must not be based on soname, moreover playing with realname
> on it, it is too fragile. It should be based on addresses, you know that l_ld
> is absolute address inside the library. So find maps/smaps entry containing
> l_ld, subtract its file offset from vaddr and you have the ELF header address.
Thinking about this, we have to do a real name on this as maps/smaps
contain name as requested initially, not pathname as resolved.
While we can determine entry that corresponds to the given l_ld, the
name sent to gdb needs to be realname as that is what gdb expects.
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
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
1 sibling, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-15 16:28 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Fri, 15 Mar 2013 16:37:37 +0100, Aleksandar Ristovski wrote:
> Thinking about this, we have to do a real name on this as maps/smaps
> contain name as requested initially, not pathname as resolved.
>
> While we can determine entry that corresponds to the given l_ld, the
> name sent to gdb needs to be realname as that is what gdb expects.
Name sent to gdb is from r_debug->link_map->l_name, gdbserver already sends it
that way and everyone seems to be fine with it
/proc/PID/maps name should be IMO really ignored, it has no use for anything
if I have not forgot about something. What do you want to use /proc/PID/maps
name for?
Maybe gdbserver should transform somehow the name from r_debug or use the name
fro /proc/PID/maps intead etc. but that would be completely unrelated new
patch.
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [draft patch 0/6] Split FYI and some review notes
2013-03-15 16:28 ` Jan Kratochvil
@ 2013-03-15 16:43 ` Aleksandar Ristovski
0 siblings, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-15 16:43 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-03-15 12:22 PM, Jan Kratochvil wrote:
> On Fri, 15 Mar 2013 16:37:37 +0100, Aleksandar Ristovski wrote:
>> Thinking about this, we have to do a real name on this as maps/smaps
>> contain name as requested initially, not pathname as resolved.
>>
>> While we can determine entry that corresponds to the given l_ld, the
>> name sent to gdb needs to be realname as that is what gdb expects.
>
> Name sent to gdb is from r_debug->link_map->l_name, gdbserver already sends it
> that way and everyone seems to be fine with it
Ah, of course. We will just send l_name. Ok, scratch my comment.
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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 ` Aleksandar Ristovski
2013-03-22 15:19 ` Aleksandar Ristovski
` (2 more replies)
1 sibling, 3 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:05 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 754 bytes --]
This is the final patch that does actual addition of build-id attribute
to qxfer_libraries.
* doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
'build-id' in description, example, new attribute in dtd.
* linux-low.c (linux-maps.h, search.h): Include.
(struct build_id_list): New structure.
(build_id_list_s): New typedef, new vector type def.
(free_build_id_list, compare_build_id_list,
compare_build_id_list_range, compare_build_id_list_inode): New.
(struct find_memory_region_callback_data): New.
(find_memory_region_callback): New fwd. declaration.
(read_build_id, find_memory_region_callback, get_hex_build_id): New.
(linux_qxfer_libraries_svr4): Add optional build-id attribute
to reply XML document.
Thanks,
Aleksandar
[-- Attachment #2: 0006-gdbserver-linux_qxfer_libraries_svr4-return-build-id.patch --]
[-- Type: text/x-patch, Size: 11817 bytes --]
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4ac28bb..5ff9e95 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40404,6 +40404,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
@@ -40421,7 +40424,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40437,6 +40440,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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..e4409ba 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/linux-low.c b/gdb/gdbserver/linux-low.c
index 523926d..8bbb5ba 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>
@@ -43,6 +44,7 @@
#include "gdb_stat.h"
#include <sys/vfs.h>
#include <sys/uio.h>
+#include <search.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -5643,6 +5645,265 @@ struct link_map_offsets
int l_prev_offset;
};
+
+/* Structure for holding all mappings. Only mapping
+ containing l_ld can have hex_build_id set. */
+
+struct build_id_list
+{
+ ULONGEST vaddr;
+
+ ULONGEST size;
+
+ ULONGEST offset;
+
+ ULONGEST inode;
+
+ const char *filename;
+ int read:1;
+ int write:1;
+ int exec:1;
+ int modified:1;
+
+ /* build_id is hex encoded string allocated using malloc, and
+ needs to be freed. */
+
+ char *hex_build_id;
+};
+
+typedef struct build_id_list build_id_list_s;
+
+DEF_VEC_O(build_id_list_s);
+
+static void
+free_build_id_list (VEC (build_id_list_s) *lst)
+{
+ if (VEC_length (build_id_list_s, lst))
+ {
+ int ix;
+ build_id_list_s *p;
+
+ for (ix = 0; VEC_iterate (build_id_list_s, lst, ix, p); ++ix)
+ xfree (p->hex_build_id);
+ }
+
+ VEC_free (build_id_list_s, lst);
+}
+
+/* Used for qsort-ing list by vaddr. */
+
+static int
+compare_build_id_list (const void *const b1,
+ const void *const b2)
+{
+ const build_id_list_s *const p1 = b1;
+ const build_id_list_s *const p2 = b2;
+
+ if (p1->vaddr > p2->vaddr)
+ return 1;
+ if (p1->vaddr < p2->vaddr)
+ return -1;
+ return 0;
+}
+
+/* Used for finding a mapping containing the given
+ l_ld passed in K. */
+
+static int
+compare_build_id_list_range (const void *const k,
+ const void *const b)
+{
+ const ULONGEST key = *(CORE_ADDR*) k;
+ const build_id_list_s *const p = b;
+
+ if (key < p->vaddr)
+ return -1;
+
+ if (key < p->vaddr + p->size)
+ return 0;
+
+ return 1;
+}
+
+/* Used for linear search of the lowest vaddr for the given
+ inode. */
+
+static int
+compare_build_id_list_inode (const void *const k, const void *const b)
+{
+ const ULONGEST key = *(ULONGEST*)k;
+ const build_id_list_s *const p = b;
+
+ return !(key == p->inode);
+}
+
+struct find_memory_region_callback_data {
+ unsigned is_elf64;
+
+ /* Return. Ordered list of all object mappings sorted in
+ ascending order by VADDR. Must be freed with free_build_id_list. */
+ VEC (build_id_list_s) *list;
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+/* Read .note.gnu.build-id from PT_NOTE. */
+
+static void
+read_build_id (struct find_memory_region_callback_data *const p,
+ build_id_list_s *const bil, const CORE_ADDR load_addr,
+ const CORE_ADDR l_addr)
+{
+ 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;
+#define HDR(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32))
+ if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (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 (load_addr + 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)
+ {
+ void *const pt_note = xmalloc (HDR (phdr, p_memsz));
+ const void *const pt_end
+ = (char*)pt_note + HDR (phdr, p_memsz);
+
+ if (linux_read_memory (HDR (phdr, p_vaddr) + l_addr,
+ pt_note, HDR (phdr, p_memsz)) != 0)
+ {
+ xfree (pt_note);
+ warning ("Could not read note.");
+ break;
+ }
+
+ for (nhdr = pt_note; (void*)nhdr < pt_end;)
+ {
+ const size_t note_sz
+ = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz)
+ + SIZEOFHDR (*nhdr);
+
+ if ((char*)nhdr + note_sz > (char*)pt_end)
+ {
+ warning ("Malformed PT_NOTE\n");
+ break;
+ }
+ if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ /* .note.gnu.build-id. */
+ bil->hex_build_id = xmalloc (note_sz * 2 + 1);
+ bin2hex ((gdb_byte*)nhdr, bil->hex_build_id, note_sz);
+ xfree (pt_note);
+ return;
+ }
+ nhdr = (void*)((char *)nhdr + note_sz);
+ }
+ xfree (pt_note);
+ }
+ }
+ }
+ else
+ warning ("Reading build-id failed.");
+#undef HDR
+#undef SIZEOFHDR
+}
+
+
+/* Create list of build_id_list. */
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
+ ULONGEST inode, int read, int write, int exec,
+ int modified, const char *filename, void *data)
+{
+ if (inode != 0)
+ {
+ struct find_memory_region_callback_data *const p = data;
+ build_id_list_s bil;
+
+ bil.vaddr = vaddr;
+ bil.size = size;
+ bil.inode = inode;
+ bil.read = !(read == 0);
+ bil.write = !(write == 0);
+ bil.exec = !(write == 0);
+ bil.modified = !(write == 0);
+ bil.filename = filename;
+ bil.hex_build_id = NULL;
+
+ VEC_safe_push (build_id_list_s, p->list, &bil);
+ }
+
+ return 0;
+}
+
+/* Get build-id for the given L_LD. DATA must point to
+ already filled list of build_id_list elements.
+
+ Return build_id as stored in the list element corresponding
+ to L_LD.
+
+ NULL may be returned if build-id could not be fetched.
+
+ Returned string must not be freed explicitly.
+*/
+
+static const char *
+get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
+ struct find_memory_region_callback_data *const data)
+{
+ build_id_list_s *const bil
+ = bsearch (&l_ld, VEC_address (build_id_list_s, data->list),
+ VEC_length (build_id_list_s, data->list),
+ sizeof (build_id_list_s), compare_build_id_list_range);
+
+ if (bil == NULL)
+ return NULL;
+
+ if (bil->hex_build_id == NULL)
+ {
+ CORE_ADDR load_addr;
+ size_t len = VEC_length (build_id_list_s, data->list);
+
+ /* Must do linear search for the first mapping of this inode. */
+ build_id_list_s *const bil_min
+ = lfind (&bil->inode, VEC_address (build_id_list_s, data->list), &len,
+ sizeof (build_id_list_s), compare_build_id_list_inode);
+ gdb_assert (bil_min != NULL && "This should never happen.");
+ load_addr = bil_min->vaddr;
+ read_build_id (data, bil, load_addr, l_addr);
+ }
+
+ return bil->hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5655,6 +5916,8 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
struct process_info_private *const priv = current_process ()->private;
char filename[PATH_MAX];
int pid, is_elf64;
+ struct find_memory_region_callback_data data;
+ int build_id_list_p;
static const struct link_map_offsets lmo_32bit_offsets =
{
@@ -5690,6 +5953,19 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ data.is_elf64 = is_elf64;
+ data.list = NULL;
+ VEC_reserve (build_id_list_s, data.list, 16);
+ build_id_list_p
+ = linux_find_memory_regions_full (
+ lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback, &data, NULL) >= 0;
+
+ if (build_id_list_p)
+ qsort (VEC_address (build_id_list_s, data.list),
+ VEC_length (build_id_list_s, data.list),
+ sizeof (build_id_list_s), compare_build_id_list);
+
if (priv->r_debug == 0)
priv->r_debug = get_r_debug (pid, is_elf64);
@@ -5764,6 +6040,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ const char *hex_enc_build_id = NULL;
if (!header_done)
{
@@ -5772,21 +6049,29 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ if (build_id_list_p)
+ hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
+ while (allocated < (p - document + len + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
+ const ptrdiff_t document_len = p - document;
- document = xrealloc (document, 2 * allocated);
allocated *= 2;
+ document = xrealloc (document, allocated);
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<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, "/>");
free (name);
}
else if (lm_prev == 0)
@@ -5821,6 +6106,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
memcpy (readbuf, document + offset, len);
xfree (document);
+ free_build_id_list (data.list);
return len;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
2013-03-10 21:09 ` [draft patch 5/6] Move linux_find_memory_regions_full & co Jan Kratochvil
@ 2013-03-22 13:05 ` Aleksandar Ristovski
2013-03-22 13:34 ` Aleksandar Ristovski
2013-03-26 18:27 ` Jan Kratochvil
0 siblings, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:05 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1168 bytes --]
As per the subject...
ChangeLog:
* common/common-utils.c (read_alloc, read_stralloc): Move definitions
from target.c.
* common/common-utils.h (read_alloc_pread_ftype): New typedef.
(read_alloc): New declaration.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): New declaration.
* common/linux-maps.c (fcntl.h, unistd.h, target.h, gdb_assert.h,
ctype.h, string.h): Include.
(read_mapping): Move from linux-tdep.c.
(linux_find_memory_read_stralloc_1_pread): New function.
(linux_find_memory_read_stralloc_1): New function.
(linux_find_memory_read_stralloc): New function.
* common/linux-maps.h (read_mapping): New declaration.
(linux_find_memory_region_ftype): Moved typedef from linux-tdep.c.
(linux_find_memory_regions_full): New declaration.
* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to common/linux-maps.c.
(linux_find_memory_region_ftype): Moved typedef to common/linux-maps.h.
(linux_find_memory_regions_full): Moved definition to
common/linux-maps.c.
* target.c (read_alloc_pread_ftype): Moved typedef to
common/common-utils.h.
(read_alloc, read_stralloc): Moved definitions to
common/common-utils.c.
---
[-- Attachment #2: 0005-Move-linux_find_memory_regions_full-and-related-to-c.patch --]
[-- Type: text/x-patch, Size: 17923 bytes --]
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index c123ed7..36e267a 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -348,3 +348,95 @@ skip_spaces_const (const char *chp)
chp++;
return chp;
}
+
+LONGEST
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
+{
+ size_t buf_alloc, buf_pos;
+ gdb_byte *buf;
+ LONGEST n;
+ int target_errno;
+
+ /* Start by reading up to 4K at a time. The target will throttle
+ this number down if necessary. */
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
+ buf_pos = 0;
+ while (1)
+ {
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
+ {
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
+ else
+ *buf_p = buf;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
+ }
+
+ buf_pos += n;
+
+ /* If the buffer is filling up, expand it. */
+ if (buf_alloc < buf_pos * 2)
+ {
+ buf_alloc *= 2;
+ buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
+ }
+ }
+}
+
+char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
+{
+ char *buffer;
+ LONGEST i, transferred;
+
+ transferred = func (filename, (gdb_byte **) &buffer, 1);
+
+ if (transferred < 0)
+ return NULL;
+
+ if (transferred == 0)
+ return xstrdup ("");
+
+ buffer[transferred] = 0;
+
+ /* Check for embedded NUL bytes; but allow trailing NULs. */
+ for (i = strlen (buffer); i < transferred; i++)
+ if (buffer[i] != 0)
+ {
+ warning (_("target file %s "
+ "contained unexpected null characters"),
+ filename);
+ break;
+ }
+
+ return buffer;
+}
+
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 2c95d34..c7f8162 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -91,4 +91,15 @@ extern char *skip_spaces (char *inp);
extern const char *skip_spaces_const (const char *inp);
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
+ read_alloc_pread_ftype *pread_func, int padding,
+ void **memory_to_free_ptr);
+
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+extern char *read_stralloc (const char *filename,
+ read_stralloc_func_ftype *func);
+
#endif
diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c
index efb0875..a2566e1 100644
--- a/gdb/common/linux-maps.c
+++ b/gdb/common/linux-maps.c
@@ -18,8 +18,194 @@
#ifdef GDBSERVER
#include "server.h"
+#include <fcntl.h>
+#include <unistd.h>
#else
#include "defs.h"
+#include "target.h"
#endif
#include "linux-maps.h"
+#include "gdb_assert.h"
+#include <ctype.h>
+#include <string.h>
+
+/* 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);
+
+ p = skip_spaces_const (p);
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ p = skip_spaces_const (p);
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ p = skip_spaces_const (p);
+ *filename = p;
+}
+
+#ifdef GDBSERVER
+
+static int
+linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf,
+ int len, ULONGEST offset,
+ int *target_errno)
+{
+ int retval = pread (handle, read_buf, len, offset);
+
+ *target_errno = errno;
+ return retval;
+}
+
+static LONGEST
+linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p,
+ int padding)
+{
+ int fd;
+ LONGEST retval;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread,
+ padding, NULL);
+
+ close (fd);
+
+ return retval;
+}
+
+#endif /* GDBSERVER */
+
+static char *
+linux_find_memory_read_stralloc (const char *filename)
+{
+#ifndef GDBSERVER
+ return target_fileio_read_stralloc (filename);
+#else /* GDBSERVER */
+ return read_stralloc (filename, linux_find_memory_read_stralloc_1);
+#endif /* GDBSERVER */
+}
+
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
+
+int
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
+
+ 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. */
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
+ }
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
+ }
+
+ return -1;
+}
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
index da426e5..e989376 100644
--- a/gdb/common/linux-maps.h
+++ b/gdb/common/linux-maps.h
@@ -19,4 +19,29 @@
#ifndef COMMON_LINUX_MAPS_H
#define COMMON_LINUX_MAPS_H
+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);
+
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
+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);
+
+extern int
+ linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr);
+
#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index c48f4ec..4544e5f 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,44 +208,6 @@ 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);
-
- p = skip_spaces_const (p);
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- p = skip_spaces_const (p);
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- p = skip_spaces_const (p);
- *filename = p;
-}
-
/* Implement the "info proc" command. */
static void
@@ -661,115 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
-/* Callback function for linux_find_memory_regions_full. If it returns
- non-zero linux_find_memory_regions_full returns immediately with that
- value. */
-
-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 PID for a corefile. Call FUNC
- with FUNC_DATA for each such region. Return immediately with the
- value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
- be registered to be freed automatically if called FUNC throws an
- exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
- not used. Return -1 if error occurs, 0 if all memory regions have
- been processed or return the value from FUNC if FUNC returns
- non-zero. */
-
-static int
-linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
- void *func_data, void **memory_to_free_ptr)
-{
- char filename[100];
- char *data;
-
- xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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", (int) pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- char *line;
- int retval = 0;
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = data;
- }
-
- 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. */
- retval = func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, func_data);
- if (retval != 0)
- break;
- }
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (data == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (data);
- return retval;
- }
-
- return -1;
-}
-
/* A structure for passing information through
linux_find_memory_regions_full. */
diff --git a/gdb/target.c b/gdb/target.c
index 9f9423e..3daa7eb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3477,69 +3477,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
target_fileio_read_alloc; see the declaration of that function for more
information. */
-typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
- ULONGEST offset, int *target_errno);
-
-static LONGEST
-read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
- int padding, void **memory_to_free_ptr)
-{
- size_t buf_alloc, buf_pos;
- gdb_byte *buf;
- LONGEST n;
- int target_errno;
-
- /* Start by reading up to 4K at a time. The target will throttle
- this number down if necessary. */
- buf_alloc = 4096;
- buf = xmalloc (buf_alloc);
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = buf;
- }
- buf_pos = 0;
- while (1)
- {
- n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
- buf_pos, &target_errno);
- if (n <= 0)
- {
- if (n < 0 || (n == 0 && buf_pos == 0))
- {
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (buf == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (buf);
- }
- else
- *buf_p = buf;
-
- if (n < 0)
- {
- /* An error occurred. */
- return -1;
- }
- else
- {
- /* Read all there was. */
- return buf_pos;
- }
- }
-
- buf_pos += n;
-
- /* If the buffer is filling up, expand it. */
- if (buf_alloc < buf_pos * 2)
- {
- buf_alloc *= 2;
- buf = xrealloc (buf, buf_alloc);
- }
- }
-}
-
static LONGEST
target_fileio_read_alloc_1 (const char *filename,
gdb_byte **buf_p, int padding)
@@ -3558,6 +3495,10 @@ target_fileio_read_alloc_1 (const char *filename,
make_cleanup (free_current_contents, &memory_to_free);
retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
&memory_to_free);
+ if (retval >= 0)
+ /* Returned allocated memory is interesting for the caller. */
+ memory_to_free = NULL;
+
do_cleanups (close_cleanup);
return retval;
}
@@ -3578,39 +3519,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
- gdb_byte **buf_p, int padding);
-
-static char *
-read_stralloc (const char *filename, read_stralloc_func_ftype *func)
-{
- gdb_byte *buffer;
- char *bufstr;
- LONGEST i, transferred;
-
- transferred = func (filename, &buffer, 1);
-
- if (transferred < 0)
- return NULL;
-
- if (transferred == 0)
- return xstrdup ("");
-
- bufstr[transferred] = 0;
-
- /* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (bufstr); i < transferred; i++)
- if (bufstr[i] != 0)
- {
- warning (_("target file %s "
- "contained unexpected null characters"),
- filename);
- break;
- }
-
- return bufstr;
-}
-
char *
target_fileio_read_stralloc (const char *filename)
{
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 1/6] Move utility functions to common/
2013-03-22 13:13 ` [patch " Aleksandar Ristovski
@ 2013-03-22 13:05 ` Aleksandar Ristovski
2013-04-07 18:54 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:05 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1168 bytes --]
As per the subject...
ChangeLog:
* cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to
common/common-utils.c.
* cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to
common/common-utils.h.
* common/common-utils.c (ctype.h): Include.
(HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move
from utils.c.
(fromhex): Copy from remote.c.
(hex2bin): Move from remote.c.
(tohex): Copy from remote.c.
(bin2hex): Move from remote.c.
(skip_spaces, skip_spaces_const): Move from cli/cli-utils.c.
* common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved
from defs.h.
(strtoulst): Move decl from utils.h.
(hex2bin, bin2hex): Move decls from remote.h.
(skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h.
* defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to
common/common-utils.h
* remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c.
* remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h.
* utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int,
strtoulst): Move to common/common-utils.c.
* utils.h (strtoulst): Moved decl to common/common-utils.h.
Thanks,
Aleksandar
[-- Attachment #2: 0001-Move-utility-functions-to-common.patch --]
[-- Type: text/x-patch, Size: 12261 bytes --]
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index f74e6b1..60f7553 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -213,30 +213,6 @@ number_is_in_list (char *list, int number)
/* See documentation in cli-utils.h. */
-char *
-skip_spaces (char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* A const-correct version of the above. */
-
-const char *
-skip_spaces_const (const char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* See documentation in cli-utils.h. */
-
const char *
skip_to_space_const (const char *chp)
{
diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h
index 152fb89..2a8850d 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -89,15 +89,6 @@ extern int get_number_or_range (struct get_number_or_range_state *state);
extern int number_is_in_list (char *list, int number);
-/* Skip leading whitespace characters in INP, returning an updated
- pointer. If INP is NULL, return NULL. */
-
-extern char *skip_spaces (char *inp);
-
-/* A const-correct version of the above. */
-
-extern const char *skip_spaces_const (const char *inp);
-
/* Skip leading non-whitespace characters in INP, returning an updated
pointer. If INP is NULL, return NULL. */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 4204abf..5e96692 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
/* The xmalloc() (libiberty.h) family of memory management routines.
@@ -161,3 +162,189 @@ 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. */
+
+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;
+}
+
+/* See documentation in cli-utils.h. */
+
+char *
+skip_spaces (char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
+
+/* A const-correct version of the above. */
+
+const char *
+skip_spaces_const (const char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 9b659d8..ee7870e 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -25,6 +25,25 @@
#include <stddef.h>
#include <stdarg.h>
+/* Static target-system-dependent parameters for GDB. */
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) then use it to set
+ the number of bits in a host char. If not, use the same size
+ as the target. */
+
+#if defined (CHAR_BIT)
+#define HOST_CHAR_BIT CHAR_BIT
+#else
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif
+
extern void malloc_failure (long size) ATTRIBUTE_NORETURN;
extern void internal_error (const char *file, int line, const char *, ...)
ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 4);
@@ -53,4 +72,19 @@ int xsnprintf (char *str, size_t size, const char *format, ...)
char *savestring (const char *ptr, size_t len);
+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+extern int hex2bin (const char *hex, gdb_byte *bin, int count);
+
+extern int bin2hex (const gdb_byte *bin, char *hex, int count);
+
+/* Skip leading whitespace characters in INP, returning an updated
+ pointer. If INP is NULL, return NULL. */
+
+extern char *skip_spaces (char *inp);
+
+/* A const-correct version of the above. */
+
+extern const char *skip_spaces_const (const char *inp);
+
#endif
diff --git a/gdb/defs.h b/gdb/defs.h
index d8a1adb..ec7e4f3 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -648,25 +648,6 @@ extern void *alloca ();
enum { MAX_REGISTER_SIZE = 64 };
-/* Static target-system-dependent parameters for GDB. */
-
-/* Number of bits in a char or unsigned char for the target machine.
- Just like CHAR_BIT in <limits.h> but describes the target machine. */
-#if !defined (TARGET_CHAR_BIT)
-#define TARGET_CHAR_BIT 8
-#endif
-
-/* If we picked up a copy of CHAR_BIT from a configuration file
- (which may get it by including <limits.h>) then use it to set
- the number of bits in a host char. If not, use the same size
- as the target. */
-
-#if defined (CHAR_BIT)
-#define HOST_CHAR_BIT CHAR_BIT
-#else
-#define HOST_CHAR_BIT TARGET_CHAR_BIT
-#endif
-
/* In findvar.c. */
extern LONGEST extract_signed_integer (const gdb_byte *, int,
diff --git a/gdb/remote.c b/gdb/remote.c
index 21d86f7..99c9182 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4572,25 +4572,6 @@ fromhex (int a)
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
@@ -4602,23 +4583,6 @@ tohex (int nib)
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/remote.h b/gdb/remote.h
index b95370c..d49b427 100644
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -39,10 +39,6 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever);
extern int putpkt (char *buf);
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
extern void async_remote_interrupt_twice (void *arg);
diff --git a/gdb/utils.c b/gdb/utils.c
index 4c2f08c..4d2a358 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3318,105 +3318,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
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 2/6] Merge multiple hex conversions
2013-03-10 21:08 ` [draft patch 2/6] Merge multiple hex conversions Jan Kratochvil
@ 2013-03-22 13:05 ` Aleksandar Ristovski
2013-04-05 16:07 ` Aleksandar Ristovski
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:05 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 827 bytes --]
As per the subject...
(tohex): Make externally linkable.
* common/common-utils.h (fromhex, tohex): New declaration.
* gdbserver/gdbreplay.c (tohex): Rename to 'fromhex'.
(logchar): Use fromhex.
* gdbserver/remote-utils.c (fromhex, unhexify): Remove.
(tohex, hexify): Remove.
(look_up_one_symbol, monitor_output): Use bin2hex instead of hexify.
* gdbserver/server.c (handle_query): Use bin2hex instead of hexify.
(handle_v_run): Ditto.
* gdbserver/server.h (unhexify, hexify): Remove declarations.
* gdbserver/tracepoint.c (cmd_qtdpsrc, cmd_qtdv): Use hex2bin
instead of unhexify.
(cmd_qtstatus): Use bin2hex instead of hexify.
(cmd_qtnotes): Use hex2bin instead of unhexify.
* monitor.c (fromhex): Remove definition.
* remote.c (tohex, fromhex): Remove fwd declarations, remove
definitions.
---
Aleksandar
[-- Attachment #2: 0002-Merge-multiple-hex-conversions.patch --]
[-- Type: text/x-patch, Size: 11952 bytes --]
From 3e9d3b829ffc14fae8225977fa6e19dfcf38bce0 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Tue, 12 Mar 2013 14:00:59 -0400
Subject: [PATCH 2/6] Merge multiple hex conversions
* common/common-utils.c (fromhex): Make externally linkable.
(tohex): Make externally linkable.
* common/common-utils.h (fromhex, tohex): New declaration.
* gdbserver/gdbreplay.c (tohex): Rename to 'fromhex'.
(logchar): Use fromhex.
* gdbserver/remote-utils.c (fromhex, unhexify): Remove.
(tohex, hexify): Remove.
(look_up_one_symbol, monitor_output): Use bin2hex instead of hexify.
* gdbserver/server.c (handle_query): Use bin2hex instead of hexify.
(handle_v_run): Ditto.
* gdbserver/server.h (unhexify, hexify): Remove declarations.
* gdbserver/tracepoint.c (cmd_qtdpsrc, cmd_qtdv): Use hex2bin
instead of unhexify.
(cmd_qtstatus): Use bin2hex instead of hexify.
(cmd_qtnotes): Use hex2bin instead of unhexify.
* monitor.c (fromhex): Remove definition.
* remote.c (tohex, fromhex): Remove fwd declarations, remove
definitions.
---
gdb/common/common-utils.c | 6 ++--
gdb/common/common-utils.h | 4 +++
gdb/gdbserver/gdbreplay.c | 6 ++--
gdb/gdbserver/remote-utils.c | 67 ++----------------------------------------
gdb/gdbserver/server.c | 5 ++--
gdb/gdbserver/server.h | 2 --
gdb/gdbserver/tracepoint.c | 16 +++++-----
gdb/monitor.c | 15 ----------
gdb/remote.c | 30 -------------------
9 files changed, 24 insertions(+), 127 deletions(-)
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 5e96692..c123ed7 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -264,7 +264,7 @@ strtoulst (const char *num, const char **trailer, int base)
/* Convert hex digit A to a number. */
-static int
+int
fromhex (int a)
{
if (a >= '0' && a <= '9')
@@ -274,7 +274,7 @@ fromhex (int a)
else if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
else
- error (_("Reply contains invalid hex digit %d"), a);
+ error (_("Invalid hex digit %d"), a);
}
int
@@ -298,7 +298,7 @@ hex2bin (const char *hex, gdb_byte *bin, int count)
/* Convert number NIB to a hex digit. */
-static int
+int
tohex (int nib)
{
if (nib < 10)
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index ee7870e..2c95d34 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -74,6 +74,10 @@ char *savestring (const char *ptr, size_t len);
ULONGEST strtoulst (const char *num, const char **trailer, int base);
+extern int fromhex (int a);
+
+extern int tohex (int nib);
+
extern int hex2bin (const char *hex, gdb_byte *bin, int count);
extern int bin2hex (const gdb_byte *bin, char *hex, int count);
diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c
index 0aa52d8..d0ff8c4 100644
--- a/gdb/gdbserver/gdbreplay.c
+++ b/gdb/gdbserver/gdbreplay.c
@@ -273,7 +273,7 @@ remote_open (char *name)
}
static int
-tohex (int ch)
+fromhex (int ch)
{
if (ch >= '0' && ch <= '9')
{
@@ -336,11 +336,11 @@ logchar (FILE *fp)
ch2 = fgetc (fp);
fputc (ch2, stdout);
fflush (stdout);
- ch = tohex (ch2) << 4;
+ ch = fromhex (ch2) << 4;
ch2 = fgetc (fp);
fputc (ch2, stdout);
fflush (stdout);
- ch |= tohex (ch2);
+ ch |= fromhex (ch2);
break;
default:
/* Treat any other char as just itself */
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 42c6a54..6ff491e 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -416,20 +416,6 @@ remote_close (void)
reset_readchar ();
}
-/* 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";
@@ -457,25 +443,6 @@ ishex (int ch, int *val)
#ifndef IN_PROCESS_AGENT
-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;
-}
-
void
decode_address (CORE_ADDR *addrp, const char *start, int len)
{
@@ -511,37 +478,8 @@ 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;
-}
-
/* Convert BUFFER, binary data at least LEN bytes long, into escaped
binary data in OUT_BUF. Set *OUT_LEN to the length of the data
encoded in OUT_BUF, and return the number of bytes in OUT_BUF
@@ -1608,7 +1546,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
/* Send the request. */
strcpy (own_buf, "qSymbol:");
- hexify (own_buf + strlen ("qSymbol:"), name, strlen (name));
+ bin2hex ((const gdb_byte *) name, own_buf + strlen ("qSymbol:"),
+ strlen (name));
if (putpkt (own_buf) < 0)
return -1;
@@ -1770,7 +1709,7 @@ monitor_output (const char *msg)
char *buf = xmalloc (strlen (msg) * 2 + 2);
buf[0] = 'O';
- hexify (buf + 1, msg, 0);
+ bin2hex ((const gdb_byte *) msg, buf + 1, 0);
putpkt (buf);
free (buf);
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6bb36d8..8b586dd 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1920,7 +1920,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
return;
}
- if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2)
+ if ((len % 2) != 0
+ || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2)
{
write_enn (own_buf);
free (mon);
@@ -2214,7 +2215,7 @@ handle_v_run (char *own_buf)
{
/* FIXME: Fail request if out of memory instead of dying. */
new_argv[i] = xmalloc (1 + (next_p - p) / 2);
- unhexify (new_argv[i], p, (next_p - p) / 2);
+ hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
new_argv[i][(next_p - p) / 2] = '\0';
}
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 139cd49..5e16088 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -322,8 +322,6 @@ int decode_search_memory_packet (const char *buf, int packet_len,
gdb_byte *pattern,
unsigned int *pattern_lenp);
-int unhexify (char *bin, const char *hex, int count);
-int hexify (char *hex, const char *bin, int count);
int remote_escape_output (const gdb_byte *buffer, int len,
gdb_byte *out_buf, int *out_len,
int out_maxlen);
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 419765b..f48e3b6 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -2679,7 +2679,7 @@ cmd_qtdpsrc (char *own_buf)
packet = unpack_varlen_hex (packet, &slen);
++packet; /* skip a colon */
src = xmalloc (slen + 1);
- nbytes = unhexify (src, packet, strlen (packet) / 2);
+ nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2);
src[nbytes] = '\0';
newlast = xmalloc (sizeof (struct source_string));
@@ -2721,7 +2721,7 @@ cmd_qtdv (char *own_buf)
nbytes = strlen (packet) / 2;
varname = xmalloc (nbytes + 1);
- nbytes = unhexify (varname, packet, nbytes);
+ nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes);
varname[nbytes] = '\0';
tsv = create_trace_state_variable (num, 1);
@@ -3594,17 +3594,17 @@ cmd_qtstatus (char *packet)
str = (tracing_user_name ? tracing_user_name : "");
slen = strlen (str);
buf1 = (char *) alloca (slen * 2 + 1);
- hexify (buf1, str, slen);
+ bin2hex ((const gdb_byte *) str, buf1, slen);
str = (tracing_notes ? tracing_notes : "");
slen = strlen (str);
buf2 = (char *) alloca (slen * 2 + 1);
- hexify (buf2, str, slen);
+ bin2hex ((const gdb_byte *) str, buf2, slen);
str = (tracing_stop_note ? tracing_stop_note : "");
slen = strlen (str);
buf3 = (char *) alloca (slen * 2 + 1);
- hexify (buf3, str, slen);
+ bin2hex ((const gdb_byte *) str, buf3, slen);
trace_debug ("Returning trace status as %d, stop reason %s",
tracing, tracing_stop_reason);
@@ -4078,7 +4078,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
user = xmalloc (nbytes + 1);
- nbytes = unhexify (user, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) user, nbytes);
user[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("User is '%s'", user);
@@ -4092,7 +4092,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
notes = xmalloc (nbytes + 1);
- nbytes = unhexify (notes, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes);
notes[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("Notes is '%s'", notes);
@@ -4106,7 +4106,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
stopnote = xmalloc (nbytes + 1);
- nbytes = unhexify (stopnote, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes);
stopnote[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("tstop note is '%s'", stopnote);
diff --git a/gdb/monitor.c b/gdb/monitor.c
index e6a9766..8ffa594 100644
--- a/gdb/monitor.c
+++ b/gdb/monitor.c
@@ -226,21 +226,6 @@ monitor_error (char *function, char *message,
message, safe_string);
}
-/* 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 (_("Invalid hex digit %d"), a);
-}
-
/* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses
This function exists to get around the problem that many host platforms
diff --git a/gdb/remote.c b/gdb/remote.c
index 99c9182..08991fc 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -124,8 +124,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);
@@ -182,8 +180,6 @@ static void remote_find_new_threads (void);
static void record_currthread (ptid_t currthread);
-static int fromhex (int a);
-
static int putpkt_binary (char *buf, int cnt);
static void check_binary_download (CORE_ADDR addr);
@@ -4557,32 +4553,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);
-}
-
-/* Convert number NIB to a hex digit. */
-
-static int
-tohex (int nib)
-{
- if (nib < 10)
- return '0' + nib;
- else
- return 'a' + nib - 10;
-}
-
\f
/* Check for the availability of vCont. This function should also check
the response. */
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 3/6] Create empty common/linux-maps.[ch]
2013-03-22 14:54 ` [patch " Aleksandar Ristovski
@ 2013-03-22 13:06 ` Aleksandar Ristovski
2013-04-05 13:25 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:06 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 411 bytes --]
As per the subject...
* Makefile.in (HFILES_NO_SRCDIR); Add common/linux-maps.h.
(linux-maps.o): New.
* common/linux-maps.c: New file.
* common/linux-maps.h: New file.
* config/i386/linux.mh (NATDEPFILES): Add linux-maps.o.
* config/i386/linux64.m (NATDEPFILES): Add linux-maps.o.
* gdbserver/Makefile.in (linux-maps.o): New.
* gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o.
---
Aleksandar
[-- Attachment #2: 0003-Create-empty-common-linux-maps.-ch.patch --]
[-- Type: text/x-patch, Size: 13664 bytes --]
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9bab01c..bc51ac3 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -772,7 +772,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 \
@@ -1948,6 +1948,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/linux-maps.c b/gdb/common/linux-maps.c
new file mode 100644
index 0000000..efb0875
--- /dev/null
+++ b/gdb/common/linux-maps.c
@@ -0,0 +1,25 @@
+/* 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"
+#else
+#include "defs.h"
+#endif
+
+#include "linux-maps.h"
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
new file mode 100644
index 0000000..da426e5
--- /dev/null
+++ b/gdb/common/linux-maps.h
@@ -0,0 +1,22 @@
+/* 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
+
+#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 7c64e83..e34f1dc 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 \
linux-btrace.o
NAT_CDEPS = $(srcdir)/proc-service.list
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index 8d782c1..78ecf30 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 linux-btrace.o
NAT_FILE= config/nm-linux.h
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 08db2cc..37d11a2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -512,6 +512,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 271a0fe..4de099b 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 linux-btrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -147,12 +159,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
@@ -162,7 +178,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
@@ -173,7 +191,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
@@ -183,7 +203,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"
@@ -216,7 +239,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"
@@ -262,7 +287,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"
@@ -283,14 +310,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
@@ -307,15 +338,20 @@ 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="${srv_tgtobj} linux-ptrace.o linux-btrace.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-x86-low.o i386-low.o"
+ srv_tgtobj="${srv_tgtobj} i387-fp.o linux-procfs.o"
+ srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+ srv_tgtobj="${srv_tgtobj} linux-btrace.o"
srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
srv_linux_usrregs=yes # This is for i386 progs.
srv_linux_regsets=yes
@@ -334,13 +370,18 @@ 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_regobj="${srv_regobj} reg-tilegx32.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
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 1/6] Move utility functions to common/
2013-03-10 21:08 ` [draft patch 1/6] Move utility functions to common/ Jan Kratochvil
@ 2013-03-22 13:13 ` Aleksandar Ristovski
2013-03-22 13:05 ` Aleksandar Ristovski
2013-04-07 18:54 ` Aleksandar Ristovski
0 siblings, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:13 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1168 bytes --]
As per the subject...
ChangeLog:
* cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to
common/common-utils.c.
* cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to
common/common-utils.h.
* common/common-utils.c (ctype.h): Include.
(HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move
from utils.c.
(fromhex): Copy from remote.c.
(hex2bin): Move from remote.c.
(tohex): Copy from remote.c.
(bin2hex): Move from remote.c.
(skip_spaces, skip_spaces_const): Move from cli/cli-utils.c.
* common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved
from defs.h.
(strtoulst): Move decl from utils.h.
(hex2bin, bin2hex): Move decls from remote.h.
(skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h.
* defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to
common/common-utils.h
* remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c.
* remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h.
* utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int,
strtoulst): Move to common/common-utils.c.
* utils.h (strtoulst): Moved decl to common/common-utils.h.
Thanks,
Aleksandar
[-- Attachment #2: 0001-Move-utility-functions-to-common.patch --]
[-- Type: text/x-patch, Size: 12261 bytes --]
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index f74e6b1..60f7553 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -213,30 +213,6 @@ number_is_in_list (char *list, int number)
/* See documentation in cli-utils.h. */
-char *
-skip_spaces (char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* A const-correct version of the above. */
-
-const char *
-skip_spaces_const (const char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* See documentation in cli-utils.h. */
-
const char *
skip_to_space_const (const char *chp)
{
diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h
index 152fb89..2a8850d 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -89,15 +89,6 @@ extern int get_number_or_range (struct get_number_or_range_state *state);
extern int number_is_in_list (char *list, int number);
-/* Skip leading whitespace characters in INP, returning an updated
- pointer. If INP is NULL, return NULL. */
-
-extern char *skip_spaces (char *inp);
-
-/* A const-correct version of the above. */
-
-extern const char *skip_spaces_const (const char *inp);
-
/* Skip leading non-whitespace characters in INP, returning an updated
pointer. If INP is NULL, return NULL. */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 4204abf..5e96692 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
/* The xmalloc() (libiberty.h) family of memory management routines.
@@ -161,3 +162,189 @@ 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. */
+
+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;
+}
+
+/* See documentation in cli-utils.h. */
+
+char *
+skip_spaces (char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
+
+/* A const-correct version of the above. */
+
+const char *
+skip_spaces_const (const char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 9b659d8..ee7870e 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -25,6 +25,25 @@
#include <stddef.h>
#include <stdarg.h>
+/* Static target-system-dependent parameters for GDB. */
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) then use it to set
+ the number of bits in a host char. If not, use the same size
+ as the target. */
+
+#if defined (CHAR_BIT)
+#define HOST_CHAR_BIT CHAR_BIT
+#else
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif
+
extern void malloc_failure (long size) ATTRIBUTE_NORETURN;
extern void internal_error (const char *file, int line, const char *, ...)
ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 4);
@@ -53,4 +72,19 @@ int xsnprintf (char *str, size_t size, const char *format, ...)
char *savestring (const char *ptr, size_t len);
+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+extern int hex2bin (const char *hex, gdb_byte *bin, int count);
+
+extern int bin2hex (const gdb_byte *bin, char *hex, int count);
+
+/* Skip leading whitespace characters in INP, returning an updated
+ pointer. If INP is NULL, return NULL. */
+
+extern char *skip_spaces (char *inp);
+
+/* A const-correct version of the above. */
+
+extern const char *skip_spaces_const (const char *inp);
+
#endif
diff --git a/gdb/defs.h b/gdb/defs.h
index d8a1adb..ec7e4f3 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -648,25 +648,6 @@ extern void *alloca ();
enum { MAX_REGISTER_SIZE = 64 };
-/* Static target-system-dependent parameters for GDB. */
-
-/* Number of bits in a char or unsigned char for the target machine.
- Just like CHAR_BIT in <limits.h> but describes the target machine. */
-#if !defined (TARGET_CHAR_BIT)
-#define TARGET_CHAR_BIT 8
-#endif
-
-/* If we picked up a copy of CHAR_BIT from a configuration file
- (which may get it by including <limits.h>) then use it to set
- the number of bits in a host char. If not, use the same size
- as the target. */
-
-#if defined (CHAR_BIT)
-#define HOST_CHAR_BIT CHAR_BIT
-#else
-#define HOST_CHAR_BIT TARGET_CHAR_BIT
-#endif
-
/* In findvar.c. */
extern LONGEST extract_signed_integer (const gdb_byte *, int,
diff --git a/gdb/remote.c b/gdb/remote.c
index 21d86f7..99c9182 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4572,25 +4572,6 @@ fromhex (int a)
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
@@ -4602,23 +4583,6 @@ tohex (int nib)
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/remote.h b/gdb/remote.h
index b95370c..d49b427 100644
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -39,10 +39,6 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever);
extern int putpkt (char *buf);
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
extern void async_remote_interrupt_twice (void *arg);
diff --git a/gdb/utils.c b/gdb/utils.c
index 4c2f08c..4d2a358 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3318,105 +3318,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
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
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 ` Aleksandar Ristovski
2013-03-22 13:54 ` Aleksandar Ristovski
2013-03-26 18:11 ` Jan Kratochvil
0 siblings, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:34 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 967 bytes --]
As per the subject...
ChangeLog:
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
Aleksandar
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-and-related-f.patch --]
[-- Type: text/x-patch, Size: 10640 bytes --]
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index a961d7b..9f9423e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3460,55 +3460,73 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
- {
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
- xfree (buf);
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
else
*buf_p = buf;
- return buf_pos;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3519,11 +3537,31 @@ target_fileio_read_alloc_1 (const char *filename,
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
}
-
- QUIT;
}
}
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ do_cleanups (close_cleanup);
+ return retval;
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and return
the size of the transferred data. See the declaration in "target.h"
function for more information about the return value. */
@@ -3540,15 +3578,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
gdb_byte *buffer;
char *bufstr;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
- bufstr = (char *) buffer;
+ transferred = func (filename, &buffer, 1);
if (transferred < 0)
return NULL;
@@ -3571,6 +3611,11 @@ target_fileio_read_stralloc (const char *filename)
return bufstr;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
2013-03-22 13:05 ` [patch " Aleksandar Ristovski
@ 2013-03-22 13:34 ` Aleksandar Ristovski
2013-03-26 18:27 ` Jan Kratochvil
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:34 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1168 bytes --]
As per the subject...
ChangeLog:
* common/common-utils.c (read_alloc, read_stralloc): Move definitions
from target.c.
* common/common-utils.h (read_alloc_pread_ftype): New typedef.
(read_alloc): New declaration.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): New declaration.
* common/linux-maps.c (fcntl.h, unistd.h, target.h, gdb_assert.h,
ctype.h, string.h): Include.
(read_mapping): Move from linux-tdep.c.
(linux_find_memory_read_stralloc_1_pread): New function.
(linux_find_memory_read_stralloc_1): New function.
(linux_find_memory_read_stralloc): New function.
* common/linux-maps.h (read_mapping): New declaration.
(linux_find_memory_region_ftype): Moved typedef from linux-tdep.c.
(linux_find_memory_regions_full): New declaration.
* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to common/linux-maps.c.
(linux_find_memory_region_ftype): Moved typedef to common/linux-maps.h.
(linux_find_memory_regions_full): Moved definition to
common/linux-maps.c.
* target.c (read_alloc_pread_ftype): Moved typedef to
common/common-utils.h.
(read_alloc, read_stralloc): Moved definitions to
common/common-utils.c.
---
[-- Attachment #2: 0005-Move-linux_find_memory_regions_full-and-related-to-c.patch --]
[-- Type: text/x-patch, Size: 17923 bytes --]
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index c123ed7..36e267a 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -348,3 +348,95 @@ skip_spaces_const (const char *chp)
chp++;
return chp;
}
+
+LONGEST
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
+{
+ size_t buf_alloc, buf_pos;
+ gdb_byte *buf;
+ LONGEST n;
+ int target_errno;
+
+ /* Start by reading up to 4K at a time. The target will throttle
+ this number down if necessary. */
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
+ buf_pos = 0;
+ while (1)
+ {
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
+ {
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
+ else
+ *buf_p = buf;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
+ }
+
+ buf_pos += n;
+
+ /* If the buffer is filling up, expand it. */
+ if (buf_alloc < buf_pos * 2)
+ {
+ buf_alloc *= 2;
+ buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
+ }
+ }
+}
+
+char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
+{
+ char *buffer;
+ LONGEST i, transferred;
+
+ transferred = func (filename, (gdb_byte **) &buffer, 1);
+
+ if (transferred < 0)
+ return NULL;
+
+ if (transferred == 0)
+ return xstrdup ("");
+
+ buffer[transferred] = 0;
+
+ /* Check for embedded NUL bytes; but allow trailing NULs. */
+ for (i = strlen (buffer); i < transferred; i++)
+ if (buffer[i] != 0)
+ {
+ warning (_("target file %s "
+ "contained unexpected null characters"),
+ filename);
+ break;
+ }
+
+ return buffer;
+}
+
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 2c95d34..c7f8162 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -91,4 +91,15 @@ extern char *skip_spaces (char *inp);
extern const char *skip_spaces_const (const char *inp);
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
+ read_alloc_pread_ftype *pread_func, int padding,
+ void **memory_to_free_ptr);
+
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+extern char *read_stralloc (const char *filename,
+ read_stralloc_func_ftype *func);
+
#endif
diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c
index efb0875..a2566e1 100644
--- a/gdb/common/linux-maps.c
+++ b/gdb/common/linux-maps.c
@@ -18,8 +18,194 @@
#ifdef GDBSERVER
#include "server.h"
+#include <fcntl.h>
+#include <unistd.h>
#else
#include "defs.h"
+#include "target.h"
#endif
#include "linux-maps.h"
+#include "gdb_assert.h"
+#include <ctype.h>
+#include <string.h>
+
+/* 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);
+
+ p = skip_spaces_const (p);
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ p = skip_spaces_const (p);
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ p = skip_spaces_const (p);
+ *filename = p;
+}
+
+#ifdef GDBSERVER
+
+static int
+linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf,
+ int len, ULONGEST offset,
+ int *target_errno)
+{
+ int retval = pread (handle, read_buf, len, offset);
+
+ *target_errno = errno;
+ return retval;
+}
+
+static LONGEST
+linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p,
+ int padding)
+{
+ int fd;
+ LONGEST retval;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread,
+ padding, NULL);
+
+ close (fd);
+
+ return retval;
+}
+
+#endif /* GDBSERVER */
+
+static char *
+linux_find_memory_read_stralloc (const char *filename)
+{
+#ifndef GDBSERVER
+ return target_fileio_read_stralloc (filename);
+#else /* GDBSERVER */
+ return read_stralloc (filename, linux_find_memory_read_stralloc_1);
+#endif /* GDBSERVER */
+}
+
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
+
+int
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
+
+ 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. */
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
+ }
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
+ }
+
+ return -1;
+}
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
index da426e5..e989376 100644
--- a/gdb/common/linux-maps.h
+++ b/gdb/common/linux-maps.h
@@ -19,4 +19,29 @@
#ifndef COMMON_LINUX_MAPS_H
#define COMMON_LINUX_MAPS_H
+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);
+
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
+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);
+
+extern int
+ linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr);
+
#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index c48f4ec..4544e5f 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,44 +208,6 @@ 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);
-
- p = skip_spaces_const (p);
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- p = skip_spaces_const (p);
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- p = skip_spaces_const (p);
- *filename = p;
-}
-
/* Implement the "info proc" command. */
static void
@@ -661,115 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
-/* Callback function for linux_find_memory_regions_full. If it returns
- non-zero linux_find_memory_regions_full returns immediately with that
- value. */
-
-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 PID for a corefile. Call FUNC
- with FUNC_DATA for each such region. Return immediately with the
- value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
- be registered to be freed automatically if called FUNC throws an
- exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
- not used. Return -1 if error occurs, 0 if all memory regions have
- been processed or return the value from FUNC if FUNC returns
- non-zero. */
-
-static int
-linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
- void *func_data, void **memory_to_free_ptr)
-{
- char filename[100];
- char *data;
-
- xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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", (int) pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- char *line;
- int retval = 0;
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = data;
- }
-
- 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. */
- retval = func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, func_data);
- if (retval != 0)
- break;
- }
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (data == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (data);
- return retval;
- }
-
- return -1;
-}
-
/* A structure for passing information through
linux_find_memory_regions_full. */
diff --git a/gdb/target.c b/gdb/target.c
index 9f9423e..3daa7eb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3477,69 +3477,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
target_fileio_read_alloc; see the declaration of that function for more
information. */
-typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
- ULONGEST offset, int *target_errno);
-
-static LONGEST
-read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
- int padding, void **memory_to_free_ptr)
-{
- size_t buf_alloc, buf_pos;
- gdb_byte *buf;
- LONGEST n;
- int target_errno;
-
- /* Start by reading up to 4K at a time. The target will throttle
- this number down if necessary. */
- buf_alloc = 4096;
- buf = xmalloc (buf_alloc);
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = buf;
- }
- buf_pos = 0;
- while (1)
- {
- n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
- buf_pos, &target_errno);
- if (n <= 0)
- {
- if (n < 0 || (n == 0 && buf_pos == 0))
- {
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (buf == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (buf);
- }
- else
- *buf_p = buf;
-
- if (n < 0)
- {
- /* An error occurred. */
- return -1;
- }
- else
- {
- /* Read all there was. */
- return buf_pos;
- }
- }
-
- buf_pos += n;
-
- /* If the buffer is filling up, expand it. */
- if (buf_alloc < buf_pos * 2)
- {
- buf_alloc *= 2;
- buf = xrealloc (buf, buf_alloc);
- }
- }
-}
-
static LONGEST
target_fileio_read_alloc_1 (const char *filename,
gdb_byte **buf_p, int padding)
@@ -3558,6 +3495,10 @@ target_fileio_read_alloc_1 (const char *filename,
make_cleanup (free_current_contents, &memory_to_free);
retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
&memory_to_free);
+ if (retval >= 0)
+ /* Returned allocated memory is interesting for the caller. */
+ memory_to_free = NULL;
+
do_cleanups (close_cleanup);
return retval;
}
@@ -3578,39 +3519,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
- gdb_byte **buf_p, int padding);
-
-static char *
-read_stralloc (const char *filename, read_stralloc_func_ftype *func)
-{
- gdb_byte *buffer;
- char *bufstr;
- LONGEST i, transferred;
-
- transferred = func (filename, &buffer, 1);
-
- if (transferred < 0)
- return NULL;
-
- if (transferred == 0)
- return xstrdup ("");
-
- bufstr[transferred] = 0;
-
- /* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (bufstr); i < transferred; i++)
- if (bufstr[i] != 0)
- {
- warning (_("target file %s "
- "contained unexpected null characters"),
- filename);
- break;
- }
-
- return bufstr;
-}
-
char *
target_fileio_read_stralloc (const char *filename)
{
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-03-22 13:34 ` [patch " Aleksandar Ristovski
@ 2013-03-22 13:54 ` Aleksandar Ristovski
2013-03-26 18:11 ` Jan Kratochvil
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 13:54 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 967 bytes --]
As per the subject...
ChangeLog:
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
Aleksandar
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-and-related-f.patch --]
[-- Type: text/x-patch, Size: 10640 bytes --]
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index a961d7b..9f9423e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3460,55 +3460,73 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
- {
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
- xfree (buf);
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
else
*buf_p = buf;
- return buf_pos;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3519,11 +3537,31 @@ target_fileio_read_alloc_1 (const char *filename,
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
}
-
- QUIT;
}
}
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ do_cleanups (close_cleanup);
+ return retval;
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and return
the size of the transferred data. See the declaration in "target.h"
function for more information about the return value. */
@@ -3540,15 +3578,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
gdb_byte *buffer;
char *bufstr;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
- bufstr = (char *) buffer;
+ transferred = func (filename, &buffer, 1);
if (transferred < 0)
return NULL;
@@ -3571,6 +3611,11 @@ target_fileio_read_stralloc (const char *filename)
return bufstr;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 3/6] Create empty common/linux-maps.[ch]
2013-03-10 21:08 ` [draft patch 3/6] Create empty common/linux-maps.[ch] Jan Kratochvil
@ 2013-03-22 14:54 ` Aleksandar Ristovski
2013-03-22 13:06 ` Aleksandar Ristovski
2013-04-05 13:25 ` Aleksandar Ristovski
0 siblings, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 14:54 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 411 bytes --]
As per the subject...
* Makefile.in (HFILES_NO_SRCDIR); Add common/linux-maps.h.
(linux-maps.o): New.
* common/linux-maps.c: New file.
* common/linux-maps.h: New file.
* config/i386/linux.mh (NATDEPFILES): Add linux-maps.o.
* config/i386/linux64.m (NATDEPFILES): Add linux-maps.o.
* gdbserver/Makefile.in (linux-maps.o): New.
* gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o.
---
Aleksandar
[-- Attachment #2: 0003-Create-empty-common-linux-maps.-ch.patch --]
[-- Type: text/x-patch, Size: 13664 bytes --]
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9bab01c..bc51ac3 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -772,7 +772,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 \
@@ -1948,6 +1948,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/linux-maps.c b/gdb/common/linux-maps.c
new file mode 100644
index 0000000..efb0875
--- /dev/null
+++ b/gdb/common/linux-maps.c
@@ -0,0 +1,25 @@
+/* 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"
+#else
+#include "defs.h"
+#endif
+
+#include "linux-maps.h"
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
new file mode 100644
index 0000000..da426e5
--- /dev/null
+++ b/gdb/common/linux-maps.h
@@ -0,0 +1,22 @@
+/* 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
+
+#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 7c64e83..e34f1dc 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 \
linux-btrace.o
NAT_CDEPS = $(srcdir)/proc-service.list
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index 8d782c1..78ecf30 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 linux-btrace.o
NAT_FILE= config/nm-linux.h
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 08db2cc..37d11a2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -512,6 +512,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 271a0fe..4de099b 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 linux-btrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -147,12 +159,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
@@ -162,7 +178,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
@@ -173,7 +191,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
@@ -183,7 +203,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"
@@ -216,7 +239,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"
@@ -262,7 +287,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"
@@ -283,14 +310,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
@@ -307,15 +338,20 @@ 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="${srv_tgtobj} linux-ptrace.o linux-btrace.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-x86-low.o i386-low.o"
+ srv_tgtobj="${srv_tgtobj} i387-fp.o linux-procfs.o"
+ srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+ srv_tgtobj="${srv_tgtobj} linux-btrace.o"
srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
srv_linux_usrregs=yes # This is for i386 progs.
srv_linux_regsets=yes
@@ -334,13 +370,18 @@ 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_regobj="${srv_regobj} reg-tilegx32.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
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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
2 siblings, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-22 15:19 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 754 bytes --]
This is the final patch that does actual addition of build-id attribute
to qxfer_libraries.
* doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
'build-id' in description, example, new attribute in dtd.
* linux-low.c (linux-maps.h, search.h): Include.
(struct build_id_list): New structure.
(build_id_list_s): New typedef, new vector type def.
(free_build_id_list, compare_build_id_list,
compare_build_id_list_range, compare_build_id_list_inode): New.
(struct find_memory_region_callback_data): New.
(find_memory_region_callback): New fwd. declaration.
(read_build_id, find_memory_region_callback, get_hex_build_id): New.
(linux_qxfer_libraries_svr4): Add optional build-id attribute
to reply XML document.
Thanks,
Aleksandar
[-- Attachment #2: 0006-gdbserver-linux_qxfer_libraries_svr4-return-build-id.patch --]
[-- Type: text/x-patch, Size: 11817 bytes --]
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4ac28bb..5ff9e95 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40404,6 +40404,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
@@ -40421,7 +40424,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40437,6 +40440,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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..e4409ba 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/linux-low.c b/gdb/gdbserver/linux-low.c
index 523926d..8bbb5ba 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>
@@ -43,6 +44,7 @@
#include "gdb_stat.h"
#include <sys/vfs.h>
#include <sys/uio.h>
+#include <search.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -5643,6 +5645,265 @@ struct link_map_offsets
int l_prev_offset;
};
+
+/* Structure for holding all mappings. Only mapping
+ containing l_ld can have hex_build_id set. */
+
+struct build_id_list
+{
+ ULONGEST vaddr;
+
+ ULONGEST size;
+
+ ULONGEST offset;
+
+ ULONGEST inode;
+
+ const char *filename;
+ int read:1;
+ int write:1;
+ int exec:1;
+ int modified:1;
+
+ /* build_id is hex encoded string allocated using malloc, and
+ needs to be freed. */
+
+ char *hex_build_id;
+};
+
+typedef struct build_id_list build_id_list_s;
+
+DEF_VEC_O(build_id_list_s);
+
+static void
+free_build_id_list (VEC (build_id_list_s) *lst)
+{
+ if (VEC_length (build_id_list_s, lst))
+ {
+ int ix;
+ build_id_list_s *p;
+
+ for (ix = 0; VEC_iterate (build_id_list_s, lst, ix, p); ++ix)
+ xfree (p->hex_build_id);
+ }
+
+ VEC_free (build_id_list_s, lst);
+}
+
+/* Used for qsort-ing list by vaddr. */
+
+static int
+compare_build_id_list (const void *const b1,
+ const void *const b2)
+{
+ const build_id_list_s *const p1 = b1;
+ const build_id_list_s *const p2 = b2;
+
+ if (p1->vaddr > p2->vaddr)
+ return 1;
+ if (p1->vaddr < p2->vaddr)
+ return -1;
+ return 0;
+}
+
+/* Used for finding a mapping containing the given
+ l_ld passed in K. */
+
+static int
+compare_build_id_list_range (const void *const k,
+ const void *const b)
+{
+ const ULONGEST key = *(CORE_ADDR*) k;
+ const build_id_list_s *const p = b;
+
+ if (key < p->vaddr)
+ return -1;
+
+ if (key < p->vaddr + p->size)
+ return 0;
+
+ return 1;
+}
+
+/* Used for linear search of the lowest vaddr for the given
+ inode. */
+
+static int
+compare_build_id_list_inode (const void *const k, const void *const b)
+{
+ const ULONGEST key = *(ULONGEST*)k;
+ const build_id_list_s *const p = b;
+
+ return !(key == p->inode);
+}
+
+struct find_memory_region_callback_data {
+ unsigned is_elf64;
+
+ /* Return. Ordered list of all object mappings sorted in
+ ascending order by VADDR. Must be freed with free_build_id_list. */
+ VEC (build_id_list_s) *list;
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+/* Read .note.gnu.build-id from PT_NOTE. */
+
+static void
+read_build_id (struct find_memory_region_callback_data *const p,
+ build_id_list_s *const bil, const CORE_ADDR load_addr,
+ const CORE_ADDR l_addr)
+{
+ 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;
+#define HDR(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32))
+ if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (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 (load_addr + 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)
+ {
+ void *const pt_note = xmalloc (HDR (phdr, p_memsz));
+ const void *const pt_end
+ = (char*)pt_note + HDR (phdr, p_memsz);
+
+ if (linux_read_memory (HDR (phdr, p_vaddr) + l_addr,
+ pt_note, HDR (phdr, p_memsz)) != 0)
+ {
+ xfree (pt_note);
+ warning ("Could not read note.");
+ break;
+ }
+
+ for (nhdr = pt_note; (void*)nhdr < pt_end;)
+ {
+ const size_t note_sz
+ = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz)
+ + SIZEOFHDR (*nhdr);
+
+ if ((char*)nhdr + note_sz > (char*)pt_end)
+ {
+ warning ("Malformed PT_NOTE\n");
+ break;
+ }
+ if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ /* .note.gnu.build-id. */
+ bil->hex_build_id = xmalloc (note_sz * 2 + 1);
+ bin2hex ((gdb_byte*)nhdr, bil->hex_build_id, note_sz);
+ xfree (pt_note);
+ return;
+ }
+ nhdr = (void*)((char *)nhdr + note_sz);
+ }
+ xfree (pt_note);
+ }
+ }
+ }
+ else
+ warning ("Reading build-id failed.");
+#undef HDR
+#undef SIZEOFHDR
+}
+
+
+/* Create list of build_id_list. */
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
+ ULONGEST inode, int read, int write, int exec,
+ int modified, const char *filename, void *data)
+{
+ if (inode != 0)
+ {
+ struct find_memory_region_callback_data *const p = data;
+ build_id_list_s bil;
+
+ bil.vaddr = vaddr;
+ bil.size = size;
+ bil.inode = inode;
+ bil.read = !(read == 0);
+ bil.write = !(write == 0);
+ bil.exec = !(write == 0);
+ bil.modified = !(write == 0);
+ bil.filename = filename;
+ bil.hex_build_id = NULL;
+
+ VEC_safe_push (build_id_list_s, p->list, &bil);
+ }
+
+ return 0;
+}
+
+/* Get build-id for the given L_LD. DATA must point to
+ already filled list of build_id_list elements.
+
+ Return build_id as stored in the list element corresponding
+ to L_LD.
+
+ NULL may be returned if build-id could not be fetched.
+
+ Returned string must not be freed explicitly.
+*/
+
+static const char *
+get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
+ struct find_memory_region_callback_data *const data)
+{
+ build_id_list_s *const bil
+ = bsearch (&l_ld, VEC_address (build_id_list_s, data->list),
+ VEC_length (build_id_list_s, data->list),
+ sizeof (build_id_list_s), compare_build_id_list_range);
+
+ if (bil == NULL)
+ return NULL;
+
+ if (bil->hex_build_id == NULL)
+ {
+ CORE_ADDR load_addr;
+ size_t len = VEC_length (build_id_list_s, data->list);
+
+ /* Must do linear search for the first mapping of this inode. */
+ build_id_list_s *const bil_min
+ = lfind (&bil->inode, VEC_address (build_id_list_s, data->list), &len,
+ sizeof (build_id_list_s), compare_build_id_list_inode);
+ gdb_assert (bil_min != NULL && "This should never happen.");
+ load_addr = bil_min->vaddr;
+ read_build_id (data, bil, load_addr, l_addr);
+ }
+
+ return bil->hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5655,6 +5916,8 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
struct process_info_private *const priv = current_process ()->private;
char filename[PATH_MAX];
int pid, is_elf64;
+ struct find_memory_region_callback_data data;
+ int build_id_list_p;
static const struct link_map_offsets lmo_32bit_offsets =
{
@@ -5690,6 +5953,19 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ data.is_elf64 = is_elf64;
+ data.list = NULL;
+ VEC_reserve (build_id_list_s, data.list, 16);
+ build_id_list_p
+ = linux_find_memory_regions_full (
+ lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback, &data, NULL) >= 0;
+
+ if (build_id_list_p)
+ qsort (VEC_address (build_id_list_s, data.list),
+ VEC_length (build_id_list_s, data.list),
+ sizeof (build_id_list_s), compare_build_id_list);
+
if (priv->r_debug == 0)
priv->r_debug = get_r_debug (pid, is_elf64);
@@ -5764,6 +6040,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ const char *hex_enc_build_id = NULL;
if (!header_done)
{
@@ -5772,21 +6049,29 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ if (build_id_list_p)
+ hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
+ while (allocated < (p - document + len + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
+ const ptrdiff_t document_len = p - document;
- document = xrealloc (document, 2 * allocated);
allocated *= 2;
+ document = xrealloc (document, allocated);
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<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, "/>");
free (name);
}
else if (lm_prev == 0)
@@ -5821,6 +6106,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
memcpy (readbuf, document + offset, len);
xfree (document);
+ free_build_id_list (data.list);
return len;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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
2 siblings, 0 replies; 79+ messages in thread
From: Eli Zaretskii @ 2013-03-22 17:24 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: jan.kratochvil, gdb-patches
> Date: Fri, 22 Mar 2013 09:04:20 -0400
> From: Aleksandar Ristovski <aristovski@qnx.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
>
> This is the final patch that does actual addition of build-id attribute
> to qxfer_libraries.
>
> * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
> 'build-id' in description, example, new attribute in dtd.
> * linux-low.c (linux-maps.h, search.h): Include.
> (struct build_id_list): New structure.
> (build_id_list_s): New typedef, new vector type def.
> (free_build_id_list, compare_build_id_list,
> compare_build_id_list_range, compare_build_id_list_inode): New.
> (struct find_memory_region_callback_data): New.
> (find_memory_region_callback): New fwd. declaration.
> (read_build_id, find_memory_region_callback, get_hex_build_id): New.
> (linux_qxfer_libraries_svr4): Add optional build-id attribute
> to reply XML document.
The documentation part is OK, thanks.
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
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
1 sibling, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-26 18:11 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Fri, 22 Mar 2013 14:04:11 +0100, Aleksandar Ristovski wrote:
> --- a/gdb/target.c
> +++ b/gdb/target.c
[...]
> @@ -3540,15 +3578,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
> are returned as allocated but empty strings. A warning is issued
> if the result contains any embedded NUL bytes. */
>
> -char *
> -target_fileio_read_stralloc (const char *filename)
> +typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
> + gdb_byte **buf_p, int padding);
> +
> +static char *
> +read_stralloc (const char *filename, read_stralloc_func_ftype *func)
> {
> gdb_byte *buffer;
> char *bufstr;
> LONGEST i, transferred;
>
> - transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
> - bufstr = (char *) buffer;
This line is accidentally deleted, it should not be.
> + transferred = func (filename, &buffer, 1);
>
> if (transferred < 0)
> return NULL;
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
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
1 sibling, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-26 18:27 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Fri, 22 Mar 2013 14:04:16 +0100, Aleksandar Ristovski wrote:
> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -3477,69 +3477,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
[...]
> -read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
> - int padding, void **memory_to_free_ptr)
[...]
> - buf = xrealloc (buf, buf_alloc);
> - }
vs.
> --- a/gdb/common/common-utils.c
> +++ b/gdb/common/common-utils.c
> @@ -348,3 +348,95 @@ skip_spaces_const (const char *chp)
[...]
> +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
> + int padding, void **memory_to_free_ptr)
[...]
> + buf = xrealloc (buf, buf_alloc);
> + if (memory_to_free_ptr != NULL)
> + *memory_to_free_ptr = buf;
> + }
This is not a move, one does not see what has really changed in the diffs.
> -read_stralloc (const char *filename, read_stralloc_func_ftype *func)
> -{
> - gdb_byte *buffer;
> - char *bufstr;
> - LONGEST i, transferred;
> -
> - transferred = func (filename, &buffer, 1);
vs.
> +read_stralloc (const char *filename, read_stralloc_func_ftype *func)
> +{
> + char *buffer;
> + LONGEST i, transferred;
> +
> + transferred = func (filename, (gdb_byte **) &buffer, 1);
Likewise this is not just a move.
One cannot review it before picking each function and comparing them by hand,
this is why the patchset was split into the change + move parts, but you made
changes in the 'move' parts without updating the 'change' parts.
Please update the patchset. Going to look at the real code changes of the
last parts.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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
2 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-26 23:45 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Fri, 22 Mar 2013 14:04:20 +0100, Aleksandar Ristovski wrote:
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 4ac28bb..5ff9e95 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -40404,6 +40404,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.
@code{build-id}, hex encoded @code{NT_GNU_BUILD_ID} note, if such
@code{PT_NOTE} exists.
This describes what gdbserver sends, and gdbserver may even have a binary with
no section table therein. segments == runtime, sections == link time.
> @end itemize
>
> Additionally the single @code{main-lm} attribute specifies address of
> @@ -40421,7 +40424,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
> </library-list-svr>
> @end smallexample
>
> @@ -40437,6 +40440,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>
Please reindent these entries to match their columns like:
<!ATTLIST library l_addr CDATA #REQUIRED>
<!ATTLIST library l_ld CDATA #REQUIRED>
> +<!ATTLIST library build-id CDATA #IMPLIED>
> @end smallexample
>
> @node Memory Map Format
> diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
> index cae7fd8..e4409ba 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>
Again the reindentation.
> +<!ATTLIST library build-id CDATA #IMPLIED>
> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index 523926d..8bbb5ba 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>
> @@ -43,6 +44,7 @@
> #include "gdb_stat.h"
> #include <sys/vfs.h>
> #include <sys/uio.h>
> +#include <search.h>
> #ifndef ELFMAG0
> /* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
> then ELFMAG0 will have been defined. If it didn't get included by
> @@ -5643,6 +5645,265 @@ struct link_map_offsets
> int l_prev_offset;
> };
>
> +
> +/* Structure for holding all mappings. Only mapping
s/all mappings/one mapping/.
> + containing l_ld can have hex_build_id set. */
> +
> +struct build_id_list
Calling it "*_list" is confusing, it is only one entry. VEC makes it a list.
Moreover I would find more appropriate something like "mapping_entry", there
will be many such structs with no relevant build-id.
> +{
Each field should have a comment. So you could remove the empty lines and say
they are all stored from the parameters of linux_find_memory_region_ftype.
> + ULONGEST vaddr;
> +
> + ULONGEST size;
> +
> + ULONGEST offset;
offset is not used so it could be removed - but in fact it should be used,
described later.
> +
> + ULONGEST inode;
> +
> + const char *filename;
It is not used anywhere, you do not need to store it at all.
> + int read:1;
It should be 'unsigned read : 1;', otherwise true value gets read as -1 (which
may not hurt but it is just not great). Also see the ' : 1' spacing (I do not
see it described anywhere but it is so in GDB)..
> + int write:1;
> + int exec:1;
> + int modified:1;
3x likewise.
But now I see any of read/write/exec/modified is not used so they should be
removed.
> +
> + /* build_id is hex encoded string allocated using malloc, and
> + needs to be freed. */
s/build_id/hex_build_id/ although one does not need to repeat the name here.
s/malloc/xmalloc/
Add: It may be NULL.
> +
> + char *hex_build_id;
> +};
> +
> +typedef struct build_id_list build_id_list_s;
> +
> +DEF_VEC_O(build_id_list_s);
> +
> +static void
> +free_build_id_list (VEC (build_id_list_s) *lst)
> +{
> + if (VEC_length (build_id_list_s, lst))
This condition can be removed, VEC_iterate works even if VEC_length == 0.
> + {
> + int ix;
> + build_id_list_s *p;
> +
> + for (ix = 0; VEC_iterate (build_id_list_s, lst, ix, p); ++ix)
> + xfree (p->hex_build_id);
> + }
> +
> + VEC_free (build_id_list_s, lst);
> +}
> +
> +/* Used for qsort-ing list by vaddr. */
> +
> +static int
> +compare_build_id_list (const void *const b1,
> + const void *const b2)
Formatting - it can be:
compare_build_id_list (const void *const b1, const void *const b2)
> +{
> + const build_id_list_s *const p1 = b1;
> + const build_id_list_s *const p2 = b2;
> +
> + if (p1->vaddr > p2->vaddr)
> + return 1;
> + if (p1->vaddr < p2->vaddr)
> + return -1;
> + return 0;
> +}
> +
> +/* Used for finding a mapping containing the given
> + l_ld passed in K. */
> +
> +static int
> +compare_build_id_list_range (const void *const k,
> + const void *const b)
Formatting:
compare_build_id_list_range (const void *const k, const void *const b)
> +{
> + const ULONGEST key = *(CORE_ADDR*) k;
> + const build_id_list_s *const p = b;
> +
> + if (key < p->vaddr)
> + return -1;
> +
> + if (key < p->vaddr + p->size)
> + return 0;
> +
> + return 1;
> +}
> +
> +/* Used for linear search of the lowest vaddr for the given
> + inode. */
> +
> +static int
> +compare_build_id_list_inode (const void *const k, const void *const b)
> +{
> + const ULONGEST key = *(ULONGEST*)k;
GNU Coding Standards formatting:
const ULONGEST key = *(ULONGEST *) k;
> + const build_id_list_s *const p = b;
> +
> + return !(key == p->inode);
> +}
> +
> +struct find_memory_region_callback_data {
Formatting:
struct find_memory_region_callback_data
{
> + unsigned is_elf64;
> +
> + /* Return. Ordered list of all object mappings sorted in
> + ascending order by VADDR. Must be freed with free_build_id_list. */
> + VEC (build_id_list_s) *list;
> +};
> +
> +static linux_find_memory_region_ftype find_memory_region_callback;
> +
> +/* Read .note.gnu.build-id from PT_NOTE. */
> +
> +static void
> +read_build_id (struct find_memory_region_callback_data *const p,
> + build_id_list_s *const bil, const CORE_ADDR load_addr,
> + const CORE_ADDR l_addr)
> +{
> + 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;
get_dynamic already parses/scans PHDRs, you introduce new PHDR parser, they
should be merged.
> +#define HDR(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
> +#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32))
> + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (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 (load_addr + 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)
> + {
> + void *const pt_note = xmalloc (HDR (phdr, p_memsz));
> + const void *const pt_end
> + = (char*)pt_note + HDR (phdr, p_memsz);
GNU Coding Standard formatting:
= (char *) pt_note + HDR (phdr, p_memsz);
> +
> + if (linux_read_memory (HDR (phdr, p_vaddr) + l_addr,
> + pt_note, HDR (phdr, p_memsz)) != 0)
> + {
> + xfree (pt_note);
> + warning ("Could not read note.");
> + break;
> + }
> +
> + for (nhdr = pt_note; (void*)nhdr < pt_end;)
GNU Coding Standard formatting:
for (nhdr = pt_note; (void *) nhdr < pt_end;)
Although I would simplify it as:
for (nhdr = pt_note; (void *) nhdr < pt_end;
nhdr = (void *) nhdr + note_sz)
> + {
> + const size_t note_sz
> + = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz)
> + + SIZEOFHDR (*nhdr);
> +
> + if ((char*)nhdr + note_sz > (char*)pt_end)
GNU Coding Standard formatting:
if ((char *) nhdr + note_sz > (char *) pt_end)
Check also for NOTE_SZ == 0 as bin2hex could crash in such case.
> + {
> + warning ("Malformed PT_NOTE\n");
> + break;
> + }
> + if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
> + {
> + /* .note.gnu.build-id. */
GNU Coding Standard formatting:
> + /* .note.gnu.build-id. */
But this is not ".note.gnu.build-id", that would be a section name. In fact
just remove the comment, there is already NT_GNU_BUILD_ID above.
> + bil->hex_build_id = xmalloc (note_sz * 2 + 1);
> + bin2hex ((gdb_byte*)nhdr, bil->hex_build_id, note_sz);
GNU Coding Standard formatting:
bin2hex ((gdb_byte *) nhdr, bil->hex_build_id, note_sz);
> + xfree (pt_note);
> + return;
> + }
> + nhdr = (void*)((char *)nhdr + note_sz);
GNU Coding Standard formatting + simplification:
nhdr = (void *) nhdr + note_sz;
> + }
> + xfree (pt_note);
> + }
> + }
> + }
> + else
> + warning ("Reading build-id failed.");
> +#undef HDR
> +#undef SIZEOFHDR
> +}
> +
> +
> +/* Create list of build_id_list. */
Update build_id_list struct name.
> +
> +static int
> +find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
> + ULONGEST inode, int read, int write, int exec,
> + int modified, const char *filename, void *data)
> +{
> + if (inode != 0)
> + {
> + struct find_memory_region_callback_data *const p = data;
> + build_id_list_s bil;
> +
> + bil.vaddr = vaddr;
> + bil.size = size;
> + bil.inode = inode;
> + bil.read = !(read == 0);
> + bil.write = !(write == 0);
> + bil.exec = !(write == 0);
> + bil.modified = !(write == 0);
> + bil.filename = filename;
> + bil.hex_build_id = NULL;
> +
> + VEC_safe_push (build_id_list_s, p->list, &bil);
> + }
> +
/* Continue the traversal. */
> + return 0;
> +}
> +
> +/* Get build-id for the given L_LD. DATA must point to
> + already filled list of build_id_list elements.
Update build_id_list struct name.
> +
> + Return build_id as stored in the list element corresponding
> + to L_LD.
> +
> + NULL may be returned if build-id could not be fetched.
> +
> + Returned string must not be freed explicitly.
> +*/
GNU Coding Standards formatting:
Returned string must not be freed explicitly. */
> +
> +static const char *
> +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
> + struct find_memory_region_callback_data *const data)
> +{
> + build_id_list_s *const bil
> + = bsearch (&l_ld, VEC_address (build_id_list_s, data->list),
> + VEC_length (build_id_list_s, data->list),
> + sizeof (build_id_list_s), compare_build_id_list_range);
> +
> + if (bil == NULL)
> + return NULL;
> +
> + if (bil->hex_build_id == NULL)
> + {
> + CORE_ADDR load_addr;
> + size_t len = VEC_length (build_id_list_s, data->list);
> +
> + /* Must do linear search for the first mapping of this inode. */
You do not have to. One could search either for an entry containing:
searched->vaddr == bil->vaddr - bil->offset
or in practice it would be faster to do a linear search backwards from BIL
down as the offset == 0 entry will be at most the fourth one.
One can stop when the vaddr gets lower than bil->vaddr - bil->offset.
The way you implemented it the time complexity is quadratic. I do not insist
on a fix as it will be pretty fast but it would be nice to fix it.
> + build_id_list_s *const bil_min
> + = lfind (&bil->inode, VEC_address (build_id_list_s, data->list), &len,
> + sizeof (build_id_list_s), compare_build_id_list_inode);
> + gdb_assert (bil_min != NULL && "This should never happen.");
It can happen. Application can munmap first page of its shared library,
gdbserver should not crash on such application. Just do not read the build-id
in such case.
Here you should also verify (and ignore build-id for such entry if it fails
the verification) ->offset matches, that is:
bil_min->offset == 0
bil_min->vaddr + bil->offset == bil->vaddr
That is also more reliable than inode, inode should be compared with device
major/minor numbers but those are currently not passed to
find_memory_region_ftype. (Not asking for changing it.)
> + load_addr = bil_min->vaddr;
> + read_build_id (data, bil, load_addr, l_addr);
If the read fails it will be retried next time; but get_hex_build_id should
not be called for the same library twice anyway. Not asking for a change.
> + }
> +
> + return bil->hex_build_id;
> +}
> +
> /* Construct qXfer:libraries-svr4:read reply. */
>
> static int
> @@ -5655,6 +5916,8 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
> struct process_info_private *const priv = current_process ()->private;
> char filename[PATH_MAX];
> int pid, is_elf64;
> + struct find_memory_region_callback_data data;
> + int build_id_list_p;
>
> static const struct link_map_offsets lmo_32bit_offsets =
> {
> @@ -5690,6 +5953,19 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
> is_elf64 = elf_64_file_p (filename, &machine);
> lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
>
> + data.is_elf64 = is_elf64;
> + data.list = NULL;
> + VEC_reserve (build_id_list_s, data.list, 16);
> + build_id_list_p
I do not see why build_id_list_p exists at all. data.list just remains empty
and all the functions already cope with it OK.
> + = linux_find_memory_regions_full (
> + lwpid_of (get_thread_lwp (current_inferior)),
> + find_memory_region_callback, &data, NULL) >= 0;
You could rather just add a warning if linux_find_memory_regions_full
returns -1.
> +
> + if (build_id_list_p)
> + qsort (VEC_address (build_id_list_s, data.list),
> + VEC_length (build_id_list_s, data.list),
> + sizeof (build_id_list_s), compare_build_id_list);
It is always already sorted by Linux kernel, rather a for cycle to verify it
really is sorted.
> +
> if (priv->r_debug == 0)
> priv->r_debug = get_r_debug (pid, is_elf64);
>
> @@ -5764,6 +6040,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
> /* 6x the size for xml_escape_text below. */
> size_t len = 6 * strlen ((char *) libname);
> char *name;
> + const char *hex_enc_build_id = NULL;
>
> if (!header_done)
> {
> @@ -5772,21 +6049,29 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
> header_done = 1;
> }
>
> - while (allocated < p - document + len + 200)
> + name = xml_escape_text ((char *) libname);
> + if (build_id_list_p)
> + hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
> +
> + while (allocated < (p - document + len + 200
> + + (hex_enc_build_id != NULL
> + ? strlen (hex_enc_build_id) : 0)))
> {
> /* Expand to guarantee sufficient storage. */
> - uintptr_t document_len = p - document;
> + const ptrdiff_t document_len = p - document;
>
> - document = xrealloc (document, 2 * allocated);
> allocated *= 2;
> + document = xrealloc (document, allocated);
> p = document + document_len;
> }
>
> - name = xml_escape_text ((char *) libname);
> p += sprintf (p, "<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, "/>");
> free (name);
> }
> else if (lm_prev == 0)
> @@ -5821,6 +6106,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
>
> memcpy (readbuf, document + offset, len);
> xfree (document);
> + free_build_id_list (data.list);
>
> return len;
> }
> --
> 1.7.10.4
>
>
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-03-26 23:45 ` Jan Kratochvil
@ 2013-03-27 17:54 ` Aleksandar Ristovski
2013-03-27 18:08 ` Jan Kratochvil
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-27 17:54 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-03-26 04:41 PM, Jan Kratochvil wrote:
>> >+
>> >+ if (build_id_list_p)
>> >+ qsort (VEC_address (build_id_list_s, data.list),
>> >+ VEC_length (build_id_list_s, data.list),
>> >+ sizeof (build_id_list_s), compare_build_id_list);
> It is always already sorted by Linux kernel, rather a for cycle to verify it
> really is sorted.
>
>
Can we guarantee this is always the case? Even if it is, qsort would do
similar to what a loop would (i.e. no moves would take place).
I'd leave it with qsort unless you feel strongly about it.
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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
0 siblings, 2 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-27 18:08 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Wed, 27 Mar 2013 15:38:29 +0100, Aleksandar Ristovski wrote:
> On 13-03-26 04:41 PM, Jan Kratochvil wrote:
> >>>+ if (build_id_list_p)
> >>>+ qsort (VEC_address (build_id_list_s, data.list),
> >>>+ VEC_length (build_id_list_s, data.list),
> >>>+ sizeof (build_id_list_s), compare_build_id_list);
> >It is always already sorted by Linux kernel, rather a for cycle to verify it
> >really is sorted.
>
> Can we guarantee this is always the case?
Yes.
The problem is that if it is unsorted there is a bug somewhere and that qsort
will hide that bug.
> Even if it is, qsort would
> do similar to what a loop would (i.e. no moves would take place).
(a) qsort has the n*log(n) complexity no matter how sorted the input is.
You are right omitting the read/writes of swapping should speed it up,
just it won't because:
(b) glibc qsort uses msort (=mergesort), therefore it always moves all the
data anyway.
I did not take any benchmarks but I do not think sorted vs. unsorted input
will make any performance difference with glibc.
> I'd leave it with qsort unless you feel strongly about it.
Yes, please change it. It would hide bugs of some unsorted or corrupted data,
and after all it is really needlessly expensive when there are efforts to
optimize the shared libraries reading.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-03-27 18:08 ` Jan Kratochvil
@ 2013-03-27 18:12 ` Eli Zaretskii
2013-03-27 20:46 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Eli Zaretskii @ 2013-03-27 18:12 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: aristovski, gdb-patches
> Date: Wed, 27 Mar 2013 15:50:28 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
>
> (a) qsort has the n*log(n) complexity no matter how sorted the input is.
AFAIK, it has O(n^2) worst-case complexity.
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
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
0 siblings, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-27 20:44 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 240 bytes --]
New patch #4/6. Changed: read_stralloc is now refactored here, rather
than in #5/6 where it gets moved, so that move remains clean in #5.
Similarly, the change for linux_find_memory_regions_full moved from #5 here.
Thanks,
Aleksandar
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-co.-for-move.patch --]
[-- Type: text/x-patch, Size: 12625 bytes --]
From 8c30427ad466b50bdfe3e0e8cf9609545fcc3e4c Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:49:36 -0400
Subject: [PATCH 4/6] Prepare linux_find_memory_regions_full & co. for move
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
gdb/linux-tdep.c | 97 ++++++++++++++++++++++++++++++-------------
gdb/target.c | 122 +++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 153 insertions(+), 66 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 9193c97..2195d0b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3460,55 +3460,73 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
- {
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
- xfree (buf);
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
else
*buf_p = buf;
- return buf_pos;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3518,12 +3536,34 @@ target_fileio_read_alloc_1 (const char *filename,
{
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
}
-
- QUIT;
}
}
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ do_cleanups (close_cleanup);
+ return retval;
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and return
the size of the transferred data. See the declaration in "target.h"
function for more information about the return value. */
@@ -3540,15 +3580,16 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
- gdb_byte *buffer;
- char *bufstr;
+ char *buffer;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
- bufstr = (char *) buffer;
+ transferred = func (filename, (gdb_byte **) &buffer, 1);
if (transferred < 0)
return NULL;
@@ -3556,11 +3597,11 @@ target_fileio_read_stralloc (const char *filename)
if (transferred == 0)
return xstrdup ("");
- bufstr[transferred] = 0;
+ buffer[transferred] = 0;
/* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (bufstr); i < transferred; i++)
- if (bufstr[i] != 0)
+ for (i = strlen (buffer); i < transferred; i++)
+ if (buffer[i] != 0)
{
warning (_("target file %s "
"contained unexpected null characters"),
@@ -3568,9 +3609,14 @@ target_fileio_read_stralloc (const char *filename)
break;
}
- return bufstr;
+ return buffer;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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
1 sibling, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-27 20:46 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 942 bytes --]
Addressed Jan's comments.
On 13-03-27 10:50 AM, Jan Kratochvil wrote:
> On Wed, 27 Mar 2013 15:38:29 +0100, Aleksandar Ristovski wrote:
>> On 13-03-26 04:41 PM, Jan Kratochvil wrote:
>>>>> + if (build_id_list_p)
>>>>> + qsort (VEC_address (build_id_list_s, data.list),
>>>>> + VEC_length (build_id_list_s, data.list),
>>>>> + sizeof (build_id_list_s), compare_build_id_list);
>>> It is always already sorted by Linux kernel, rather a for cycle to verify it
>>> really is sorted.
>>
>> Can we guarantee this is always the case?
>
> Yes.
>
> The problem is that if it is unsorted there is a bug somewhere and that qsort
> will hide that bug.
Qsort removed. I didn't put any traversal; we are making assumption that
the list will be sorted. The checks in the other bits make sure that we
either find the right mapping or none at all, so worst case scenario is
we don't get build-id communicated to gdb.
Thanks,
Aleksandar
[-- Attachment #2: 0006-gdbserver-build-id-attribute-generator.patch --]
[-- Type: text/x-patch, Size: 18151 bytes --]
From 7b49e440f3376999acf4220893944206e94597be Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 11:56:57 -0400
Subject: [PATCH 6/8] gdbserver build-id attribute generator
* doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
'build-id' in description, example, new attribute in dtd.
* features/library-list-svr4.dtd (library-list-svr4): New
'build-id' attribute.
* linux-low.c (linux-maps.h, search.h): Include.
(find_phdr_p_ftype, find_phdr, find_phdr_p): New.
(get_dynamic): Use find_pdhr to traverse program headers.
(struct mapping_entry): New structure.
(mapping_entry_s): New typedef, new vector type def.
(free_mapping_entry, compare_mapping_entry,
compare_mapping_entry_range, compare_mapping_entry_inode): New.
(struct find_memory_region_callback_data): New.
(find_memory_region_callback): New fwd. declaration.
(read_build_id, find_memory_region_callback, get_hex_build_id): New.
(linux_qxfer_libraries_svr4): Add optional build-id attribute
to reply XML document.
---
gdb/doc/gdb.texinfo | 17 +-
gdb/features/library-list-svr4.dtd | 13 +-
gdb/gdbserver/linux-low.c | 396 ++++++++++++++++++++++++++++++++++--
3 files changed, 391 insertions(+), 35 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 38ce259..7c17209 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40323,6 +40323,8 @@ memory address. It is a displacement of absolute memory address against
address the file was prelinked to during the library load.
@item
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
+@item
+@code{build-id}, hex encoded @code{NT_GNU_BUID_ID} note, if it exists.
@end itemize
Additionally the single @code{main-lm} attribute specifies address of
@@ -40340,7 +40342,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40349,13 +40351,14 @@ The format of an SVR4 library list is described by this DTD:
@smallexample
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..fdd6ec0 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -6,11 +6,12 @@
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..f820792 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>
@@ -43,6 +44,7 @@
#include "gdb_stat.h"
#include <sys/vfs.h>
#include <sys/uio.h>
+#include <search.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -5432,6 +5434,70 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
return 0;
}
+
+/* Predicate function type returns 1 if the given phdr is what is
+ being looked for. Returns 0 otherwise. */
+
+typedef int (*find_phdr_p_ftype)(const void *phdr, int is_elf64,
+ const void *data);
+
+/* Linearly traverse pheaders given in PHDR until supplied
+ predicate function returns 1. If supplied predicate function
+ did return 1, stop traversal and return that PHDR. */
+
+static const void *
+find_phdr (int is_elf64, const void *const phdr_begin,
+ const void *const phdr_end, find_phdr_p_ftype find_phdr_p,
+ const void *const data)
+{
+#define SIZEOFHDR(hdr) (is_elf64? sizeof((hdr)._64) : sizeof((hdr)._32))
+#define PHDR_NEXT(hdrp) ((void *) ((char *)(hdrp) + SIZEOFHDR(*hdrp)))
+
+ union ElfXX_Phdr
+ {
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+ } const *phdr = phdr_begin;
+
+ if (phdr == NULL)
+ return NULL;
+
+ while (PHDR_NEXT (phdr) <= phdr_end)
+ {
+ if (find_phdr_p (phdr, is_elf64, data) == 1)
+ return phdr;
+ phdr = PHDR_NEXT (phdr);
+ }
+
+ return NULL;
+#undef PHDR_NEXT
+#undef SIZEOFHDR
+}
+
+
+static int
+find_phdr_p (const void *const phdr, const int is_elf64,
+ const void *const data)
+{
+ const ULONGEST *const type = data;
+
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ return 0;
+}
+
/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
static CORE_ADDR
@@ -5441,6 +5507,8 @@ get_dynamic (const int pid, const int is_elf64)
int num_phdr, i;
unsigned char *phdr_buf;
const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
+ const void *phdr;
+ ULONGEST p_type;
if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
return 0;
@@ -5454,21 +5522,24 @@ get_dynamic (const int pid, const int is_elf64)
/* Compute relocation: it is expected to be 0 for "regular" executables,
non-zero for PIE ones. */
relocation = -1;
- for (i = 0; relocation == -1 && i < num_phdr; i++)
- if (is_elf64)
- {
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ p_type = PT_PHDR;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+ if (phdr)
+ {
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
- else
- {
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
+ }
+ }
if (relocation == -1)
{
@@ -5485,21 +5556,25 @@ get_dynamic (const int pid, const int is_elf64)
return 0;
}
+ p_type = PT_DYNAMIC;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+
for (i = 0; i < num_phdr; i++)
{
if (is_elf64)
{
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf64_Phdr *const p
+ = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
else
{
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf32_Phdr *const p
+ = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
}
@@ -5641,6 +5716,265 @@ struct link_map_offsets
int l_prev_offset;
};
+
+/* Structure for holding a mapping. Only mapping
+ containing l_ld can have hex_build_id set.
+
+ Fields are populated from linux_find_memory_region parameters. */
+
+struct mapping_entry
+{
+ ULONGEST vaddr;
+ ULONGEST size;
+ ULONGEST offset;
+ ULONGEST inode;
+
+ /* Hex encoded string allocated using xmalloc, and
+ needs to be freed. It can be NULL. */
+
+ char *hex_build_id;
+};
+
+typedef struct mapping_entry mapping_entry_s;
+
+DEF_VEC_O(mapping_entry_s);
+
+static void
+free_mapping_entry (VEC (mapping_entry_s) *lst)
+{
+ int ix;
+ mapping_entry_s *p;
+
+ for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix)
+ xfree (p->hex_build_id);
+
+ VEC_free (mapping_entry_s, lst);
+}
+
+/* Used for finding a mapping containing the given
+ l_ld passed in K. */
+
+static int
+compare_mapping_entry_range (const void *const k, const void *const b)
+{
+ const ULONGEST key = *(CORE_ADDR*) k;
+ const mapping_entry_s *const p = b;
+
+ if (key < p->vaddr)
+ return -1;
+
+ if (key < p->vaddr + p->size)
+ return 0;
+
+ return 1;
+}
+
+struct find_memory_region_callback_data
+{
+ unsigned is_elf64;
+
+ /* Return. Ordered list of all object mappings sorted in
+ ascending order by VADDR. Must be freed with free_mapping_entry. */
+ VEC (mapping_entry_s) *list;
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+/* Read .note.gnu.build-id from PT_NOTE. */
+
+static void
+read_build_id (struct find_memory_region_callback_data *const p,
+ mapping_entry_s *const bil, const CORE_ADDR load_addr,
+ const CORE_ADDR l_addr)
+{
+ union ElfXX_Ehdr
+ {
+ Elf32_Ehdr _32;
+ Elf64_Ehdr _64;
+ } ehdr;
+ union ElfXX_Phdr
+ {
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+ } const *phdr;
+ union ElfXX_Nhdr
+ {
+ Elf32_Nhdr _32;
+ Elf64_Nhdr _64;
+ } *nhdr;
+#define HDR(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32))
+ if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (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)
+ {
+ void *phdr_buf;
+ const ULONGEST p_type = PT_NOTE;
+
+ gdb_assert (HDR (ehdr, e_phnum) < 100); /* Basic sanity check. */
+ gdb_assert (HDR (ehdr, e_phentsize) == SIZEOFHDR (*phdr));
+ phdr_buf = alloca (HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize));
+
+ if (linux_read_memory (load_addr + HDR (ehdr, e_phoff), phdr_buf,
+ HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize))
+ != 0)
+ {
+ warning ("Could not read program header.");
+ return;
+ }
+
+ phdr = phdr_buf;
+
+ while ((phdr = find_phdr (p->is_elf64, phdr, (char *) phdr_buf
+ + HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize),
+ find_phdr_p, &p_type)) != NULL)
+ {
+ void *const pt_note = xmalloc (HDR (*phdr, p_memsz));
+ const void *const pt_end
+ = (char*) pt_note + HDR (*phdr, p_memsz);
+
+ if (linux_read_memory (HDR (*phdr, p_vaddr) + l_addr,
+ pt_note, HDR (*phdr, p_memsz)) != 0)
+ {
+ xfree (pt_note);
+ warning ("Could not read note.");
+ break;
+ }
+
+ nhdr = pt_note;
+ while ((void *) nhdr < pt_end)
+ {
+ const size_t note_sz
+ = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz)
+ + SIZEOFHDR (*nhdr);
+
+ if (((char *) nhdr + note_sz) > (char *) pt_end)
+ {
+ warning ("Malformed PT_NOTE\n");
+ break;
+ }
+ if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ bil->hex_build_id = xmalloc (note_sz * 2 + 1);
+ bin2hex ((gdb_byte*) nhdr, bil->hex_build_id, note_sz);
+ xfree (pt_note);
+ return;
+ }
+ nhdr = (void*) ((char *) nhdr + note_sz);
+ }
+ xfree (pt_note);
+ }
+ }
+ else
+ warning ("Reading build-id failed.");
+#undef HDR
+#undef SIZEOFHDR
+}
+
+
+/* Add mapping_entry. */
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
+ ULONGEST inode, int read, int write, int exec,
+ int modified, const char *filename, void *data)
+{
+ if (inode != 0)
+ {
+ struct find_memory_region_callback_data *const p = data;
+ mapping_entry_s bil;
+
+ bil.vaddr = vaddr;
+ bil.size = size;
+ bil.offset = offset;
+ bil.inode = inode;
+ bil.hex_build_id = NULL;
+
+ VEC_safe_push (mapping_entry_s, p->list, &bil);
+ }
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Linear reverse find starting from RBEGIN towards REND looking for
+ the lowest vaddr mapping of the same inode and zero offset. */
+
+static mapping_entry_s *
+lrfind_mapping_entry (mapping_entry_s *const rbegin,
+ const mapping_entry_s *const rend)
+{
+ mapping_entry_s *p;
+
+ for (p = rbegin - 1; p >= rend && p->inode == rbegin->inode; --p)
+ {
+ if (p->offset == 0)
+ {
+ /* Check if the mapping is sane: */
+ if (p->vaddr + rbegin->offset == rbegin->vaddr)
+ return p;
+ warning ("Mapping with offset 0 found but does not correspond to "
+ " the given l_ld");
+ /* Nothing returned in this case. */
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/* Get build-id for the given L_LD. DATA must point to
+ already filled list of mapping_entry elements.
+
+ Return build_id as stored in the list element corresponding
+ to L_LD.
+
+ NULL may be returned if build-id could not be fetched.
+
+ Returned string must not be freed explicitly. */
+
+static const char *
+get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
+ struct find_memory_region_callback_data *const data)
+{
+ mapping_entry_s *bil;
+
+ if (VEC_address (mapping_entry_s, data->list) == NULL)
+ return NULL;
+
+ bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list),
+ VEC_length (mapping_entry_s, data->list),
+ sizeof (mapping_entry_s), compare_mapping_entry_range);
+
+ if (bil == NULL)
+ return NULL;
+
+ if (bil->hex_build_id == NULL)
+ {
+ CORE_ADDR load_addr;
+ mapping_entry_s *const bil_min
+ = lrfind_mapping_entry (bil,
+ VEC_address (mapping_entry_s, data->list));
+ if (bil_min != NULL)
+ {
+ load_addr = bil_min->vaddr;
+ read_build_id (data, bil, load_addr, l_addr);
+ }
+ else
+ {
+ /* Do not try to find hex_build_id again. */
+ bil->hex_build_id = xstrdup ("");
+ warning ("Could not determine load address; "
+ "build_id can not be used.");
+ }
+ }
+
+ return bil->hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5653,6 +5987,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
struct process_info_private *const priv = current_process ()->private;
char filename[PATH_MAX];
int pid, is_elf64;
+ struct find_memory_region_callback_data data;
static const struct link_map_offsets lmo_32bit_offsets =
{
@@ -5688,6 +6023,14 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ data.is_elf64 = is_elf64;
+ data.list = NULL;
+ VEC_reserve (mapping_entry_s, data.list, 16);
+ if (linux_find_memory_regions_full (
+ lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback, &data, NULL) < 0)
+ warning ("Finding memory regions failed");
+
if (priv->r_debug == 0)
priv->r_debug = get_r_debug (pid, is_elf64);
@@ -5762,6 +6105,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ const char *hex_enc_build_id = NULL;
if (!header_done)
{
@@ -5770,21 +6114,28 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
+ while (allocated < (p - document + len + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
+ const ptrdiff_t document_len = p - document;
- document = xrealloc (document, 2 * allocated);
allocated *= 2;
+ document = xrealloc (document, allocated);
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<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, "/>");
free (name);
}
else if (lm_prev == 0)
@@ -5819,6 +6170,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
memcpy (readbuf, document + offset, len);
xfree (document);
+ free_mapping_entry (data.list);
return len;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
2013-03-26 18:27 ` Jan Kratochvil
@ 2013-03-27 21:25 ` Aleksandar Ristovski
2013-03-28 22:38 ` Jan Kratochvil
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-27 21:25 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1806 bytes --]
Moves should now be clean, without mods.
Thanks,
Aleksandar
On 13-03-26 12:58 PM, Jan Kratochvil wrote:
> On Fri, 22 Mar 2013 14:04:16 +0100, Aleksandar Ristovski wrote:
>> --- a/gdb/target.c
>> +++ b/gdb/target.c
>> @@ -3477,69 +3477,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
> [...]
>> -read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
>> - int padding, void **memory_to_free_ptr)
> [...]
>> - buf = xrealloc (buf, buf_alloc);
>> - }
>
> vs.
>
>> --- a/gdb/common/common-utils.c
>> +++ b/gdb/common/common-utils.c
>> @@ -348,3 +348,95 @@ skip_spaces_const (const char *chp)
> [...]
>> +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
>> + int padding, void **memory_to_free_ptr)
> [...]
>> + buf = xrealloc (buf, buf_alloc);
>> + if (memory_to_free_ptr != NULL)
>> + *memory_to_free_ptr = buf;
>> + }
>
> This is not a move, one does not see what has really changed in the diffs.
>
>
>
>> -read_stralloc (const char *filename, read_stralloc_func_ftype *func)
>> -{
>> - gdb_byte *buffer;
>> - char *bufstr;
>> - LONGEST i, transferred;
>> -
>> - transferred = func (filename, &buffer, 1);
>
> vs.
>
>> +read_stralloc (const char *filename, read_stralloc_func_ftype *func)
>> +{
>> + char *buffer;
>> + LONGEST i, transferred;
>> +
>> + transferred = func (filename, (gdb_byte **) &buffer, 1);
>
> Likewise this is not just a move.
>
>
> One cannot review it before picking each function and comparing them by hand,
> this is why the patchset was split into the change + move parts, but you made
> changes in the 'move' parts without updating the 'change' parts.
>
> Please update the patchset. Going to look at the real code changes of the
> last parts.
>
>
> Thanks,
> Jan
>
[-- Attachment #2: 0005-Move-linux_find_memory_regions_full-co.patch --]
[-- Type: text/x-patch, Size: 19736 bytes --]
From bf933cc22eadaa55652d7a13ecbf270341c5e1a8 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:54:36 -0400
Subject: [PATCH 5/6] Move linux_find_memory_regions_full & co.
* common/common-utils.c (read_alloc, read_stralloc): Move definitions
from target.c.
* common/common-utils.h (read_alloc_pread_ftype): New typedef.
(read_alloc): New declaration.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): New declaration.
* common/linux-maps.c (fcntl.h, unistd.h, target.h, gdb_assert.h,
ctype.h, string.h): Include.
(read_mapping): Move from linux-tdep.c.
(linux_find_memory_read_stralloc_1_pread): New function.
(linux_find_memory_read_stralloc_1): New function.
(linux_find_memory_read_stralloc): New function.
* common/linux-maps.h (read_mapping): New declaration.
(linux_find_memory_region_ftype): Moved typedef from linux-tdep.c.
(linux_find_memory_regions_full): New declaration.
* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to common/linux-maps.c.
(linux_find_memory_region_ftype): Moved typedef to common/linux-maps.h.
(linux_find_memory_regions_full): Moved definition to
common/linux-maps.c.
* target.c (read_alloc_pread_ftype): Moved typedef to
common/common-utils.h.
(read_alloc, read_stralloc): Moved definitions to
common/common-utils.c.
---
gdb/common/common-utils.c | 92 ++++++++++++++++++++++
gdb/common/common-utils.h | 11 +++
gdb/common/linux-maps.c | 186 +++++++++++++++++++++++++++++++++++++++++++++
gdb/common/linux-maps.h | 25 ++++++
gdb/linux-tdep.c | 148 +-----------------------------------
gdb/target.c | 101 +-----------------------
6 files changed, 319 insertions(+), 244 deletions(-)
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index c123ed7..36e267a 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -348,3 +348,95 @@ skip_spaces_const (const char *chp)
chp++;
return chp;
}
+
+LONGEST
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
+{
+ size_t buf_alloc, buf_pos;
+ gdb_byte *buf;
+ LONGEST n;
+ int target_errno;
+
+ /* Start by reading up to 4K at a time. The target will throttle
+ this number down if necessary. */
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
+ buf_pos = 0;
+ while (1)
+ {
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
+ {
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
+ else
+ *buf_p = buf;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
+ }
+
+ buf_pos += n;
+
+ /* If the buffer is filling up, expand it. */
+ if (buf_alloc < buf_pos * 2)
+ {
+ buf_alloc *= 2;
+ buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
+ }
+ }
+}
+
+char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
+{
+ char *buffer;
+ LONGEST i, transferred;
+
+ transferred = func (filename, (gdb_byte **) &buffer, 1);
+
+ if (transferred < 0)
+ return NULL;
+
+ if (transferred == 0)
+ return xstrdup ("");
+
+ buffer[transferred] = 0;
+
+ /* Check for embedded NUL bytes; but allow trailing NULs. */
+ for (i = strlen (buffer); i < transferred; i++)
+ if (buffer[i] != 0)
+ {
+ warning (_("target file %s "
+ "contained unexpected null characters"),
+ filename);
+ break;
+ }
+
+ return buffer;
+}
+
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 2c95d34..c7f8162 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -91,4 +91,15 @@ extern char *skip_spaces (char *inp);
extern const char *skip_spaces_const (const char *inp);
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
+ read_alloc_pread_ftype *pread_func, int padding,
+ void **memory_to_free_ptr);
+
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+extern char *read_stralloc (const char *filename,
+ read_stralloc_func_ftype *func);
+
#endif
diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c
index efb0875..a2566e1 100644
--- a/gdb/common/linux-maps.c
+++ b/gdb/common/linux-maps.c
@@ -18,8 +18,194 @@
#ifdef GDBSERVER
#include "server.h"
+#include <fcntl.h>
+#include <unistd.h>
#else
#include "defs.h"
+#include "target.h"
#endif
#include "linux-maps.h"
+#include "gdb_assert.h"
+#include <ctype.h>
+#include <string.h>
+
+/* 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);
+
+ p = skip_spaces_const (p);
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ p = skip_spaces_const (p);
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ p = skip_spaces_const (p);
+ *filename = p;
+}
+
+#ifdef GDBSERVER
+
+static int
+linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf,
+ int len, ULONGEST offset,
+ int *target_errno)
+{
+ int retval = pread (handle, read_buf, len, offset);
+
+ *target_errno = errno;
+ return retval;
+}
+
+static LONGEST
+linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p,
+ int padding)
+{
+ int fd;
+ LONGEST retval;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread,
+ padding, NULL);
+
+ close (fd);
+
+ return retval;
+}
+
+#endif /* GDBSERVER */
+
+static char *
+linux_find_memory_read_stralloc (const char *filename)
+{
+#ifndef GDBSERVER
+ return target_fileio_read_stralloc (filename);
+#else /* GDBSERVER */
+ return read_stralloc (filename, linux_find_memory_read_stralloc_1);
+#endif /* GDBSERVER */
+}
+
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
+
+int
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
+
+ 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. */
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
+ }
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
+ }
+
+ return -1;
+}
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
index da426e5..e989376 100644
--- a/gdb/common/linux-maps.h
+++ b/gdb/common/linux-maps.h
@@ -19,4 +19,29 @@
#ifndef COMMON_LINUX_MAPS_H
#define COMMON_LINUX_MAPS_H
+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);
+
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
+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);
+
+extern int
+ linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr);
+
#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index c48f4ec..4544e5f 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,44 +208,6 @@ 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);
-
- p = skip_spaces_const (p);
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- p = skip_spaces_const (p);
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- p = skip_spaces_const (p);
- *filename = p;
-}
-
/* Implement the "info proc" command. */
static void
@@ -661,115 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
-/* Callback function for linux_find_memory_regions_full. If it returns
- non-zero linux_find_memory_regions_full returns immediately with that
- value. */
-
-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 PID for a corefile. Call FUNC
- with FUNC_DATA for each such region. Return immediately with the
- value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
- be registered to be freed automatically if called FUNC throws an
- exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
- not used. Return -1 if error occurs, 0 if all memory regions have
- been processed or return the value from FUNC if FUNC returns
- non-zero. */
-
-static int
-linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
- void *func_data, void **memory_to_free_ptr)
-{
- char filename[100];
- char *data;
-
- xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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", (int) pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- char *line;
- int retval = 0;
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = data;
- }
-
- 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. */
- retval = func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, func_data);
- if (retval != 0)
- break;
- }
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (data == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (data);
- return retval;
- }
-
- return -1;
-}
-
/* A structure for passing information through
linux_find_memory_regions_full. */
diff --git a/gdb/target.c b/gdb/target.c
index 2195d0b..b24e8b2 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3477,71 +3477,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
target_fileio_read_alloc; see the declaration of that function for more
information. */
-typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
- ULONGEST offset, int *target_errno);
-
-static LONGEST
-read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
- int padding, void **memory_to_free_ptr)
-{
- size_t buf_alloc, buf_pos;
- gdb_byte *buf;
- LONGEST n;
- int target_errno;
-
- /* Start by reading up to 4K at a time. The target will throttle
- this number down if necessary. */
- buf_alloc = 4096;
- buf = xmalloc (buf_alloc);
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = buf;
- }
- buf_pos = 0;
- while (1)
- {
- n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
- buf_pos, &target_errno);
- if (n <= 0)
- {
- if (n < 0 || (n == 0 && buf_pos == 0))
- {
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (buf == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (buf);
- }
- else
- *buf_p = buf;
-
- if (n < 0)
- {
- /* An error occurred. */
- return -1;
- }
- else
- {
- /* Read all there was. */
- return buf_pos;
- }
- }
-
- buf_pos += n;
-
- /* If the buffer is filling up, expand it. */
- if (buf_alloc < buf_pos * 2)
- {
- buf_alloc *= 2;
- buf = xrealloc (buf, buf_alloc);
- if (memory_to_free_ptr != NULL)
- *memory_to_free_ptr = buf;
- }
- }
-}
-
static LONGEST
target_fileio_read_alloc_1 (const char *filename,
gdb_byte **buf_p, int padding)
@@ -3560,6 +3495,10 @@ target_fileio_read_alloc_1 (const char *filename,
make_cleanup (free_current_contents, &memory_to_free);
retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
&memory_to_free);
+ if (retval >= 0)
+ /* Returned allocated memory is interesting for the caller. */
+ memory_to_free = NULL;
+
do_cleanups (close_cleanup);
return retval;
}
@@ -3580,38 +3519,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
- gdb_byte **buf_p, int padding);
-
-static char *
-read_stralloc (const char *filename, read_stralloc_func_ftype *func)
-{
- char *buffer;
- LONGEST i, transferred;
-
- transferred = func (filename, (gdb_byte **) &buffer, 1);
-
- if (transferred < 0)
- return NULL;
-
- if (transferred == 0)
- return xstrdup ("");
-
- buffer[transferred] = 0;
-
- /* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (buffer); i < transferred; i++)
- if (buffer[i] != 0)
- {
- warning (_("target file %s "
- "contained unexpected null characters"),
- filename);
- break;
- }
-
- return buffer;
-}
-
char *
target_fileio_read_stralloc (const char *filename)
{
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-03-27 20:44 ` Aleksandar Ristovski
@ 2013-03-27 21:54 ` Aleksandar Ristovski
2013-03-28 23:02 ` Jan Kratochvil
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-27 21:54 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 240 bytes --]
New patch #4/6. Changed: read_stralloc is now refactored here, rather
than in #5/6 where it gets moved, so that move remains clean in #5.
Similarly, the change for linux_find_memory_regions_full moved from #5 here.
Thanks,
Aleksandar
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-co.-for-move.patch --]
[-- Type: text/x-patch, Size: 12625 bytes --]
From 8c30427ad466b50bdfe3e0e8cf9609545fcc3e4c Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:49:36 -0400
Subject: [PATCH 4/6] Prepare linux_find_memory_regions_full & co. for move
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
gdb/linux-tdep.c | 97 ++++++++++++++++++++++++++++++-------------
gdb/target.c | 122 +++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 153 insertions(+), 66 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 9193c97..2195d0b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3460,55 +3460,73 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
- {
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
- xfree (buf);
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
else
*buf_p = buf;
- return buf_pos;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3518,12 +3536,34 @@ target_fileio_read_alloc_1 (const char *filename,
{
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
}
-
- QUIT;
}
}
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ do_cleanups (close_cleanup);
+ return retval;
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and return
the size of the transferred data. See the declaration in "target.h"
function for more information about the return value. */
@@ -3540,15 +3580,16 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
- gdb_byte *buffer;
- char *bufstr;
+ char *buffer;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
- bufstr = (char *) buffer;
+ transferred = func (filename, (gdb_byte **) &buffer, 1);
if (transferred < 0)
return NULL;
@@ -3556,11 +3597,11 @@ target_fileio_read_stralloc (const char *filename)
if (transferred == 0)
return xstrdup ("");
- bufstr[transferred] = 0;
+ buffer[transferred] = 0;
/* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (bufstr); i < transferred; i++)
- if (bufstr[i] != 0)
+ for (i = strlen (buffer); i < transferred; i++)
+ if (buffer[i] != 0)
{
warning (_("target file %s "
"contained unexpected null characters"),
@@ -3568,9 +3609,14 @@ target_fileio_read_stralloc (const char *filename)
break;
}
- return bufstr;
+ return buffer;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
2013-03-27 21:25 ` Aleksandar Ristovski
@ 2013-03-28 22:38 ` Jan Kratochvil
2013-04-01 23:19 ` Aleksandar Ristovski
0 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-28 22:38 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Wed, 27 Mar 2013 21:17:12 +0100, Aleksandar Ristovski wrote:
> Moves should now be clean, without mods.
[...]
> @@ -3560,6 +3495,10 @@ target_fileio_read_alloc_1 (const char *filename,
> make_cleanup (free_current_contents, &memory_to_free);
> retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
> &memory_to_free);
> + if (retval >= 0)
> + /* Returned allocated memory is interesting for the caller. */
> + memory_to_free = NULL;
The formatting according to GDB specific style in gdb/doc/gdbint.texinfo:
if (retval >= 0)
{
/* Returned allocated memory is interesting for the caller. */
memory_to_free = NULL;
}
> +
> do_cleanups (close_cleanup);
> return retval;
> }
This part should have been in the previous patch. No need to repost but
please rearrange it during the final check-in.
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
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-04-01 22:39 ` Aleksandar Ristovski
1 sibling, 2 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-28 23:02 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Wed, 27 Mar 2013 21:17:08 +0100, Aleksandar Ristovski wrote:
> --- a/gdb/target.c
> +++ b/gdb/target.c
[...]
> @@ -3540,15 +3580,16 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
> are returned as allocated but empty strings. A warning is issued
> if the result contains any embedded NUL bytes. */
>
> -char *
> -target_fileio_read_stralloc (const char *filename)
> +typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
> + gdb_byte **buf_p, int padding);
> +
> +static char *
> +read_stralloc (const char *filename, read_stralloc_func_ftype *func)
> {
> - gdb_byte *buffer;
> - char *bufstr;
> + char *buffer;
Why you make this change? That is unrelated to this patchset, it is a recent
modification by Pedro.
fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3546) gdb_byte *buffer;
fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3547) char *bufstr;
> LONGEST i, transferred;
>
> - transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
> - bufstr = (char *) buffer;
Likewise. I already replied to this change in:
http://sourceware.org/ml/gdb-patches/2013-03/msg00965.html
Message-ID: <20130326165242.GA12291@host2.jankratochvil.net>
> + transferred = func (filename, (gdb_byte **) &buffer, 1);
Likewise - the (gdb_byte **) cast.
>
> if (transferred < 0)
> return NULL;
> @@ -3556,11 +3597,11 @@ target_fileio_read_stralloc (const char *filename)
> if (transferred == 0)
> return xstrdup ("");
>
> - bufstr[transferred] = 0;
> + buffer[transferred] = 0;
>
> /* Check for embedded NUL bytes; but allow trailing NULs. */
> - for (i = strlen (bufstr); i < transferred; i++)
> - if (bufstr[i] != 0)
> + for (i = strlen (buffer); i < transferred; i++)
> + if (buffer[i] != 0)
> {
> warning (_("target file %s "
> "contained unexpected null characters"),
> @@ -3568,9 +3609,14 @@ target_fileio_read_stralloc (const char *filename)
> break;
> }
>
> - return bufstr;
> + return buffer;
> }
>
> +char *
> +target_fileio_read_stralloc (const char *filename)
> +{
> + return read_stralloc (filename, target_fileio_read_alloc_1);
> +}
>
> static int
> default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
> --
> 1.7.10.4
>
Otherwise OK for this part but it needs a new post, thanks for catching the
xrealloc.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-03-27 20:46 ` Aleksandar Ristovski
@ 2013-03-29 0:13 ` Aleksandar Ristovski
2013-03-29 0:20 ` Aleksandar Ristovski
` (2 more replies)
0 siblings, 3 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-29 0:13 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1713 bytes --]
Fixed patch. I haven't addressed any of your concerns except fixed what
was broken. There are two things changed:
1) get_dynamic, you will see I left it unfinished when switched to
generic "find_phdr" to address phdr traversal duplication code.
2) lrfind_mapping_entry can not check for vaddr + offset as offset is
file offset, and for some shared objects this will not match even though
the vaddr of the entry with zero offset is valid.
Stepping through code now shows some of the things you couldn't see,
like e.g. why is there so->build_id, and where is it being set (you
couldn't see it being set before as qXfer_library was broken).
---
Aleksandar
On 13-03-27 04:17 PM, Aleksandar Ristovski wrote:
> Addressed Jan's comments.
>
>
>
> On 13-03-27 10:50 AM, Jan Kratochvil wrote:
>> On Wed, 27 Mar 2013 15:38:29 +0100, Aleksandar Ristovski wrote:
>>> On 13-03-26 04:41 PM, Jan Kratochvil wrote:
>>>>>> + if (build_id_list_p)
>>>>>> + qsort (VEC_address (build_id_list_s, data.list),
>>>>>> + VEC_length (build_id_list_s, data.list),
>>>>>> + sizeof (build_id_list_s), compare_build_id_list);
>>>> It is always already sorted by Linux kernel, rather a for cycle to
>>>> verify it
>>>> really is sorted.
>>>
>>> Can we guarantee this is always the case?
>>
>> Yes.
>>
>> The problem is that if it is unsorted there is a bug somewhere and
>> that qsort
>> will hide that bug.
>
>
> Qsort removed. I didn't put any traversal; we are making assumption that
> the list will be sorted. The checks in the other bits make sure that we
> either find the right mapping or none at all, so worst case scenario is
> we don't get build-id communicated to gdb.
>
>
>
> Thanks,
>
> Aleksandar
>
[-- Attachment #2: 0006-gdbserver-build-id-attribute-generator.patch --]
[-- Type: text/x-patch, Size: 17862 bytes --]
From 80cd24335bcff6625b5c69c1b2f2d43142db08d1 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 11:56:57 -0400
Subject: [PATCH 6/8] gdbserver build-id attribute generator
* doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
'build-id' in description, example, new attribute in dtd.
* features/library-list-svr4.dtd (library-list-svr4): New
'build-id' attribute.
* linux-low.c (linux-maps.h, search.h): Include.
(find_phdr_p_ftype, find_phdr, find_phdr_p): New.
(get_dynamic): Use find_pdhr to traverse program headers.
(struct mapping_entry): New structure.
(mapping_entry_s): New typedef, new vector type def.
(free_mapping_entry, compare_mapping_entry,
compare_mapping_entry_range, compare_mapping_entry_inode): New.
(struct find_memory_region_callback_data): New.
(find_memory_region_callback): New fwd. declaration.
(read_build_id, find_memory_region_callback, get_hex_build_id): New.
(linux_qxfer_libraries_svr4): Add optional build-id attribute
to reply XML document.
---
gdb/doc/gdb.texinfo | 17 +-
gdb/features/library-list-svr4.dtd | 13 +-
gdb/gdbserver/linux-low.c | 388 +++++++++++++++++++++++++++++++++---
3 files changed, 381 insertions(+), 37 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 38ce259..7c17209 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40323,6 +40323,8 @@ memory address. It is a displacement of absolute memory address against
address the file was prelinked to during the library load.
@item
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
+@item
+@code{build-id}, hex encoded @code{NT_GNU_BUID_ID} note, if it exists.
@end itemize
Additionally the single @code{main-lm} attribute specifies address of
@@ -40340,7 +40342,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40349,13 +40351,14 @@ The format of an SVR4 library list is described by this DTD:
@smallexample
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..fdd6ec0 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -6,11 +6,12 @@
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..aa248e9 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>
@@ -43,6 +44,7 @@
#include "gdb_stat.h"
#include <sys/vfs.h>
#include <sys/uio.h>
+#include <search.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -5432,15 +5434,81 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
return 0;
}
+
+/* Predicate function type returns 1 if the given phdr is what is
+ being looked for. Returns 0 otherwise. */
+
+typedef int (*find_phdr_p_ftype)(const void *phdr, int is_elf64,
+ const void *data);
+
+/* Linearly traverse pheaders given in PHDR until supplied
+ predicate function returns 1. If supplied predicate function
+ did return 1, stop traversal and return that PHDR. */
+
+static const void *
+find_phdr (int is_elf64, const void *const phdr_begin,
+ const void *const phdr_end, find_phdr_p_ftype find_phdr_p,
+ const void *const data)
+{
+#define SIZEOFHDR(hdr) (is_elf64? sizeof((hdr)._64) : sizeof((hdr)._32))
+#define PHDR_NEXT(hdrp) ((void *) ((char *)(hdrp) + SIZEOFHDR(*hdrp)))
+
+ union ElfXX_Phdr
+ {
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+ } const *phdr = phdr_begin;
+
+ if (phdr == NULL)
+ return NULL;
+
+ while (PHDR_NEXT (phdr) <= phdr_end)
+ {
+ if (find_phdr_p (phdr, is_elf64, data) == 1)
+ return phdr;
+ phdr = PHDR_NEXT (phdr);
+ }
+
+ return NULL;
+#undef PHDR_NEXT
+#undef SIZEOFHDR
+}
+
+
+static int
+find_phdr_p (const void *const phdr, const int is_elf64,
+ const void *const data)
+{
+ const ULONGEST *const type = data;
+
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ return 0;
+}
+
/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
static CORE_ADDR
get_dynamic (const int pid, const int is_elf64)
{
CORE_ADDR phdr_memaddr, relocation;
- int num_phdr, i;
+ int num_phdr;
unsigned char *phdr_buf;
const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
+ const void *phdr;
+ ULONGEST p_type;
if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
return 0;
@@ -5454,21 +5522,24 @@ get_dynamic (const int pid, const int is_elf64)
/* Compute relocation: it is expected to be 0 for "regular" executables,
non-zero for PIE ones. */
relocation = -1;
- for (i = 0; relocation == -1 && i < num_phdr; i++)
- if (is_elf64)
- {
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ p_type = PT_PHDR;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+ if (phdr != NULL)
+ {
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
- else
- {
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
+ }
+ }
if (relocation == -1)
{
@@ -5485,21 +5556,23 @@ get_dynamic (const int pid, const int is_elf64)
return 0;
}
- for (i = 0; i < num_phdr; i++)
+ p_type = PT_DYNAMIC;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+
+ if (phdr != NULL)
{
if (is_elf64)
{
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
else
{
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
}
@@ -5641,6 +5714,255 @@ struct link_map_offsets
int l_prev_offset;
};
+
+/* Structure for holding a mapping. Only mapping
+ containing l_ld can have hex_build_id set.
+
+ Fields are populated from linux_find_memory_region parameters. */
+
+struct mapping_entry
+{
+ ULONGEST vaddr;
+ ULONGEST size;
+ ULONGEST offset;
+ ULONGEST inode;
+
+ /* Hex encoded string allocated using xmalloc, and
+ needs to be freed. It can be NULL. */
+
+ char *hex_build_id;
+};
+
+typedef struct mapping_entry mapping_entry_s;
+
+DEF_VEC_O(mapping_entry_s);
+
+static void
+free_mapping_entry (VEC (mapping_entry_s) *lst)
+{
+ int ix;
+ mapping_entry_s *p;
+
+ for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix)
+ xfree (p->hex_build_id);
+
+ VEC_free (mapping_entry_s, lst);
+}
+
+/* Used for finding a mapping containing the given
+ l_ld passed in K. */
+
+static int
+compare_mapping_entry_range (const void *const k, const void *const b)
+{
+ const ULONGEST key = *(CORE_ADDR*) k;
+ const mapping_entry_s *const p = b;
+
+ if (key < p->vaddr)
+ return -1;
+
+ if (key < p->vaddr + p->size)
+ return 0;
+
+ return 1;
+}
+
+struct find_memory_region_callback_data
+{
+ unsigned is_elf64;
+
+ /* Return. Ordered list of all object mappings sorted in
+ ascending order by VADDR. Must be freed with free_mapping_entry. */
+ VEC (mapping_entry_s) *list;
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+/* Read .note.gnu.build-id from PT_NOTE. */
+
+static void
+read_build_id (struct find_memory_region_callback_data *const p,
+ mapping_entry_s *const bil, const CORE_ADDR load_addr,
+ const CORE_ADDR l_addr)
+{
+ union ElfXX_Ehdr
+ {
+ Elf32_Ehdr _32;
+ Elf64_Ehdr _64;
+ } ehdr;
+ union ElfXX_Phdr
+ {
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+ } const *phdr;
+ union ElfXX_Nhdr
+ {
+ Elf32_Nhdr _32;
+ Elf64_Nhdr _64;
+ } *nhdr;
+#define HDR(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32))
+ if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (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)
+ {
+ void *phdr_buf;
+ const ULONGEST p_type = PT_NOTE;
+
+ gdb_assert (HDR (ehdr, e_phnum) < 100); /* Basic sanity check. */
+ gdb_assert (HDR (ehdr, e_phentsize) == SIZEOFHDR (*phdr));
+ phdr_buf = alloca (HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize));
+
+ if (linux_read_memory (load_addr + HDR (ehdr, e_phoff), phdr_buf,
+ HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize))
+ != 0)
+ {
+ warning ("Could not read program header.");
+ return;
+ }
+
+ phdr = phdr_buf;
+
+ while ((phdr = find_phdr (p->is_elf64, phdr, (char *) phdr_buf
+ + HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize),
+ find_phdr_p, &p_type)) != NULL)
+ {
+ void *const pt_note = xmalloc (HDR (*phdr, p_memsz));
+ const void *const pt_end
+ = (char*) pt_note + HDR (*phdr, p_memsz);
+
+ if (linux_read_memory (HDR (*phdr, p_vaddr) + l_addr,
+ pt_note, HDR (*phdr, p_memsz)) != 0)
+ {
+ xfree (pt_note);
+ warning ("Could not read note.");
+ break;
+ }
+
+ nhdr = pt_note;
+ while ((void *) nhdr < pt_end)
+ {
+ const size_t note_sz
+ = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz)
+ + SIZEOFHDR (*nhdr);
+
+ if (((char *) nhdr + note_sz) > (char *) pt_end)
+ {
+ warning ("Malformed PT_NOTE\n");
+ break;
+ }
+ if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ bil->hex_build_id = xmalloc (note_sz * 2 + 1);
+ bin2hex ((gdb_byte*) nhdr, bil->hex_build_id, note_sz);
+ xfree (pt_note);
+ return;
+ }
+ nhdr = (void*) ((char *) nhdr + note_sz);
+ }
+ xfree (pt_note);
+ }
+ }
+ else
+ warning ("Reading build-id failed.");
+#undef HDR
+#undef SIZEOFHDR
+}
+
+
+/* Add mapping_entry. */
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
+ ULONGEST inode, int read, int write, int exec,
+ int modified, const char *filename, void *data)
+{
+ if (inode != 0)
+ {
+ struct find_memory_region_callback_data *const p = data;
+ mapping_entry_s bil;
+
+ bil.vaddr = vaddr;
+ bil.size = size;
+ bil.offset = offset;
+ bil.inode = inode;
+ bil.hex_build_id = NULL;
+
+ VEC_safe_push (mapping_entry_s, p->list, &bil);
+ }
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Linear reverse find starting from RBEGIN towards REND looking for
+ the lowest vaddr mapping of the same inode and zero offset. */
+
+static mapping_entry_s *
+lrfind_mapping_entry (mapping_entry_s *const rbegin,
+ const mapping_entry_s *const rend)
+{
+ mapping_entry_s *p;
+
+ for (p = rbegin - 1; p >= rend && p->inode == rbegin->inode; --p)
+ if (p->offset == 0)
+ return p;
+
+ return NULL;
+}
+
+/* Get build-id for the given L_LD. DATA must point to
+ already filled list of mapping_entry elements.
+
+ Return build_id as stored in the list element corresponding
+ to L_LD.
+
+ NULL may be returned if build-id could not be fetched.
+
+ Returned string must not be freed explicitly. */
+
+static const char *
+get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
+ struct find_memory_region_callback_data *const data)
+{
+ mapping_entry_s *bil;
+
+ if (VEC_address (mapping_entry_s, data->list) == NULL)
+ return NULL;
+
+ bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list),
+ VEC_length (mapping_entry_s, data->list),
+ sizeof (mapping_entry_s), compare_mapping_entry_range);
+
+ if (bil == NULL)
+ return NULL;
+
+ if (bil->hex_build_id == NULL)
+ {
+ CORE_ADDR load_addr;
+ mapping_entry_s *const bil_min
+ = lrfind_mapping_entry (bil,
+ VEC_address (mapping_entry_s, data->list));
+ if (bil_min != NULL)
+ {
+ load_addr = bil_min->vaddr;
+ read_build_id (data, bil, load_addr, l_addr);
+ }
+ else
+ {
+ /* Do not try to find hex_build_id again. */
+ bil->hex_build_id = xstrdup ("");
+ warning ("Could not determine load address; "
+ "build_id can not be used.");
+ }
+ }
+
+ return bil->hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5653,6 +5975,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
struct process_info_private *const priv = current_process ()->private;
char filename[PATH_MAX];
int pid, is_elf64;
+ struct find_memory_region_callback_data data;
static const struct link_map_offsets lmo_32bit_offsets =
{
@@ -5688,6 +6011,14 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ data.is_elf64 = is_elf64;
+ data.list = NULL;
+ VEC_reserve (mapping_entry_s, data.list, 16);
+ if (linux_find_memory_regions_full (
+ lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback, &data, NULL) < 0)
+ warning ("Finding memory regions failed");
+
if (priv->r_debug == 0)
priv->r_debug = get_r_debug (pid, is_elf64);
@@ -5762,6 +6093,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ const char *hex_enc_build_id = NULL;
if (!header_done)
{
@@ -5770,21 +6102,28 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
+ while (allocated < (p - document + len + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
+ const ptrdiff_t document_len = p - document;
- document = xrealloc (document, 2 * allocated);
allocated *= 2;
+ document = xrealloc (document, allocated);
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<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, "/>");
free (name);
}
else if (lm_prev == 0)
@@ -5819,6 +6158,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
memcpy (readbuf, document + offset, len);
xfree (document);
+ free_mapping_entry (data.list);
return len;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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>
2 siblings, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-29 0:20 UTC (permalink / raw)
To: gdb-patches; +Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1713 bytes --]
Fixed patch. I haven't addressed any of your concerns except fixed what
was broken. There are two things changed:
1) get_dynamic, you will see I left it unfinished when switched to
generic "find_phdr" to address phdr traversal duplication code.
2) lrfind_mapping_entry can not check for vaddr + offset as offset is
file offset, and for some shared objects this will not match even though
the vaddr of the entry with zero offset is valid.
Stepping through code now shows some of the things you couldn't see,
like e.g. why is there so->build_id, and where is it being set (you
couldn't see it being set before as qXfer_library was broken).
---
Aleksandar
On 13-03-27 04:17 PM, Aleksandar Ristovski wrote:
> Addressed Jan's comments.
>
>
>
> On 13-03-27 10:50 AM, Jan Kratochvil wrote:
>> On Wed, 27 Mar 2013 15:38:29 +0100, Aleksandar Ristovski wrote:
>>> On 13-03-26 04:41 PM, Jan Kratochvil wrote:
>>>>>> + if (build_id_list_p)
>>>>>> + qsort (VEC_address (build_id_list_s, data.list),
>>>>>> + VEC_length (build_id_list_s, data.list),
>>>>>> + sizeof (build_id_list_s), compare_build_id_list);
>>>> It is always already sorted by Linux kernel, rather a for cycle to
>>>> verify it
>>>> really is sorted.
>>>
>>> Can we guarantee this is always the case?
>>
>> Yes.
>>
>> The problem is that if it is unsorted there is a bug somewhere and
>> that qsort
>> will hide that bug.
>
>
> Qsort removed. I didn't put any traversal; we are making assumption that
> the list will be sorted. The checks in the other bits make sure that we
> either find the right mapping or none at all, so worst case scenario is
> we don't get build-id communicated to gdb.
>
>
>
> Thanks,
>
> Aleksandar
>
[-- Attachment #2: 0006-gdbserver-build-id-attribute-generator.patch --]
[-- Type: text/x-patch, Size: 17862 bytes --]
From 80cd24335bcff6625b5c69c1b2f2d43142db08d1 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 11:56:57 -0400
Subject: [PATCH 6/8] gdbserver build-id attribute generator
* doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
'build-id' in description, example, new attribute in dtd.
* features/library-list-svr4.dtd (library-list-svr4): New
'build-id' attribute.
* linux-low.c (linux-maps.h, search.h): Include.
(find_phdr_p_ftype, find_phdr, find_phdr_p): New.
(get_dynamic): Use find_pdhr to traverse program headers.
(struct mapping_entry): New structure.
(mapping_entry_s): New typedef, new vector type def.
(free_mapping_entry, compare_mapping_entry,
compare_mapping_entry_range, compare_mapping_entry_inode): New.
(struct find_memory_region_callback_data): New.
(find_memory_region_callback): New fwd. declaration.
(read_build_id, find_memory_region_callback, get_hex_build_id): New.
(linux_qxfer_libraries_svr4): Add optional build-id attribute
to reply XML document.
---
gdb/doc/gdb.texinfo | 17 +-
gdb/features/library-list-svr4.dtd | 13 +-
gdb/gdbserver/linux-low.c | 388 +++++++++++++++++++++++++++++++++---
3 files changed, 381 insertions(+), 37 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 38ce259..7c17209 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40323,6 +40323,8 @@ memory address. It is a displacement of absolute memory address against
address the file was prelinked to during the library load.
@item
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
+@item
+@code{build-id}, hex encoded @code{NT_GNU_BUID_ID} note, if it exists.
@end itemize
Additionally the single @code{main-lm} attribute specifies address of
@@ -40340,7 +40342,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40349,13 +40351,14 @@ The format of an SVR4 library list is described by this DTD:
@smallexample
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..fdd6ec0 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -6,11 +6,12 @@
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..aa248e9 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>
@@ -43,6 +44,7 @@
#include "gdb_stat.h"
#include <sys/vfs.h>
#include <sys/uio.h>
+#include <search.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -5432,15 +5434,81 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
return 0;
}
+
+/* Predicate function type returns 1 if the given phdr is what is
+ being looked for. Returns 0 otherwise. */
+
+typedef int (*find_phdr_p_ftype)(const void *phdr, int is_elf64,
+ const void *data);
+
+/* Linearly traverse pheaders given in PHDR until supplied
+ predicate function returns 1. If supplied predicate function
+ did return 1, stop traversal and return that PHDR. */
+
+static const void *
+find_phdr (int is_elf64, const void *const phdr_begin,
+ const void *const phdr_end, find_phdr_p_ftype find_phdr_p,
+ const void *const data)
+{
+#define SIZEOFHDR(hdr) (is_elf64? sizeof((hdr)._64) : sizeof((hdr)._32))
+#define PHDR_NEXT(hdrp) ((void *) ((char *)(hdrp) + SIZEOFHDR(*hdrp)))
+
+ union ElfXX_Phdr
+ {
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+ } const *phdr = phdr_begin;
+
+ if (phdr == NULL)
+ return NULL;
+
+ while (PHDR_NEXT (phdr) <= phdr_end)
+ {
+ if (find_phdr_p (phdr, is_elf64, data) == 1)
+ return phdr;
+ phdr = PHDR_NEXT (phdr);
+ }
+
+ return NULL;
+#undef PHDR_NEXT
+#undef SIZEOFHDR
+}
+
+
+static int
+find_phdr_p (const void *const phdr, const int is_elf64,
+ const void *const data)
+{
+ const ULONGEST *const type = data;
+
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ return 0;
+}
+
/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
static CORE_ADDR
get_dynamic (const int pid, const int is_elf64)
{
CORE_ADDR phdr_memaddr, relocation;
- int num_phdr, i;
+ int num_phdr;
unsigned char *phdr_buf;
const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
+ const void *phdr;
+ ULONGEST p_type;
if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
return 0;
@@ -5454,21 +5522,24 @@ get_dynamic (const int pid, const int is_elf64)
/* Compute relocation: it is expected to be 0 for "regular" executables,
non-zero for PIE ones. */
relocation = -1;
- for (i = 0; relocation == -1 && i < num_phdr; i++)
- if (is_elf64)
- {
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ p_type = PT_PHDR;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+ if (phdr != NULL)
+ {
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
- else
- {
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
+ }
+ }
if (relocation == -1)
{
@@ -5485,21 +5556,23 @@ get_dynamic (const int pid, const int is_elf64)
return 0;
}
- for (i = 0; i < num_phdr; i++)
+ p_type = PT_DYNAMIC;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+
+ if (phdr != NULL)
{
if (is_elf64)
{
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
else
{
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
}
@@ -5641,6 +5714,255 @@ struct link_map_offsets
int l_prev_offset;
};
+
+/* Structure for holding a mapping. Only mapping
+ containing l_ld can have hex_build_id set.
+
+ Fields are populated from linux_find_memory_region parameters. */
+
+struct mapping_entry
+{
+ ULONGEST vaddr;
+ ULONGEST size;
+ ULONGEST offset;
+ ULONGEST inode;
+
+ /* Hex encoded string allocated using xmalloc, and
+ needs to be freed. It can be NULL. */
+
+ char *hex_build_id;
+};
+
+typedef struct mapping_entry mapping_entry_s;
+
+DEF_VEC_O(mapping_entry_s);
+
+static void
+free_mapping_entry (VEC (mapping_entry_s) *lst)
+{
+ int ix;
+ mapping_entry_s *p;
+
+ for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix)
+ xfree (p->hex_build_id);
+
+ VEC_free (mapping_entry_s, lst);
+}
+
+/* Used for finding a mapping containing the given
+ l_ld passed in K. */
+
+static int
+compare_mapping_entry_range (const void *const k, const void *const b)
+{
+ const ULONGEST key = *(CORE_ADDR*) k;
+ const mapping_entry_s *const p = b;
+
+ if (key < p->vaddr)
+ return -1;
+
+ if (key < p->vaddr + p->size)
+ return 0;
+
+ return 1;
+}
+
+struct find_memory_region_callback_data
+{
+ unsigned is_elf64;
+
+ /* Return. Ordered list of all object mappings sorted in
+ ascending order by VADDR. Must be freed with free_mapping_entry. */
+ VEC (mapping_entry_s) *list;
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+/* Read .note.gnu.build-id from PT_NOTE. */
+
+static void
+read_build_id (struct find_memory_region_callback_data *const p,
+ mapping_entry_s *const bil, const CORE_ADDR load_addr,
+ const CORE_ADDR l_addr)
+{
+ union ElfXX_Ehdr
+ {
+ Elf32_Ehdr _32;
+ Elf64_Ehdr _64;
+ } ehdr;
+ union ElfXX_Phdr
+ {
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+ } const *phdr;
+ union ElfXX_Nhdr
+ {
+ Elf32_Nhdr _32;
+ Elf64_Nhdr _64;
+ } *nhdr;
+#define HDR(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
+#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32))
+ if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (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)
+ {
+ void *phdr_buf;
+ const ULONGEST p_type = PT_NOTE;
+
+ gdb_assert (HDR (ehdr, e_phnum) < 100); /* Basic sanity check. */
+ gdb_assert (HDR (ehdr, e_phentsize) == SIZEOFHDR (*phdr));
+ phdr_buf = alloca (HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize));
+
+ if (linux_read_memory (load_addr + HDR (ehdr, e_phoff), phdr_buf,
+ HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize))
+ != 0)
+ {
+ warning ("Could not read program header.");
+ return;
+ }
+
+ phdr = phdr_buf;
+
+ while ((phdr = find_phdr (p->is_elf64, phdr, (char *) phdr_buf
+ + HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize),
+ find_phdr_p, &p_type)) != NULL)
+ {
+ void *const pt_note = xmalloc (HDR (*phdr, p_memsz));
+ const void *const pt_end
+ = (char*) pt_note + HDR (*phdr, p_memsz);
+
+ if (linux_read_memory (HDR (*phdr, p_vaddr) + l_addr,
+ pt_note, HDR (*phdr, p_memsz)) != 0)
+ {
+ xfree (pt_note);
+ warning ("Could not read note.");
+ break;
+ }
+
+ nhdr = pt_note;
+ while ((void *) nhdr < pt_end)
+ {
+ const size_t note_sz
+ = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz)
+ + SIZEOFHDR (*nhdr);
+
+ if (((char *) nhdr + note_sz) > (char *) pt_end)
+ {
+ warning ("Malformed PT_NOTE\n");
+ break;
+ }
+ if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
+ {
+ bil->hex_build_id = xmalloc (note_sz * 2 + 1);
+ bin2hex ((gdb_byte*) nhdr, bil->hex_build_id, note_sz);
+ xfree (pt_note);
+ return;
+ }
+ nhdr = (void*) ((char *) nhdr + note_sz);
+ }
+ xfree (pt_note);
+ }
+ }
+ else
+ warning ("Reading build-id failed.");
+#undef HDR
+#undef SIZEOFHDR
+}
+
+
+/* Add mapping_entry. */
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
+ ULONGEST inode, int read, int write, int exec,
+ int modified, const char *filename, void *data)
+{
+ if (inode != 0)
+ {
+ struct find_memory_region_callback_data *const p = data;
+ mapping_entry_s bil;
+
+ bil.vaddr = vaddr;
+ bil.size = size;
+ bil.offset = offset;
+ bil.inode = inode;
+ bil.hex_build_id = NULL;
+
+ VEC_safe_push (mapping_entry_s, p->list, &bil);
+ }
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Linear reverse find starting from RBEGIN towards REND looking for
+ the lowest vaddr mapping of the same inode and zero offset. */
+
+static mapping_entry_s *
+lrfind_mapping_entry (mapping_entry_s *const rbegin,
+ const mapping_entry_s *const rend)
+{
+ mapping_entry_s *p;
+
+ for (p = rbegin - 1; p >= rend && p->inode == rbegin->inode; --p)
+ if (p->offset == 0)
+ return p;
+
+ return NULL;
+}
+
+/* Get build-id for the given L_LD. DATA must point to
+ already filled list of mapping_entry elements.
+
+ Return build_id as stored in the list element corresponding
+ to L_LD.
+
+ NULL may be returned if build-id could not be fetched.
+
+ Returned string must not be freed explicitly. */
+
+static const char *
+get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
+ struct find_memory_region_callback_data *const data)
+{
+ mapping_entry_s *bil;
+
+ if (VEC_address (mapping_entry_s, data->list) == NULL)
+ return NULL;
+
+ bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list),
+ VEC_length (mapping_entry_s, data->list),
+ sizeof (mapping_entry_s), compare_mapping_entry_range);
+
+ if (bil == NULL)
+ return NULL;
+
+ if (bil->hex_build_id == NULL)
+ {
+ CORE_ADDR load_addr;
+ mapping_entry_s *const bil_min
+ = lrfind_mapping_entry (bil,
+ VEC_address (mapping_entry_s, data->list));
+ if (bil_min != NULL)
+ {
+ load_addr = bil_min->vaddr;
+ read_build_id (data, bil, load_addr, l_addr);
+ }
+ else
+ {
+ /* Do not try to find hex_build_id again. */
+ bil->hex_build_id = xstrdup ("");
+ warning ("Could not determine load address; "
+ "build_id can not be used.");
+ }
+ }
+
+ return bil->hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5653,6 +5975,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
struct process_info_private *const priv = current_process ()->private;
char filename[PATH_MAX];
int pid, is_elf64;
+ struct find_memory_region_callback_data data;
static const struct link_map_offsets lmo_32bit_offsets =
{
@@ -5688,6 +6011,14 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ data.is_elf64 = is_elf64;
+ data.list = NULL;
+ VEC_reserve (mapping_entry_s, data.list, 16);
+ if (linux_find_memory_regions_full (
+ lwpid_of (get_thread_lwp (current_inferior)),
+ find_memory_region_callback, &data, NULL) < 0)
+ warning ("Finding memory regions failed");
+
if (priv->r_debug == 0)
priv->r_debug = get_r_debug (pid, is_elf64);
@@ -5762,6 +6093,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ const char *hex_enc_build_id = NULL;
if (!header_done)
{
@@ -5770,21 +6102,28 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
+ while (allocated < (p - document + len + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
+ const ptrdiff_t document_len = p - document;
- document = xrealloc (document, 2 * allocated);
allocated *= 2;
+ document = xrealloc (document, allocated);
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<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, "/>");
free (name);
}
else if (lm_prev == 0)
@@ -5819,6 +6158,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
memcpy (readbuf, document + offset, len);
xfree (document);
+ free_mapping_entry (data.list);
return len;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
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
1 sibling, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-03-29 0:26 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, Pedro Alves
On 13-03-28 04:28 PM, Jan Kratochvil wrote:
> On Wed, 27 Mar 2013 21:17:08 +0100, Aleksandar Ristovski wrote:
>> --- a/gdb/target.c
>> +++ b/gdb/target.c
> [...]
>> @@ -3540,15 +3580,16 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
>> are returned as allocated but empty strings. A warning is issued
>> if the result contains any embedded NUL bytes. */
>>
>> -char *
>> -target_fileio_read_stralloc (const char *filename)
>> +typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
>> + gdb_byte **buf_p, int padding);
>> +
>> +static char *
>> +read_stralloc (const char *filename, read_stralloc_func_ftype *func)
>> {
>> - gdb_byte *buffer;
>> - char *bufstr;
>> + char *buffer;
>
> Why you make this change? That is unrelated to this patchset, it is a recent
> modification by Pedro.
[AR] I apologize to Pedro - the code as I put it seems more natural, a
few less lines and such. But I can remove it, it is not essential.
>
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3546) gdb_byte *buffer;
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3547) char *bufstr;
>
>
>
>> LONGEST i, transferred;
>>
>> - transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
>
>> - bufstr = (char *) buffer;
>
> Likewise. I already replied to this change in:
> http://sourceware.org/ml/gdb-patches/2013-03/msg00965.html
> Message-ID: <20130326165242.GA12291@host2.jankratochvil.net>
>
>
>> + transferred = func (filename, (gdb_byte **) &buffer, 1);
>
> Likewise - the (gdb_byte **) cast.
>
>
>>
>> if (transferred < 0)
>> return NULL;
>> @@ -3556,11 +3597,11 @@ target_fileio_read_stralloc (const char *filename)
>> if (transferred == 0)
>> return xstrdup ("");
>>
>> - bufstr[transferred] = 0;
>> + buffer[transferred] = 0;
>>
>> /* Check for embedded NUL bytes; but allow trailing NULs. */
>> - for (i = strlen (bufstr); i < transferred; i++)
>> - if (bufstr[i] != 0)
>> + for (i = strlen (buffer); i < transferred; i++)
>> + if (buffer[i] != 0)
>> {
>> warning (_("target file %s "
>> "contained unexpected null characters"),
>> @@ -3568,9 +3609,14 @@ target_fileio_read_stralloc (const char *filename)
>> break;
>> }
>>
>> - return bufstr;
>> + return buffer;
>> }
>>
>> +char *
>> +target_fileio_read_stralloc (const char *filename)
>> +{
>> + return read_stralloc (filename, target_fileio_read_alloc_1);
>> +}
>>
>> static int
>> default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
>> --
>> 1.7.10.4
>>
>
>
> Otherwise OK for this part but it needs a new post, thanks for catching the
> xrealloc.
[AR] Thanks. I will repost the patch.
>
>
> Thanks,
> Jan
>
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-03-29 0:26 ` Aleksandar Ristovski
@ 2013-03-29 0:29 ` Pedro Alves
0 siblings, 0 replies; 79+ messages in thread
From: Pedro Alves @ 2013-03-29 0:29 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: Jan Kratochvil, gdb-patches
On 03/28/2013 08:56 PM, Aleksandar Ristovski wrote:
>>>
>>> +static char *
>>> +read_stralloc (const char *filename, read_stralloc_func_ftype *func)
>>> {
>>> - gdb_byte *buffer;
>>> - char *bufstr;
>>> + char *buffer;
>>
>> Why you make this change? That is unrelated to this patchset, it is a recent
>> modification by Pedro.
>
>
> [AR] I apologize to Pedro - the code as I put it seems more natural, a few less lines and such. But I can remove it, it is not essential.
Please don't revert that.
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3546) gdb_byte *buffer;
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3547) char *bufstr;
$ git show fad14e531
commit fad14e531b1fa96211beac28557d7fb5d42a8b80
Author: Pedro Alves <palves@redhat.com>
Date: Mon Mar 11 12:22:16 2013 +0000
Avoid invalid pointer to pointer conversions.
Casts between 'char **' <-> 'unsigned char **' and 'char **' <-> const
char **' are actually invalid:
http://gcc.gnu.org/ml/gcc-help/2013-03/msg00118.html
In a nutshell, char (and variants) can alias anything, but pointers to
chars get no special treatment (cf. C99/N1256, 6.5/7).
Turns out older gcc's actually warn/complain on these constructs,
though newer one's don't:
http://sourceware.org/ml/gdb-patches/2013-03/msg00429.html
http://sourceware.org/ml/gdb-patches/2013-03/msg00430.html
This patch fixes the cases I added last week. It also fixes one other
preexisting case in charset.c, though it seems even older gccs don't
complain of char * <-> const char * aliasing.
Tested on x86_64 Fedora 17.
gdb/
2013-03-11 Pedro Alves <palves@redhat.com>
* charset.c (convert_between_encodings): Don't cast between
different pointer to pointer types. Instead, make the 'inp' local
be of the type iconv expects.
(wchar_iterate): Don't cast between different pointer to pointer
types. Instead, use new pointer local of the type iconv expects.
* target.c (target_read_stralloc, target_fileio_read_stralloc):
Add new local of type char pointer, and use it to get a
char/string view of the byte buffer, instead of casting between
pointer to pointer types.
--
Pedro Alves
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
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>
2 siblings, 0 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-03-29 16:19 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Thu, 28 Mar 2013 21:53:38 +0100, Aleksandar Ristovski wrote:
> 2) lrfind_mapping_entry can not check for vaddr + offset as offset
> is file offset, and for some shared objects this will not match even
> though the vaddr of the entry with zero offset is valid.
This is not yet a new review but:
When it does not match? ELF is designed so that each segment can be placed
arbitrarily but this code is Linux specific and Linux guarantees all segments
will be placed in memory with the same displacement against the file.
So in Linux file offset vs. memory offset is the same.
> Stepping through code now shows some of the things you couldn't see,
> like e.g. why is there so->build_id, and where is it being set (you
> couldn't see it being set before as qXfer_library was broken).
There was also a mistake by me I did not notice it.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-04-01 22:39 ` Aleksandar Ristovski
@ 2013-04-01 21:13 ` Aleksandar Ristovski
2013-04-02 13:41 ` Jan Kratochvil
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-01 21:13 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 531 bytes --]
On 13-03-28 04:28 PM, Jan Kratochvil wrote:
>
> Why you make this change? That is unrelated to this patchset, it is a recent
> modification by Pedro.
>
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3546) gdb_byte *buffer;
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3547) char *bufstr;
>
...
>
>
> Otherwise OK for this part but it needs a new post, thanks for catching the
> xrealloc.
>
>
> Thanks,
> Jan
>
Ok,
new patch; removed reversal of Pedro's change.
Thanks,
Aleksandar
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-co.-for-move.patch --]
[-- Type: text/x-patch, Size: 12049 bytes --]
From f2cb5b86d02859c11a229b1b20787b0015bc4c68 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:49:36 -0400
Subject: [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
gdb/linux-tdep.c | 97 ++++++++++++++++++++++++++++++++--------------
gdb/target.c | 113 +++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 152 insertions(+), 58 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 24cc79d..d8ab056 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3476,55 +3476,73 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
- {
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
- xfree (buf);
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
else
*buf_p = buf;
- return buf_pos;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3534,10 +3552,37 @@ target_fileio_read_alloc_1 (const char *filename,
{
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
}
+ }
+}
- QUIT;
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ if (retval >= 0)
+ {
+ /* Returned allocated memory is interesting for the caller. */
+ memory_to_free = NULL;
}
+ do_cleanups (close_cleanup);
+ return retval;
}
/* Read target file FILENAME. Store the result in *BUF_P and return
@@ -3556,14 +3601,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
gdb_byte *buffer;
char *bufstr;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
+ transferred = func (filename, &buffer, 1);
bufstr = (char *) buffer;
if (transferred < 0)
@@ -3587,6 +3635,11 @@ target_fileio_read_stralloc (const char *filename)
return bufstr;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-03-28 23:02 ` Jan Kratochvil
2013-03-29 0:26 ` Aleksandar Ristovski
@ 2013-04-01 22:39 ` Aleksandar Ristovski
2013-04-01 21:13 ` Aleksandar Ristovski
2013-04-02 13:41 ` Jan Kratochvil
1 sibling, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-01 22:39 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 531 bytes --]
On 13-03-28 04:28 PM, Jan Kratochvil wrote:
>
> Why you make this change? That is unrelated to this patchset, it is a recent
> modification by Pedro.
>
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3546) gdb_byte *buffer;
> fad14e531 (Pedro Alves 2013-03-11 12:22:16 +0000 3547) char *bufstr;
>
...
>
>
> Otherwise OK for this part but it needs a new post, thanks for catching the
> xrealloc.
>
>
> Thanks,
> Jan
>
Ok,
new patch; removed reversal of Pedro's change.
Thanks,
Aleksandar
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-co.-for-move.patch --]
[-- Type: text/x-patch, Size: 12049 bytes --]
From f2cb5b86d02859c11a229b1b20787b0015bc4c68 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:49:36 -0400
Subject: [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
gdb/linux-tdep.c | 97 ++++++++++++++++++++++++++++++++--------------
gdb/target.c | 113 +++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 152 insertions(+), 58 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 24cc79d..d8ab056 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3476,55 +3476,73 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
- {
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
- xfree (buf);
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ {
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (buf == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (buf);
+ }
else
*buf_p = buf;
- return buf_pos;
+
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3534,10 +3552,37 @@ target_fileio_read_alloc_1 (const char *filename,
{
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
}
+ }
+}
- QUIT;
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ if (retval >= 0)
+ {
+ /* Returned allocated memory is interesting for the caller. */
+ memory_to_free = NULL;
}
+ do_cleanups (close_cleanup);
+ return retval;
}
/* Read target file FILENAME. Store the result in *BUF_P and return
@@ -3556,14 +3601,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
gdb_byte *buffer;
char *bufstr;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
+ transferred = func (filename, &buffer, 1);
bufstr = (char *) buffer;
if (transferred < 0)
@@ -3587,6 +3635,11 @@ target_fileio_read_stralloc (const char *filename)
return bufstr;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
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
0 siblings, 2 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-01 23:19 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-03-28 04:13 PM, Jan Kratochvil wrote:
> This part should have been in the previous patch. No need to repost but
> please rearrange it during the final check-in.
>
>
> Jan
Done, waiting for your feedback on #4/6 to proceed with commit.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
2013-04-01 23:19 ` Aleksandar Ristovski
@ 2013-04-02 2:33 ` Aleksandar Ristovski
2013-04-02 2:33 ` Jan Kratochvil
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-02 2:33 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
On 13-03-28 04:13 PM, Jan Kratochvil wrote:
> This part should have been in the previous patch. No need to repost but
> please rearrange it during the final check-in.
>
>
> Jan
Done, waiting for your feedback on #4/6 to proceed with commit.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
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
1 sibling, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-04-02 2:33 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Mon, 01 Apr 2013 21:46:05 +0200, Aleksandar Ristovski wrote:
> Done, waiting for your feedback on #4/6 to proceed with commit.
BTW the patchset should get checked in only as a whole, only some parts of it
have no benefit to the user.
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-04-02 13:41 ` Aleksandar Ristovski
@ 2013-04-02 13:41 ` Jan Kratochvil
2013-04-05 15:37 ` Aleksandar Ristovski
0 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-04-02 13:41 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Tue, 02 Apr 2013 15:29:47 +0200, Aleksandar Ristovski wrote:
> Ok, diff from the code at patch 4 (i.e. after applying patches 1-4)
> that I will incorporate into patch 4 is pasted below.
Yes...
> I did not put any assert in target_fileio_read_alloc_1 - I don't
> think it's useful.
I agree.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
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
1 sibling, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-04-02 13:41 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Mon, 01 Apr 2013 21:44:04 +0200, Aleksandar Ristovski wrote:
[...]
> --- a/gdb/target.c
> +++ b/gdb/target.c
[...]
> +static LONGEST
> +target_fileio_read_alloc_1 (const char *filename,
> + gdb_byte **buf_p, int padding)
> +{
> + struct cleanup *close_cleanup;
> + int fd, target_errno;
> + void *memory_to_free = NULL;
> + LONGEST retval;
> +
> + fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
> + if (fd == -1)
> + return -1;
> +
> + close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
> +
> + make_cleanup (free_current_contents, &memory_to_free);
> + retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
> + &memory_to_free);
> + if (retval >= 0)
> + {
> + /* Returned allocated memory is interesting for the caller. */
> + memory_to_free = NULL;
> }
BTW ">= 0" is incorrect, the decision of filled in *BUF_P should be "> 0", see
target_fileio_read_stralloc in FSF GDB:
if (transferred < 0)
return NULL;
if (transferred == 0)
return xstrdup ("");
bufstr[transferred] = 0;
or even the documentation of target_fileio_read_alloc:
If a positive value is returned, a
sufficiently large buffer will be allocated using xmalloc and
returned in *BUF_P containing the contents of the object.
But I find you wrote a workaround of my bug in the code of read_alloc, the
should have been:
if (n < 0 || (n == 0 && buf_pos == 0))
xfree (buf);
else
*buf_p = buf;
if (memory_to_free_ptr != NULL)
*memory_to_free_ptr = NULL;
Then target_fileio_read_alloc_1 can contain just (if you want):
gdb_assert (memory_to_free == NULL);
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-04-02 13:41 ` Jan Kratochvil
@ 2013-04-02 13:41 ` Aleksandar Ristovski
2013-04-02 13:41 ` Jan Kratochvil
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-02 13:41 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On 13-04-02 09:07 AM, Jan Kratochvil wrote:
> On Mon, 01 Apr 2013 21:44:04 +0200, Aleksandar Ristovski wrote:
> [...]
>> --- a/gdb/target.c
>> +++ b/gdb/target.c
> [...]
>> +static LONGEST
>> +target_fileio_read_alloc_1 (const char *filename,
>> + gdb_byte **buf_p, int padding)
>> +{
>> + struct cleanup *close_cleanup;
>> + int fd, target_errno;
>> + void *memory_to_free = NULL;
>> + LONGEST retval;
>> +
>> + fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
>> + if (fd == -1)
>> + return -1;
>> +
>> + close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
>> +
>> + make_cleanup (free_current_contents, &memory_to_free);
>> + retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
>> + &memory_to_free);
>
>
>> + if (retval >= 0)
>> + {
>> + /* Returned allocated memory is interesting for the caller. */
>> + memory_to_free = NULL;
>> }
>
> BTW ">= 0" is incorrect, the decision of filled in *BUF_P should be "> 0", see
> target_fileio_read_stralloc in FSF GDB:
> if (transferred < 0)
> return NULL;
> if (transferred == 0)
> return xstrdup ("");
> bufstr[transferred] = 0;
> or even the documentation of target_fileio_read_alloc:
> If a positive value is returned, a
> sufficiently large buffer will be allocated using xmalloc and
> returned in *BUF_P containing the contents of the object.
>
>
> But I find you wrote a workaround of my bug in the code of read_alloc, the
> should have been:
> if (n < 0 || (n == 0 && buf_pos == 0))
> xfree (buf);
> else
> *buf_p = buf;
> if (memory_to_free_ptr != NULL)
> *memory_to_free_ptr = NULL;
>
> Then target_fileio_read_alloc_1 can contain just (if you want):
> gdb_assert (memory_to_free == NULL);
>
>
Ok, diff from the code at patch 4 (i.e. after applying patches 1-4) that
I will incorporate into patch 4 is pasted below.
I did not put any assert in target_fileio_read_alloc_1 - I don't think
it's useful.
Thanks,
Aleksandar
diff --git a/gdb/target.c b/gdb/target.c
index d8ab056..ed0f3bf 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3522,17 +3522,11 @@ read_alloc (gdb_byte **buf_p, int handle,
read_alloc_pre
if (n <= 0)
{
if (n < 0 || (n == 0 && buf_pos == 0))
- {
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (buf == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (buf);
- }
+ xfree (buf);
else
*buf_p = buf;
-
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = NULL;
if (n < 0)
{
/* An error occurred. */
@@ -3576,11 +3570,6 @@ target_fileio_read_alloc_1 (const char *filename,
make_cleanup (free_current_contents, &memory_to_free);
retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread,
padding,
&memory_to_free);
- if (retval >= 0)
- {
- /* Returned allocated memory is interesting for the caller. */
- memory_to_free = NULL;
- }
do_cleanups (close_cleanup);
return retval;
}
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
[not found] ` <20130331174322.GB21374@host2.jankratochvil.net>
@ 2013-04-02 17:18 ` Aleksandar Ristovski
2013-04-04 2:22 ` Jan Kratochvil
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-02 17:18 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 30398 bytes --]
Attached patch addresses your comments. See inline for details.
On 13-03-31 01:43 PM, Jan Kratochvil wrote:
> On Thu, 28 Mar 2013 21:53:38 +0100, Aleksandar Ristovski wrote:
>> Fixed patch. I haven't addressed any of your concerns except fixed
>> what was broken. There are two things changed:
>>
>> 1) get_dynamic, you will see I left it unfinished when switched to
>> generic "find_phdr" to address phdr traversal duplication code.
>
> I wrote at "find_phdr_p":
> But I do not understand why this function exists
>
> which probably corresponds to this your comment.
>
>
>> 2) lrfind_mapping_entry can not check for vaddr + offset as offset
>> is file offset, and for some shared objects this will not match even
>> though the vaddr of the entry with zero offset is valid.
>
> Oops, you are right:
>
> 7ffff7ddc000-7ffff7dfd000 r-xp 00000000 fd:01 51415762 /usr/lib64/ld-2.17.so
> 7ffff7ffc000-7ffff7ffe000 rw-p 00020000 fd:01 51415762 /usr/lib64/ld-2.17.so
> (gdb) p/x 0x7ffff7ffc000-0x7ffff7ddc000
> $1 = 0x220000
>
> It is mapped by additional displacement of 2MB. Adjustment is suggested below.
>
>
> BTW for gdbserver compatibility I have posted:
> [patch 1/2+7.6] /proc/PID/smaps: filename fix
> http://sourceware.org/ml/gdb-patches/2013-03/msg01120.html
> [patch 2/2+7.6] /proc/PID/smaps: Linux kernel 3.8.3 compat.
> http://sourceware.org/ml/gdb-patches/2013-03/msg01119.html
> but you probably did not face this compat. problem.
>
>
>> Stepping through code now shows some of the things you couldn't see,
>> like e.g. why is there so->build_id, and where is it being set (you
>> couldn't see it being set before as qXfer_library was broken).
>>
>>
>> ---
>> Aleksandar
>>
>>
>>
>> On 13-03-27 04:17 PM, Aleksandar Ristovski wrote:
>>> Addressed Jan's comments.
>>>
>>>
>>>
>>> On 13-03-27 10:50 AM, Jan Kratochvil wrote:
>>>> On Wed, 27 Mar 2013 15:38:29 +0100, Aleksandar Ristovski wrote:
>>>>> On 13-03-26 04:41 PM, Jan Kratochvil wrote:
>>>>>>>> + if (build_id_list_p)
>>>>>>>> + qsort (VEC_address (build_id_list_s, data.list),
>>>>>>>> + VEC_length (build_id_list_s, data.list),
>>>>>>>> + sizeof (build_id_list_s), compare_build_id_list);
>>>>>> It is always already sorted by Linux kernel, rather a for cycle to
>>>>>> verify it
>>>>>> really is sorted.
>>>>>
>>>>> Can we guarantee this is always the case?
>>>>
>>>> Yes.
>>>>
>>>> The problem is that if it is unsorted there is a bug somewhere and
>>>> that qsort
>>>> will hide that bug.
>>>
>>>
>>> Qsort removed. I didn't put any traversal; we are making assumption that
>>> the list will be sorted. The checks in the other bits make sure that we
>>> either find the right mapping or none at all, so worst case scenario is
>>> we don't get build-id communicated to gdb.
>>>
>>>
>>>
>>> Thanks,
>>>
>>> Aleksandar
>>>
>>
>
>> >From 80cd24335bcff6625b5c69c1b2f2d43142db08d1 Mon Sep 17 00:00:00 2001
>> From: Aleksandar Ristovski <ARistovski@qnx.com>
>> Date: Wed, 27 Mar 2013 11:56:57 -0400
>> Subject: [PATCH 6/8] gdbserver build-id attribute generator
>>
>> * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
>> 'build-id' in description, example, new attribute in dtd.
>> * features/library-list-svr4.dtd (library-list-svr4): New
>> 'build-id' attribute.
>> * linux-low.c (linux-maps.h, search.h): Include.
>> (find_phdr_p_ftype, find_phdr, find_phdr_p): New.
>> (get_dynamic): Use find_pdhr to traverse program headers.
>> (struct mapping_entry): New structure.
>> (mapping_entry_s): New typedef, new vector type def.
>> (free_mapping_entry, compare_mapping_entry,
>> compare_mapping_entry_range, compare_mapping_entry_inode): New.
>> (struct find_memory_region_callback_data): New.
>> (find_memory_region_callback): New fwd. declaration.
>> (read_build_id, find_memory_region_callback, get_hex_build_id): New.
>> (linux_qxfer_libraries_svr4): Add optional build-id attribute
>> to reply XML document.
>> ---
>> gdb/doc/gdb.texinfo | 17 +-
>> gdb/features/library-list-svr4.dtd | 13 +-
>> gdb/gdbserver/linux-low.c | 388 +++++++++++++++++++++++++++++++++---
>> 3 files changed, 381 insertions(+), 37 deletions(-)
>>
>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index 38ce259..7c17209 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -40323,6 +40323,8 @@ memory address. It is a displacement of absolute memory address against
>> address the file was prelinked to during the library load.
>> @item
>> @code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
>> +@item
>> +@code{build-id}, hex encoded @code{NT_GNU_BUID_ID} note, if it exists.
>
> Typo: NT_GNU_BUILD_ID
[AR]
Done.
>
>
>> @end itemize
>>
>> Additionally the single @code{main-lm} attribute specifies address of
>> @@ -40340,7 +40342,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
>> </library-list-svr>
>> @end smallexample
>>
>> @@ -40349,13 +40351,14 @@ The format of an SVR4 library list is described by this DTD:
>> @smallexample
>> <!-- library-list-svr4: Root element with versioning -->
>> <!ELEMENT library-list-svr4 (library)*>
>> -<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
>> -<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
>> +<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
>> +<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
>> <!ELEMENT library EMPTY>
>> -<!ATTLIST library name CDATA #REQUIRED>
>> -<!ATTLIST library lm CDATA #REQUIRED>
>> -<!ATTLIST library l_addr CDATA #REQUIRED>
>> -<!ATTLIST library l_ld CDATA #REQUIRED>
>> +<!ATTLIST library name CDATA #REQUIRED>
>> +<!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
>> diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
>> index cae7fd8..fdd6ec0 100644
>> --- a/gdb/features/library-list-svr4.dtd
>> +++ b/gdb/features/library-list-svr4.dtd
>> @@ -6,11 +6,12 @@
>>
>> <!-- library-list-svr4: Root element with versioning -->
>> <!ELEMENT library-list-svr4 (library)*>
>> -<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
>> -<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
>> +<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
>> +<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
>>
>> <!ELEMENT library EMPTY>
>> -<!ATTLIST library name CDATA #REQUIRED>
>> -<!ATTLIST library lm CDATA #REQUIRED>
>> -<!ATTLIST library l_addr CDATA #REQUIRED>
>> -<!ATTLIST library l_ld CDATA #REQUIRED>
>> +<!ATTLIST library name CDATA #REQUIRED>
>> +<!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/linux-low.c b/gdb/gdbserver/linux-low.c
>> index 72c51e0..aa248e9 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>
>> @@ -43,6 +44,7 @@
>> #include "gdb_stat.h"
>> #include <sys/vfs.h>
>> #include <sys/uio.h>
>> +#include <search.h>
>> #ifndef ELFMAG0
>> /* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
>> then ELFMAG0 will have been defined. If it didn't get included by
>> @@ -5432,15 +5434,81 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
>> return 0;
>> }
>>
>> +
>
> Extra empty line, there should be only one empty line.
>
[AR] Ok.
>
>> +/* Predicate function type returns 1 if the given phdr is what is
>> + being looked for. Returns 0 otherwise. */
>> +
>> +typedef int (*find_phdr_p_ftype)(const void *phdr, int is_elf64,
>> + const void *data);
>
> GNU Coding Standards formatting:
> typedef int (*find_phdr_p_ftype) (const void *phdr, int is_elf64,
>
> GDB uses *_ftype types without that * pointer,
> use then find_phdr_p_ftype *find_phdr_p.
[AR] Ok.
>
>> +
>> +/* Linearly traverse pheaders given in PHDR until supplied
> program headers given between PHDR_BEGIN and PHDR_END
>
>> + predicate function returns 1. If supplied predicate function
>> + did return 1, stop traversal and return that PHDR. */
> that program header.
>
>> +
>> +static const void *
>> +find_phdr (int is_elf64, const void *const phdr_begin,
>> + const void *const phdr_end, find_phdr_p_ftype find_phdr_p,
>
> Use find_phdr_p_ftype *find_phdr_p.
>
>> + const void *const data)
>> +{
>> +#define SIZEOFHDR(hdr) (is_elf64? sizeof((hdr)._64) : sizeof((hdr)._32))
>
> GNU Coding Standards formatting:
> #define SIZEOFHDR(hdr) (is_elf64 ? sizeof ((hdr)._64) : sizeof ((hdr)._32))
>
> But in fact I do not see why you define a macro which is used only once.
[AR]: For readability, so the generic part of the code does not mention
"64" or "32".
>
>
>> +#define PHDR_NEXT(hdrp) ((void *) ((char *)(hdrp) + SIZEOFHDR(*hdrp)))
>
> GNU Coding Standards formatting and also parentheses around each macro
> parameter:
> #define PHDR_NEXT(hdrp) ((void *) ((char *) (hdrp) + SIZEOFHDR (*hdrp)))
>
> But as GDB codebase allows void * arithmetics it can be simplified to (also
> putting there const otherwise it deconstifies the passed in pointer):
> #define PHDR_NEXT(hdrp) (((const void *) (hdrp) + SIZEOFHDR (*hdrp)))
[AR]: void* arithmetic is not defined even if gcc allows it. Changed to
casting to const gdb_byte for the arithmetic part.
>
>
>> +
>> + union ElfXX_Phdr
>> + {
>> + Elf32_Phdr _32;
>> + Elf64_Phdr _64;
>> + } const *phdr = phdr_begin;
>> +
>> + if (phdr == NULL)
>> + return NULL;
>> +
>> + while (PHDR_NEXT (phdr) <= phdr_end)
>> + {
>> + if (find_phdr_p (phdr, is_elf64, data) == 1)
>> + return phdr;
>> + phdr = PHDR_NEXT (phdr);
>> + }
>> +
>> + return NULL;
>> +#undef PHDR_NEXT
>> +#undef SIZEOFHDR
>> +}
>> +
>
> Missing function comment.
[AR] Ok.
>
>
>> +
>> +static int
>> +find_phdr_p (const void *const phdr, const int is_elf64,
>> + const void *const data)
>
> But I do not understand why this function exists - it could be integrated in
> find_phdr as very every caller of find_phdr passse as find_phdr_p parameter
> this find_phdr_p implementation.
[AR] Yes, but I am eyeing solib-svr4.c loops over pheaders
generalization - find_phdr could be moved to 'common' and possibly
called 'iterate_phdrs' with the ability to pass in any function, not
necessarily a predicate only. E.g. svr4_exec_displacement, etc...)
>
>
>> +{
>> + const ULONGEST *const type = data;
>> +
>> + if (is_elf64)
>> + {
>> + const Elf64_Phdr *const p = phdr;
>> +
>> + if (p->p_type == *type)
>> + return 1;
>> + }
>> + else
>> + {
>> + const Elf32_Phdr *const p = phdr;
>> +
>> + if (p->p_type == *type)
>> + return 1;
>> + }
>> + return 0;
>> +}
>> +
>> /* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
>>
>> static CORE_ADDR
>> get_dynamic (const int pid, const int is_elf64)
>> {
>> CORE_ADDR phdr_memaddr, relocation;
>> - int num_phdr, i;
>> + int num_phdr;
>> unsigned char *phdr_buf;
>> const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
>> + const void *phdr;
>> + ULONGEST p_type;
>>
>> if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
>> return 0;
>> @@ -5454,21 +5522,24 @@ get_dynamic (const int pid, const int is_elf64)
>> /* Compute relocation: it is expected to be 0 for "regular" executables,
>> non-zero for PIE ones. */
>> relocation = -1;
>> - for (i = 0; relocation == -1 && i < num_phdr; i++)
>> - if (is_elf64)
>> - {
>> - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
>> + p_type = PT_PHDR;
>> + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
>> + find_phdr_p, &p_type);
>> + if (phdr != NULL)
>> + {
>> + if (is_elf64)
>> + {
>> + const Elf64_Phdr *const p = phdr;
>>
>> - if (p->p_type == PT_PHDR)
>> relocation = phdr_memaddr - p->p_vaddr;
>> - }
>> - else
>> - {
>> - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
>> + }
>> + else
>> + {
>> + const Elf32_Phdr *const p = phdr;
>>
>> - if (p->p_type == PT_PHDR)
>> relocation = phdr_memaddr - p->p_vaddr;
>> - }
>> + }
>> + }
>>
>> if (relocation == -1)
>> {
>> @@ -5485,21 +5556,23 @@ get_dynamic (const int pid, const int is_elf64)
>> return 0;
>> }
>>
>> - for (i = 0; i < num_phdr; i++)
>> + p_type = PT_DYNAMIC;
>> + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
>> + find_phdr_p, &p_type);
>> +
>> + if (phdr != NULL)
>> {
>> if (is_elf64)
>> {
>> - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
>> + const Elf64_Phdr *const p = phdr;
>>
>> - if (p->p_type == PT_DYNAMIC)
>> - return p->p_vaddr + relocation;
>> + return p->p_vaddr + relocation;
>> }
>> else
>> {
>> - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
>> + const Elf32_Phdr *const p = phdr;
>>
>> - if (p->p_type == PT_DYNAMIC)
>> - return p->p_vaddr + relocation;
>> + return p->p_vaddr + relocation;
>> }
>> }
>>
>> @@ -5641,6 +5714,255 @@ struct link_map_offsets
>> int l_prev_offset;
>> };
>>
>> +
>> +/* Structure for holding a mapping. Only mapping
>> + containing l_ld can have hex_build_id set.
>> +
>> + Fields are populated from linux_find_memory_region parameters. */
>> +
>> +struct mapping_entry
>> +{
>
> Here should be the line:
> /* Fields are populated from linux_find_memory_region parameters. */
[AR] ok.
>
>
>> + ULONGEST vaddr;
>> + ULONGEST size;
>> + ULONGEST offset;
>> + ULONGEST inode;
>> +
>> + /* Hex encoded string allocated using xmalloc, and
>> + needs to be freed. It can be NULL. */
>> +
>> + char *hex_build_id;
>> +};
>> +
>> +typedef struct mapping_entry mapping_entry_s;
>> +
>> +DEF_VEC_O(mapping_entry_s);
>> +
>> +static void
>> +free_mapping_entry (VEC (mapping_entry_s) *lst)
>> +{
>> + int ix;
>> + mapping_entry_s *p;
>> +
>> + for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix)
>> + xfree (p->hex_build_id);
>> +
>> + VEC_free (mapping_entry_s, lst);
>> +}
>> +
>> +/* Used for finding a mapping containing the given
>> + l_ld passed in K. */
>> +
>> +static int
>> +compare_mapping_entry_range (const void *const k, const void *const b)
>> +{
>> + const ULONGEST key = *(CORE_ADDR*) k;
>> + const mapping_entry_s *const p = b;
>> +
>> + if (key < p->vaddr)
>> + return -1;
>> +
>> + if (key < p->vaddr + p->size)
>> + return 0;
>> +
>> + return 1;
>> +}
>> +
>> +struct find_memory_region_callback_data
>> +{
>> + unsigned is_elf64;
>> +
>> + /* Return. Ordered list of all object mappings sorted in
>> + ascending order by VADDR. Must be freed with free_mapping_entry. */
>> + VEC (mapping_entry_s) *list;
>> +};
>> +
>> +static linux_find_memory_region_ftype find_memory_region_callback;
>> +
>> +/* Read .note.gnu.build-id from PT_NOTE. */
>
> It is NT_GNU_BUILD_ID note from PT_NOTE segment.
>
> .note.gnu.build-id is section name, PT_NOTE is segment name. Those do not
> match.
[AR] ok.
>
>
>> +
>> +static void
>> +read_build_id (struct find_memory_region_callback_data *const p,
>> + mapping_entry_s *const bil, const CORE_ADDR load_addr,
>> + const CORE_ADDR l_addr)
>> +{
>> + union ElfXX_Ehdr
>> + {
>> + Elf32_Ehdr _32;
>> + Elf64_Ehdr _64;
>> + } ehdr;
>> + union ElfXX_Phdr
>> + {
>> + Elf32_Phdr _32;
>> + Elf64_Phdr _64;
>> + } const *phdr;
>> + union ElfXX_Nhdr
>> + {
>> + Elf32_Nhdr _32;
>> + Elf64_Nhdr _64;
>> + } *nhdr;
>> +#define HDR(hdr, fld) (((p)->is_elf64)? (hdr)._64.fld : (hdr)._32.fld)
>> +#define SIZEOFHDR(hdr) (((p)->is_elf64)?sizeof((hdr)._64):sizeof((hdr)._32))
>
> These macros are already defined above, use only one definition. It would be
> appropriate to make their name slightly longer in such case, not required.
[AR]. Moved unions and defines up, removed "undef". Changed naming to be
slightly less prone to collisions and clearer.
>
>
>> + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, SIZEOFHDR (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)
>> + {
>> + void *phdr_buf;
>> + const ULONGEST p_type = PT_NOTE;
>> +
>> + gdb_assert (HDR (ehdr, e_phnum) < 100); /* Basic sanity check. */
>> + gdb_assert (HDR (ehdr, e_phentsize) == SIZEOFHDR (*phdr));
>> + phdr_buf = alloca (HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize));
>> +
>> + if (linux_read_memory (load_addr + HDR (ehdr, e_phoff), phdr_buf,
>> + HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize))
>> + != 0)
>> + {
>> + warning ("Could not read program header.");
>> + return;
>> + }
>> +
>> + phdr = phdr_buf;
>> +
>> + while ((phdr = find_phdr (p->is_elf64, phdr, (char *) phdr_buf
>> + + HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize),
>> + find_phdr_p, &p_type)) != NULL)
>
> phdr_buf is void * and GDB codebase allows void * arithmetics so the cast
> could be removed.
[AR] I really dislike using void* even if gdb uses it. It's not correct.
>
> find_phdr_p probably should not be passed, as discussed above.
[AR] I can remove it, but the idea is to make generic phdr iterator
similar to 'maps' parser.
>
> Assignment needs to be on a separate line according to GNU Coding Standards,
> therefore:
> for (;;)
> {
> phdr = find_phdr (p->is_elf64, phdr,
> (phdr_buf
> + HDR (ehdr, e_phnum) * HDR (ehdr, e_phentsize)),
> find_phdr_p, &p_type);
> if (phdr == NULL)
> break;
>
>
>> + {
>> + void *const pt_note = xmalloc (HDR (*phdr, p_memsz));
>> + const void *const pt_end
>> + = (char*) pt_note + HDR (*phdr, p_memsz);
>
> When it does not fit on a single line use separate declaration line:
> const void *pt_end;
>
> pt_end = (gdb_byte *) pt_note + HDR (*phdr, p_memsz);
>
> And also you use 'char' for byte but GDB - even with recent Pedro's changes
> - prefers to use gdb_byte in such case. It is not a printable character.
>
>
>> +
>> + if (linux_read_memory (HDR (*phdr, p_vaddr) + l_addr,
>> + pt_note, HDR (*phdr, p_memsz)) != 0)
>> + {
>> + xfree (pt_note);
>> + warning ("Could not read note.");
>> + break;
>> + }
>> +
>> + nhdr = pt_note;
>> + while ((void *) nhdr < pt_end)
>> + {
>> + const size_t note_sz
>> + = HDR (*nhdr, n_namesz) + HDR (*nhdr, n_descsz)
>> + + SIZEOFHDR (*nhdr);
>
> Again it is more readable if split, also please keep the order as present in
> the file:
> const size_t note_sz;
>
> note_sz = (SIZEOFHDR (*nhdr) + HDR (*nhdr, n_namesz)
> + HDR (*nhdr, n_descsz));
>
> But there is also missing alignment to 4 bytes of both n_namesz and n_descsz:
> Padding is present, if necessary, to ensure 4-byte alignment for the
> descriptor. Such padding is not included in namesz.
[AR] Ok, code re-arranged; sizes rounded up to appropriate size.
> +
> Padding is present, if necessary, to ensure 4-byte alignment for the
> next note entry. Such padding is not included in descsz.
>
>
>> +
>> + if (((char *) nhdr + note_sz) > (char *) pt_end)
>
> gdb_byte *
>
> And I asked for checking NOTE_SZ == 0 but you still do not check it. If there
> will be NOTE_SZ == 0 then bin2hex below will use the code path:
> /* May use a length, or a nul-terminated string as input. */
> if (count == 0)
> count = strlen ((char *) bin);
>
> which may in a worst case even crash GDB on invalid file running out through
> non-zero bytes out of mapped memory.
[AR] It is now being checked.
>
>
>> + {
>> + warning ("Malformed PT_NOTE\n");
>> + break;
>> + }
>
> You need to check here also the name content, it is "GNU\x00" (n_namesz == 4).
[AR], can it be any other name if type is NT_GNU_BUILD_ID? Added the
check but seems like an overkill to me.
>
>
>> + if (HDR (*nhdr, n_type) == NT_GNU_BUILD_ID)
>> + {
>> + bil->hex_build_id = xmalloc (note_sz * 2 + 1);
>> + bin2hex ((gdb_byte*) nhdr, bil->hex_build_id, note_sz);
>
> I wrote last time:
> GNU Coding Standard formatting:
> bin2hex ((gdb_byte *) nhdr, bil->hex_build_id, note_sz);
>
>
> But this is not the build-id.
>
> readelf -n
> Build ID: 1dfca42f0dac568cf81fedc2a9a37a98789a03e4
>
> vs. gdbserver:
>
> <library name="/lib64/ld-linux-x86-64.so.2" lm="0x7ffff7ffd998" l_addr="0x7ffff7ddc000" l_ld="0x7ffff7ffcdf0" build-id="040000001400000003000000474e55001dfca42f0dac568cf81fedc2a9a37a98789a03e4"/>
>
> You need to send only the real build-id bytes, omitting the note header and the
> note name ("GNU\0").
>
> Then it will not match GDB itself, it also needs to be updated to process only
> the build-id bytes, not the header.
[AR] Ok.
>
>
>> + xfree (pt_note);
>> + return;
>> + }
>> + nhdr = (void*) ((char *) nhdr + note_sz);
>
> I wrote last time:
> GNU Coding Standard formatting + simplification:
> nhdr = (void *) nhdr + note_sz;
[AR] I re-arranged the code. Void * arithmetic is not right, so I'm
avoiding it.
>
>
>> + }
>> + xfree (pt_note);
>> + }
>> + }
>> + else
>> + warning ("Reading build-id failed.");
>
> I would omit these warnings. But otherwise please put there some better
> identifiers, such as vaddr and/or filename. Seeing just many such errors is
> not too useful as I have found during the debugging today.
[AR] Removed the warning.
>
>
>> +#undef HDR
>> +#undef SIZEOFHDR
>> +}
>> +
>> +
>> +/* Add mapping_entry. */
>> +
>> +static int
>> +find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
>> + ULONGEST inode, int read, int write, int exec,
>> + int modified, const char *filename, void *data)
>> +{
>> + if (inode != 0)
>> + {
>> + struct find_memory_region_callback_data *const p = data;
>> + mapping_entry_s bil;
>> +
>> + bil.vaddr = vaddr;
>> + bil.size = size;
>> + bil.offset = offset;
>> + bil.inode = inode;
>> + bil.hex_build_id = NULL;
>> +
>> + VEC_safe_push (mapping_entry_s, p->list, &bil);
>> + }
>> +
>> + /* Continue the traversal. */
>> + return 0;
>> +}
>> +
>> +/* Linear reverse find starting from RBEGIN towards REND looking for
>> + the lowest vaddr mapping of the same inode and zero offset. */
>> +
>> +static mapping_entry_s *
>> +lrfind_mapping_entry (mapping_entry_s *const rbegin,
>> + const mapping_entry_s *const rend)
>> +{
>> + mapping_entry_s *p;
>> +
>> + for (p = rbegin - 1; p >= rend && p->inode == rbegin->inode; --p)
>> + if (p->offset == 0)
>> + return p;
>
> I had here this layout:
> 7ffff7ddc000-7ffff7dfd000 r-xp 00000000 fd:01 51415762 /usr/lib64/ld-2.17.so
> 7ffff7ff9000-7ffff7ffa000 rw-p 00000000 00:00 0
> 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
> 7ffff7ffc000-7ffff7ffe000 rw-p 00020000 fd:01 51415762 /usr/lib64/ld-2.17.so
>
> so it should rather be:
> for (p = rbegin - 1; p >= rend; --p)
> if (p->offset == 0 && p->inode == rbegin->inode)
> return p;
>
> Fortunately it should not have any real performance impact.
[AR] Ok, though we are not adding mappings with inode == 0. See
'find_memory_region_callback'. I changed it anyway, seems a bit more
robust at the expense of rather unlikely event where mapping with offset
0 does not exist.
>
>
>> +
>> + return NULL;
>> +}
>> +
>> +/* Get build-id for the given L_LD. DATA must point to
>> + already filled list of mapping_entry elements.
>> +
>> + Return build_id as stored in the list element corresponding
>> + to L_LD.
>> +
>> + NULL may be returned if build-id could not be fetched.
>> +
>> + Returned string must not be freed explicitly. */
>> +
>> +static const char *
>> +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
>> + struct find_memory_region_callback_data *const data)
>> +{
>> + mapping_entry_s *bil;
>> +
>> + if (VEC_address (mapping_entry_s, data->list) == NULL)
>> + return NULL;
>> +
>> + bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list),
>> + VEC_length (mapping_entry_s, data->list),
>> + sizeof (mapping_entry_s), compare_mapping_entry_range);
>> +
>> + if (bil == NULL)
>> + return NULL;
>> +
>> + if (bil->hex_build_id == NULL)
>> + {
>> + CORE_ADDR load_addr;
>
> This variable declaration should be moved to the more inner block below.
>
>
>> + mapping_entry_s *const bil_min
>> + = lrfind_mapping_entry (bil,
>> + VEC_address (mapping_entry_s, data->list));
>
> When it does not fit the line make the declaration separate, such as:
>
> mapping_entry_s *const bil_min;
>
> bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s,
> data->list));
[AR] Not sure what is the advantage, but ok.
>
> There should be an empty line between declarations and code statements.
>
>> + if (bil_min != NULL)
>> + {
>> + load_addr = bil_min->vaddr;
>> + read_build_id (data, bil, load_addr, l_addr);
>> + }
>> + else
>> + {
>> + /* Do not try to find hex_build_id again. */
>> + bil->hex_build_id = xstrdup ("");
>> + warning ("Could not determine load address; "
>> + "build_id can not be used.");
> build-id
>
> The name of the feature is "build-id" so it always should be presented this
> way to the user. Variable names are not interesting to users.
[AR] Ok. Also, please note the change: I assign BUILD_ID_INVALID here
rather than "" so that we can determine this at document creation time.
I'd rather not emit build-id attribute at all than emitting empty
build-id when it could not be fetched.
>
>
>> + }
>> + }
>> +
>> + return bil->hex_build_id;
>> +}
>> +
>> /* Construct qXfer:libraries-svr4:read reply. */
>>
>> static int
>> @@ -5653,6 +5975,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
>> struct process_info_private *const priv = current_process ()->private;
>> char filename[PATH_MAX];
>> int pid, is_elf64;
>> + struct find_memory_region_callback_data data;
>>
>> static const struct link_map_offsets lmo_32bit_offsets =
>> {
>> @@ -5688,6 +6011,14 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
>> is_elf64 = elf_64_file_p (filename, &machine);
>> lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
>>
>> + data.is_elf64 = is_elf64;
>> + data.list = NULL;
>> + VEC_reserve (mapping_entry_s, data.list, 16);
>> + if (linux_find_memory_regions_full (
>
> There should not be opening paren at the end.
[AR] Ok.
>
>> + lwpid_of (get_thread_lwp (current_inferior)),
>
> When the parameters are too long for proper indentation use a temporary
> variable for the value.
[AR] Ok, used 'pid' which had been there already.
>
>
>> + find_memory_region_callback, &data, NULL) < 0)
>> + warning ("Finding memory regions failed");
>> +
>> if (priv->r_debug == 0)
>> priv->r_debug = get_r_debug (pid, is_elf64);
>>
>> @@ -5762,6 +6093,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
>> /* 6x the size for xml_escape_text below. */
>> size_t len = 6 * strlen ((char *) libname);
>> char *name;
>> + const char *hex_enc_build_id = NULL;
>>
>> if (!header_done)
>> {
>> @@ -5770,21 +6102,28 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
>> header_done = 1;
>> }
>>
>> - while (allocated < p - document + len + 200)
>> + name = xml_escape_text ((char *) libname);
>> + hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
>> +
>> + while (allocated < (p - document + len + 200
>> + + (hex_enc_build_id != NULL
>> + ? strlen (hex_enc_build_id) : 0)))
>> {
>> /* Expand to guarantee sufficient storage. */
>> - uintptr_t document_len = p - document;
>> + const ptrdiff_t document_len = p - document;
>>
>> - document = xrealloc (document, 2 * allocated);
>> allocated *= 2;
>> + document = xrealloc (document, allocated);
>> p = document + document_len;
>> }
>>
>> - name = xml_escape_text ((char *) libname);
>> p += sprintf (p, "<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, "/>");
>> free (name);
>> }
>> else if (lm_prev == 0)
>> @@ -5819,6 +6158,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
>>
>> memcpy (readbuf, document + offset, len);
>> xfree (document);
>> + free_mapping_entry (data.list);
>>
>> return len;
>> }
>> --
>> 1.7.10.4
>>
>
>
>
> Thanks,
> Jan
>
Thanks,
Aleksandar
[-- Attachment #2: 0006-gdbserver-build-id-attribute-generator.patch --]
[-- Type: text/x-patch, Size: 19046 bytes --]
From 799c0ca7884b2f3761762928e23ff755fe7f41b0 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 11:56:57 -0400
Subject: [PATCH 6/8] gdbserver build-id attribute generator
* doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
'build-id' in description, example, new attribute in dtd.
* features/library-list-svr4.dtd (library-list-svr4): New
'build-id' attribute.
* linux-low.c (linux-maps.h, search.h): Include.
(ElfXX_Ehdr, ElfXX_Phdr, ElfXX_Nhdr): New.
(ELFXX_FLD, ELFXX_SIZEOF, ELFXX_ROUNDUP, BUILD_ID_INVALID): New.
(find_phdr_p_ftype, find_phdr, find_phdr_p): New.
(get_dynamic): Use find_pdhr to traverse program headers.
(struct mapping_entry): New structure.
(mapping_entry_s): New typedef, new vector type def.
(free_mapping_entry, compare_mapping_entry,
compare_mapping_entry_range, compare_mapping_entry_inode): New.
(struct find_memory_region_callback_data): New.
(find_memory_region_callback): New fwd. declaration.
(read_build_id, find_memory_region_callback, get_hex_build_id): New.
(linux_qxfer_libraries_svr4): Add optional build-id attribute
to reply XML document.
---
gdb/doc/gdb.texinfo | 17 +-
gdb/features/library-list-svr4.dtd | 13 +-
gdb/gdbserver/linux-low.c | 409 +++++++++++++++++++++++++++++++++---
3 files changed, 402 insertions(+), 37 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3b63d01..25d8eea 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40329,6 +40329,8 @@ memory address. It is a displacement of absolute memory address against
address the file was prelinked to during the library load.
@item
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
+@item
+@code{build-id}, hex encoded @code{NT_GNU_BUILD_ID} note, if it exists.
@end itemize
Additionally the single @code{main-lm} attribute specifies address of
@@ -40346,7 +40348,7 @@ 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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40355,13 +40357,14 @@ The format of an SVR4 library list is described by this DTD:
@smallexample
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..fdd6ec0 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -6,11 +6,12 @@
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..61da37c 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -20,6 +20,7 @@
#include "linux-low.h"
#include "linux-osdata.h"
#include "agent.h"
+#include "linux-maps.h"
#include "gdb_wait.h"
#include <stdio.h>
@@ -43,6 +44,7 @@
#include "gdb_stat.h"
#include <sys/vfs.h>
#include <sys/uio.h>
+#include <search.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -118,6 +120,33 @@ typedef struct
} Elf64_auxv_t;
#endif
+typedef union ElfXX_Ehdr
+{
+ Elf32_Ehdr _32;
+ Elf64_Ehdr _64;
+} ElfXX_Ehdr;
+
+typedef union ElfXX_Phdr
+{
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+} ElfXX_Phdr;
+
+typedef union ElfXX_Nhdr
+{
+ Elf32_Nhdr _32;
+ Elf64_Nhdr _64;
+} ElfXX_Nhdr;
+
+#define ELFXX_FLD(hdr, fld) ((is_elf64) ? (hdr)._64.fld : (hdr)._32.fld)
+#define ELFXX_SIZEOF(hdr) ((is_elf64) ? sizeof ((hdr)._64) \
+ : sizeof ((hdr)._32))
+#define ELFXX_ROUNDUP(what) ((is_elf64) ? (((what) + sizeof (Elf64_Word) - 1) \
+ & ~(sizeof (Elf64_Word) - 1)) \
+ : (((what) + sizeof (Elf32_Word) - 1) \
+ & ~(sizeof (Elf32_Word) - 1)))
+#define BUILD_ID_INVALID "?"
+
/* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol
representation of the thread ID.
@@ -5432,15 +5461,76 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
return 0;
}
+/* Predicate function type returns 1 if the given phdr is what is
+ being looked for. Returns 0 otherwise. */
+
+typedef int (find_phdr_p_ftype) (const void *phdr, int is_elf64,
+ const void *data);
+
+/* Linearly traverse pheaders given in PHDR until supplied
+ predicate function returns 1. If supplied predicate function
+ did return 1, stop traversal and return that PHDR. */
+
+static const void *
+find_phdr (int is_elf64, const void *const phdr_begin,
+ const void *const phdr_end, find_phdr_p_ftype *const find_phdr_p,
+ const void *const data)
+{
+#define PHDR_NEXT(hdrp) ((const void *) ((const gdb_byte *) (hdrp) + \
+ ELFXX_SIZEOF (*hdrp)))
+
+ const ElfXX_Phdr *phdr = phdr_begin;
+
+ if (phdr == NULL)
+ return NULL;
+
+ while (PHDR_NEXT (phdr) <= phdr_end)
+ {
+ if (find_phdr_p (phdr, is_elf64, data) == 1)
+ return phdr;
+ phdr = PHDR_NEXT (phdr);
+ }
+
+ return NULL;
+#undef PHDR_NEXT
+}
+
+/* Predicate function for find_phdr iteration. */
+
+static int
+find_phdr_p (const void *const phdr, const int is_elf64,
+ const void *const data)
+{
+ const ULONGEST *const type = data;
+
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ return 0;
+}
+
/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
static CORE_ADDR
get_dynamic (const int pid, const int is_elf64)
{
CORE_ADDR phdr_memaddr, relocation;
- int num_phdr, i;
+ int num_phdr;
unsigned char *phdr_buf;
const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
+ const void *phdr;
+ ULONGEST p_type;
if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
return 0;
@@ -5454,21 +5544,24 @@ get_dynamic (const int pid, const int is_elf64)
/* Compute relocation: it is expected to be 0 for "regular" executables,
non-zero for PIE ones. */
relocation = -1;
- for (i = 0; relocation == -1 && i < num_phdr; i++)
- if (is_elf64)
- {
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ p_type = PT_PHDR;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+ if (phdr != NULL)
+ {
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
- else
- {
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
+ }
+ }
if (relocation == -1)
{
@@ -5485,21 +5578,23 @@ get_dynamic (const int pid, const int is_elf64)
return 0;
}
- for (i = 0; i < num_phdr; i++)
+ p_type = PT_DYNAMIC;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+
+ if (phdr != NULL)
{
if (is_elf64)
{
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
else
{
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
}
@@ -5641,6 +5736,254 @@ struct link_map_offsets
int l_prev_offset;
};
+
+/* Structure for holding a mapping. Only mapping
+ containing l_ld can have hex_build_id set. */
+
+struct mapping_entry
+{
+ /* Fields are populated from linux_find_memory_region parameters. */
+
+ ULONGEST vaddr;
+ ULONGEST size;
+ ULONGEST offset;
+ ULONGEST inode;
+
+ /* Hex encoded string allocated using xmalloc, and
+ needs to be freed. It can be NULL. */
+
+ char *hex_build_id;
+};
+
+typedef struct mapping_entry mapping_entry_s;
+
+DEF_VEC_O(mapping_entry_s);
+
+static void
+free_mapping_entry (VEC (mapping_entry_s) *lst)
+{
+ int ix;
+ mapping_entry_s *p;
+
+ for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix)
+ xfree (p->hex_build_id);
+
+ VEC_free (mapping_entry_s, lst);
+}
+
+/* Used for finding a mapping containing the given
+ l_ld passed in K. */
+
+static int
+compare_mapping_entry_range (const void *const k, const void *const b)
+{
+ const ULONGEST key = *(CORE_ADDR*) k;
+ const mapping_entry_s *const p = b;
+
+ if (key < p->vaddr)
+ return -1;
+
+ if (key < p->vaddr + p->size)
+ return 0;
+
+ return 1;
+}
+
+struct find_memory_region_callback_data
+{
+ unsigned is_elf64;
+
+ /* Return. Ordered list of all object mappings sorted in
+ ascending order by VADDR. Must be freed with free_mapping_entry. */
+ VEC (mapping_entry_s) *list;
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+/* Read build-id from PT_NOTE. */
+
+static void
+read_build_id (struct find_memory_region_callback_data *const p,
+ mapping_entry_s *const bil, const CORE_ADDR load_addr,
+ const CORE_ADDR l_addr)
+{
+ const int is_elf64 = p->is_elf64;
+ ElfXX_Ehdr ehdr;
+
+ if (linux_read_memory (load_addr, (unsigned char *) &ehdr,
+ ELFXX_SIZEOF (ehdr)) == 0
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG0]) == ELFMAG0
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG1]) == ELFMAG1
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG2]) == ELFMAG2
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG3]) == ELFMAG3)
+ {
+ const ElfXX_Phdr *phdr;
+ void *phdr_buf;
+ const ULONGEST p_type = PT_NOTE;
+ const unsigned e_phentsize = ELFXX_FLD (ehdr, e_phentsize);
+
+ gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); /* Basic sanity check. */
+ gdb_assert (e_phentsize == ELFXX_SIZEOF (*phdr));
+ phdr_buf = alloca (ELFXX_FLD (ehdr, e_phnum) * e_phentsize);
+
+ if (linux_read_memory (load_addr + ELFXX_FLD (ehdr, e_phoff), phdr_buf,
+ ELFXX_FLD (ehdr, e_phnum) * e_phentsize) != 0)
+ {
+ warning ("Could not read program header.");
+ return;
+ }
+
+ phdr = phdr_buf;
+
+ for (;;)
+ {
+ gdb_byte *pt_note;
+ const gdb_byte *pt_end;
+ const ElfXX_Nhdr *nhdr;
+
+ phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf
+ + ELFXX_FLD (ehdr, e_phnum) * e_phentsize,
+ find_phdr_p, &p_type);
+ if (phdr == NULL)
+ break;
+ pt_note = xmalloc (ELFXX_FLD (*phdr, p_memsz));
+ pt_end = (gdb_byte*) pt_note + ELFXX_FLD (*phdr, p_memsz);
+
+ if (linux_read_memory (ELFXX_FLD (*phdr, p_vaddr) + l_addr, pt_note,
+ ELFXX_FLD (*phdr, p_memsz)) != 0)
+ {
+ xfree (pt_note);
+ warning ("Could not read note.");
+ break;
+ }
+
+ nhdr = (void *) pt_note;
+ while ((void *) nhdr < (void *) pt_end)
+ {
+ const size_t namesz
+ = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_namesz));
+ const size_t descsz
+ = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_descsz));
+ const size_t note_sz = ELFXX_SIZEOF (*nhdr) + namesz + descsz;
+
+ if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0
+ || descsz == 0)
+ {
+ warning ("Malformed PT_NOTE\n");
+ break;
+ }
+ if (ELFXX_FLD (*nhdr, n_type) == NT_GNU_BUILD_ID
+ && ELFXX_FLD (*nhdr, n_namesz) == 4)
+ {
+ const char gnu[4] = "GNU\0";
+ const char *const pname
+ = (char *) nhdr + ELFXX_SIZEOF (*nhdr);
+
+ if (memcmp (pname, gnu, 4) == 0)
+ {
+ const size_t n_descsz = ELFXX_FLD (*nhdr, n_descsz);
+
+ bil->hex_build_id = xmalloc (n_descsz * 2 + 1);
+ bin2hex ((gdb_byte*) pname + namesz, bil->hex_build_id,
+ n_descsz);
+ xfree (pt_note);
+ return;
+ }
+ }
+ nhdr = (void*) ((gdb_byte *) nhdr + note_sz);
+ }
+ xfree (pt_note);
+ }
+ }
+}
+
+/* Add mapping_entry. */
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
+ ULONGEST inode, int read, int write, int exec,
+ int modified, const char *filename, void *data)
+{
+ if (inode != 0)
+ {
+ struct find_memory_region_callback_data *const p = data;
+ mapping_entry_s bil;
+
+ bil.vaddr = vaddr;
+ bil.size = size;
+ bil.offset = offset;
+ bil.inode = inode;
+ bil.hex_build_id = NULL;
+
+ VEC_safe_push (mapping_entry_s, p->list, &bil);
+ }
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Linear reverse find starting from RBEGIN towards REND looking for
+ the lowest vaddr mapping of the same inode and zero offset. */
+
+static mapping_entry_s *
+lrfind_mapping_entry (mapping_entry_s *const rbegin,
+ const mapping_entry_s *const rend)
+{
+ mapping_entry_s *p;
+
+ for (p = rbegin - 1; p >= rend; --p)
+ if (p->offset == 0 && p->inode == rbegin->inode)
+ return p;
+
+ return NULL;
+}
+
+/* Get build-id for the given L_LD. DATA must point to
+ already filled list of mapping_entry elements.
+
+ Return build_id as stored in the list element corresponding
+ to L_LD.
+
+ NULL may be returned if build-id could not be fetched.
+
+ Returned string must not be freed explicitly. */
+
+static const char *
+get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
+ struct find_memory_region_callback_data *const data)
+{
+ mapping_entry_s *bil;
+
+ if (VEC_address (mapping_entry_s, data->list) == NULL)
+ return NULL;
+
+ bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list),
+ VEC_length (mapping_entry_s, data->list),
+ sizeof (mapping_entry_s), compare_mapping_entry_range);
+
+ if (bil == NULL)
+ return NULL;
+
+ if (bil->hex_build_id == NULL)
+ {
+ mapping_entry_s *bil_min;
+
+ bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s,
+ data->list));
+ if (bil_min != NULL)
+ read_build_id (data, bil, bil_min->vaddr, l_addr);
+ else
+ {
+ /* Do not try to find hex_build_id again. */
+ bil->hex_build_id = xstrdup (BUILD_ID_INVALID);
+ warning ("Could not determine load address; "
+ "build-id can not be used.");
+ }
+ }
+
+ return bil->hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5653,6 +5996,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
struct process_info_private *const priv = current_process ()->private;
char filename[PATH_MAX];
int pid, is_elf64;
+ struct find_memory_region_callback_data data;
static const struct link_map_offsets lmo_32bit_offsets =
{
@@ -5688,6 +6032,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ data.is_elf64 = is_elf64;
+ data.list = NULL;
+ VEC_reserve (mapping_entry_s, data.list, 16);
+ if (linux_find_memory_regions_full (pid, find_memory_region_callback, &data,
+ NULL) < 0)
+ warning ("Finding memory regions failed");
+
if (priv->r_debug == 0)
priv->r_debug = get_r_debug (pid, is_elf64);
@@ -5762,6 +6113,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ const char *hex_enc_build_id = NULL;
if (!header_done)
{
@@ -5770,21 +6122,29 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
+ while (allocated < (p - document + len + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
+ const ptrdiff_t document_len = p - document;
- document = xrealloc (document, 2 * allocated);
allocated *= 2;
+ document = xrealloc (document, allocated);
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<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
+ && strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0)
+ p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id);
+ p += sprintf(p, "/>");
free (name);
}
else if (lm_prev == 0)
@@ -5819,6 +6179,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
memcpy (readbuf, document + offset, len);
xfree (document);
+ free_mapping_entry (data.list);
return len;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-02 17:18 ` Aleksandar Ristovski
@ 2013-04-04 2:22 ` Jan Kratochvil
2013-04-05 15:05 ` Aleksandar Ristovski
0 siblings, 1 reply; 79+ messages in thread
From: Jan Kratochvil @ 2013-04-04 2:22 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
On Tue, 02 Apr 2013 18:22:48 +0200, Aleksandar Ristovski wrote:
> >>+static int
> >>+find_phdr_p (const void *const phdr, const int is_elf64,
> >>+ const void *const data)
> >
> >But I do not understand why this function exists - it could be integrated in
> >find_phdr as very every caller of find_phdr passse as find_phdr_p parameter
> >this find_phdr_p implementation.
>
>
> [AR] Yes, but I am eyeing solib-svr4.c loops over pheaders
> generalization - find_phdr could be moved to 'common' and possibly
> called 'iterate_phdrs' with the ability to pass in any function, not
> necessarily a predicate only. E.g. svr4_exec_displacement, etc...)
It is not relevant for this patch what do you plan. In the form as is it is
needlessly overcomplicated. That more thorough generalization would be
possibly good but it is not here and it may never happen. GDB will just
remain with needlessly complicated code.
> >You need to check here also the name content, it is "GNU\x00" (n_namesz == 4).
>
> [AR], can it be any other name if type is NT_GNU_BUILD_ID? Added the
> check but seems like an overkill to me.
NT_GNU_BUILD_ID is just number 3. I find very realistic for example
"SUNW Solaris" would use at least 3 note types (does not use it already?).
> >>+/* Linear reverse find starting from RBEGIN towards REND looking for
> >>+ the lowest vaddr mapping of the same inode and zero offset. */
> >>+
> >>+static mapping_entry_s *
> >>+lrfind_mapping_entry (mapping_entry_s *const rbegin,
> >>+ const mapping_entry_s *const rend)
> >>+{
> >>+ mapping_entry_s *p;
> >>+
> >>+ for (p = rbegin - 1; p >= rend && p->inode == rbegin->inode; --p)
> >>+ if (p->offset == 0)
> >>+ return p;
> >
> >I had here this layout:
> >7ffff7ddc000-7ffff7dfd000 r-xp 00000000 fd:01 51415762 /usr/lib64/ld-2.17.so
> >7ffff7ff9000-7ffff7ffa000 rw-p 00000000 00:00 0
> >7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
> >7ffff7ffc000-7ffff7ffe000 rw-p 00020000 fd:01 51415762 /usr/lib64/ld-2.17.so
> >
> >so it should rather be:
> > for (p = rbegin - 1; p >= rend; --p)
> > if (p->offset == 0 && p->inode == rbegin->inode)
> > return p;
> >
> >Fortunately it should not have any real performance impact.
>
> [AR] Ok, though we are not adding mappings with inode == 0. See
> 'find_memory_region_callback'.
Hmm, that's true, I do not see now why it failed for me. But that could be
even non-zero-inode mapping so a change was appropriate.
This is not yet a full review.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch] gdbserver build-id in qxfer_libraries reply
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
` (7 preceding siblings ...)
2013-03-10 21:09 ` [draft patch 5/6] Move linux_find_memory_regions_full & co Jan Kratochvil
@ 2013-04-04 16:08 ` Jan Kratochvil
8 siblings, 0 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-04-04 16:08 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: gdb-patches
Hello Aleksandar,
please post a new version of the patchset, I tried to build an actual local
GIT tree for it but it is no longer easy with so many patches, for example
Message-ID: <515ADD4B.9030409@qnx.com>
does not apply.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 1/6] Move utility functions to common/
2013-04-07 18:54 ` Aleksandar Ristovski
@ 2013-04-05 13:06 ` Aleksandar Ristovski
0 siblings, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 13:06 UTC (permalink / raw)
Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1443 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-03-22 09:03 AM, Aleksandar Ristovski wrote:
> As per the subject...
>
>
> ChangeLog:
>
> * cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to
> common/common-utils.c.
> * cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to
> common/common-utils.h.
> * common/common-utils.c (ctype.h): Include.
> (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move
> from utils.c.
> (fromhex): Copy from remote.c.
> (hex2bin): Move from remote.c.
> (tohex): Copy from remote.c.
> (bin2hex): Move from remote.c.
> (skip_spaces, skip_spaces_const): Move from cli/cli-utils.c.
> * common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved
> from defs.h.
> (strtoulst): Move decl from utils.h.
> (hex2bin, bin2hex): Move decls from remote.h.
> (skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h.
> * defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to
> common/common-utils.h
> * remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c.
> * remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h.
> * utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int,
> strtoulst): Move to common/common-utils.c.
> * utils.h (strtoulst): Moved decl to common/common-utils.h.
>
>
>
> Thanks,
>
> Aleksandar
>
>
[-- Attachment #2: 0001-Move-utility-functions-to-common.patch --]
[-- Type: text/x-patch, Size: 14057 bytes --]
From d2cb04f1e90e14d72a63fa23ec5bb6421cc9e682 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:39:05 -0400
Subject: [PATCH 1/8] Move utility functions to common/
* cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to
common/common-utils.c.
* cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to
common/common-utils.h.
* common/common-utils.c (ctype.h): Include.
(HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move
from utils.c.
(fromhex): Copy from remote.c.
(hex2bin): Move from remote.c.
(tohex): Copy from remote.c.
(bin2hex): Move from remote.c.
(skip_spaces, skip_spaces_const): Move from cli/cli-utils.c.
* common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved
from defs.h.
(strtoulst): Move decl from utils.h.
(hex2bin, bin2hex): Move decls from remote.h.
(skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h.
* defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to
common/common-utils.h
* remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c.
* remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h.
* utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int,
strtoulst): Move to common/common-utils.c.
* utils.h (strtoulst): Moved decl to common/common-utils.h.
---
gdb/cli/cli-utils.c | 24 ------
gdb/cli/cli-utils.h | 9 ---
gdb/common/common-utils.c | 187 +++++++++++++++++++++++++++++++++++++++++++++
gdb/common/common-utils.h | 34 +++++++++
gdb/defs.h | 19 -----
gdb/remote.c | 36 ---------
gdb/remote.h | 4 -
gdb/utils.c | 99 ------------------------
gdb/utils.h | 2 -
9 files changed, 221 insertions(+), 193 deletions(-)
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index f74e6b1..60f7553 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -213,30 +213,6 @@ number_is_in_list (char *list, int number)
/* See documentation in cli-utils.h. */
-char *
-skip_spaces (char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* A const-correct version of the above. */
-
-const char *
-skip_spaces_const (const char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* See documentation in cli-utils.h. */
-
const char *
skip_to_space_const (const char *chp)
{
diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h
index 152fb89..2a8850d 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -89,15 +89,6 @@ extern int get_number_or_range (struct get_number_or_range_state *state);
extern int number_is_in_list (char *list, int number);
-/* Skip leading whitespace characters in INP, returning an updated
- pointer. If INP is NULL, return NULL. */
-
-extern char *skip_spaces (char *inp);
-
-/* A const-correct version of the above. */
-
-extern const char *skip_spaces_const (const char *inp);
-
/* Skip leading non-whitespace characters in INP, returning an updated
pointer. If INP is NULL, return NULL. */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 4204abf..5e96692 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
/* The xmalloc() (libiberty.h) family of memory management routines.
@@ -161,3 +162,189 @@ 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. */
+
+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;
+}
+
+/* See documentation in cli-utils.h. */
+
+char *
+skip_spaces (char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
+
+/* A const-correct version of the above. */
+
+const char *
+skip_spaces_const (const char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 9b659d8..ee7870e 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -25,6 +25,25 @@
#include <stddef.h>
#include <stdarg.h>
+/* Static target-system-dependent parameters for GDB. */
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) then use it to set
+ the number of bits in a host char. If not, use the same size
+ as the target. */
+
+#if defined (CHAR_BIT)
+#define HOST_CHAR_BIT CHAR_BIT
+#else
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif
+
extern void malloc_failure (long size) ATTRIBUTE_NORETURN;
extern void internal_error (const char *file, int line, const char *, ...)
ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 4);
@@ -53,4 +72,19 @@ int xsnprintf (char *str, size_t size, const char *format, ...)
char *savestring (const char *ptr, size_t len);
+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+extern int hex2bin (const char *hex, gdb_byte *bin, int count);
+
+extern int bin2hex (const gdb_byte *bin, char *hex, int count);
+
+/* Skip leading whitespace characters in INP, returning an updated
+ pointer. If INP is NULL, return NULL. */
+
+extern char *skip_spaces (char *inp);
+
+/* A const-correct version of the above. */
+
+extern const char *skip_spaces_const (const char *inp);
+
#endif
diff --git a/gdb/defs.h b/gdb/defs.h
index d8a1adb..ec7e4f3 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -648,25 +648,6 @@ extern void *alloca ();
enum { MAX_REGISTER_SIZE = 64 };
-/* Static target-system-dependent parameters for GDB. */
-
-/* Number of bits in a char or unsigned char for the target machine.
- Just like CHAR_BIT in <limits.h> but describes the target machine. */
-#if !defined (TARGET_CHAR_BIT)
-#define TARGET_CHAR_BIT 8
-#endif
-
-/* If we picked up a copy of CHAR_BIT from a configuration file
- (which may get it by including <limits.h>) then use it to set
- the number of bits in a host char. If not, use the same size
- as the target. */
-
-#if defined (CHAR_BIT)
-#define HOST_CHAR_BIT CHAR_BIT
-#else
-#define HOST_CHAR_BIT TARGET_CHAR_BIT
-#endif
-
/* In findvar.c. */
extern LONGEST extract_signed_integer (const gdb_byte *, int,
diff --git a/gdb/remote.c b/gdb/remote.c
index aefbcf1..6a11652 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4569,25 +4569,6 @@ fromhex (int a)
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
@@ -4599,23 +4580,6 @@ tohex (int nib)
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/remote.h b/gdb/remote.h
index b95370c..d49b427 100644
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -39,10 +39,6 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever);
extern int putpkt (char *buf);
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
extern void async_remote_interrupt_twice (void *arg);
diff --git a/gdb/utils.c b/gdb/utils.c
index a222c59..e1ced2c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3233,105 +3233,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 ad5bea4..e3b6fbf 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
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 3/6] Create empty common/linux-maps.[ch]
2013-03-22 14:54 ` [patch " Aleksandar Ristovski
2013-03-22 13:06 ` Aleksandar Ristovski
@ 2013-04-05 13:25 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 13:25 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 581 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-03-22 09:04 AM, Aleksandar Ristovski wrote:
> As per the subject...
>
>
> * Makefile.in (HFILES_NO_SRCDIR); Add common/linux-maps.h.
> (linux-maps.o): New.
> * common/linux-maps.c: New file.
> * common/linux-maps.h: New file.
> * config/i386/linux.mh (NATDEPFILES): Add linux-maps.o.
> * config/i386/linux64.m (NATDEPFILES): Add linux-maps.o.
> * gdbserver/Makefile.in (linux-maps.o): New.
> * gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o.
>
> ---
> Aleksandar
>
[-- Attachment #2: 0003-Create-empty-common-linux-maps.-ch.patch --]
[-- Type: text/x-patch, Size: 14732 bytes --]
From 8e669398ba8fc885551cbf4920f03b99cf96a16c Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:40:24 -0400
Subject: [PATCH 3/8] Create empty common/linux-maps.[ch]
* Makefile.in (HFILES_NO_SRCDIR); Add common/linux-maps.h.
(linux-maps.o): New.
* common/linux-maps.c: New file.
* common/linux-maps.h: New file.
* config/i386/linux.mh (NATDEPFILES): Add linux-maps.o.
* config/i386/linux64.m (NATDEPFILES): Add linux-maps.o.
* gdbserver/Makefile.in (linux-maps.o): New.
* gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o.
---
gdb/Makefile.in | 6 +++-
gdb/common/linux-maps.c | 25 ++++++++++++++
gdb/common/linux-maps.h | 22 ++++++++++++
gdb/config/i386/linux.mh | 2 +-
gdb/config/i386/linux64.mh | 2 +-
gdb/gdbserver/Makefile.in | 3 ++
gdb/gdbserver/configure.srv | 79 ++++++++++++++++++++++++++++++++-----------
7 files changed, 117 insertions(+), 22 deletions(-)
create mode 100644 gdb/common/linux-maps.c
create mode 100644 gdb/common/linux-maps.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 47b4338..8b1bca6 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -772,7 +772,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 \
@@ -1948,6 +1948,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/linux-maps.c b/gdb/common/linux-maps.c
new file mode 100644
index 0000000..efb0875
--- /dev/null
+++ b/gdb/common/linux-maps.c
@@ -0,0 +1,25 @@
+/* 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"
+#else
+#include "defs.h"
+#endif
+
+#include "linux-maps.h"
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
new file mode 100644
index 0000000..da426e5
--- /dev/null
+++ b/gdb/common/linux-maps.h
@@ -0,0 +1,22 @@
+/* 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
+
+#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 7c64e83..e34f1dc 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 \
linux-btrace.o
NAT_CDEPS = $(srcdir)/proc-service.list
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index 8d782c1..78ecf30 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 linux-btrace.o
NAT_FILE= config/nm-linux.h
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 08db2cc..37d11a2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -512,6 +512,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 271a0fe..4de099b 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 linux-btrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -147,12 +159,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
@@ -162,7 +178,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
@@ -173,7 +191,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
@@ -183,7 +203,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"
@@ -216,7 +239,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"
@@ -262,7 +287,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"
@@ -283,14 +310,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
@@ -307,15 +338,20 @@ 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="${srv_tgtobj} linux-ptrace.o linux-btrace.o"
+ srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o"
+ srv_tgtobj="${srv_tgtobj} linux-x86-low.o i386-low.o"
+ srv_tgtobj="${srv_tgtobj} i387-fp.o linux-procfs.o"
+ srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+ srv_tgtobj="${srv_tgtobj} linux-btrace.o"
srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
srv_linux_usrregs=yes # This is for i386 progs.
srv_linux_regsets=yes
@@ -334,13 +370,18 @@ 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_regobj="${srv_regobj} reg-tilegx32.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
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-04 2:22 ` Jan Kratochvil
@ 2013-04-05 15:05 ` Aleksandar Ristovski
2013-04-09 15:28 ` Gary Benson
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 15:05 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2754 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-04-03 03:32 PM, Jan Kratochvil wrote:
> On Tue, 02 Apr 2013 18:22:48 +0200, Aleksandar Ristovski wrote:
>>>> +static int
>>>> +find_phdr_p (const void *const phdr, const int is_elf64,
>>>> + const void *const data)
>>>
>>> But I do not understand why this function exists - it could be integrated in
>>> find_phdr as very every caller of find_phdr passse as find_phdr_p parameter
>>> this find_phdr_p implementation.
>>
>>
>> [AR] Yes, but I am eyeing solib-svr4.c loops over pheaders
>> generalization - find_phdr could be moved to 'common' and possibly
>> called 'iterate_phdrs' with the ability to pass in any function, not
>> necessarily a predicate only. E.g. svr4_exec_displacement, etc...)
>
> It is not relevant for this patch what do you plan. In the form as is it is
> needlessly overcomplicated. That more thorough generalization would be
> possibly good but it is not here and it may never happen. GDB will just
> remain with needlessly complicated code.
>
>
>
>>> You need to check here also the name content, it is "GNU\x00" (n_namesz == 4).
>>
>> [AR], can it be any other name if type is NT_GNU_BUILD_ID? Added the
>> check but seems like an overkill to me.
>
> NT_GNU_BUILD_ID is just number 3. I find very realistic for example
> "SUNW Solaris" would use at least 3 note types (does not use it already?).
>
>
>>>> +/* Linear reverse find starting from RBEGIN towards REND looking for
>>>> + the lowest vaddr mapping of the same inode and zero offset. */
>>>> +
>>>> +static mapping_entry_s *
>>>> +lrfind_mapping_entry (mapping_entry_s *const rbegin,
>>>> + const mapping_entry_s *const rend)
>>>> +{
>>>> + mapping_entry_s *p;
>>>> +
>>>> + for (p = rbegin - 1; p >= rend && p->inode == rbegin->inode; --p)
>>>> + if (p->offset == 0)
>>>> + return p;
>>>
>>> I had here this layout:
>>> 7ffff7ddc000-7ffff7dfd000 r-xp 00000000 fd:01 51415762 /usr/lib64/ld-2.17.so
>>> 7ffff7ff9000-7ffff7ffa000 rw-p 00000000 00:00 0
>>> 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
>>> 7ffff7ffc000-7ffff7ffe000 rw-p 00020000 fd:01 51415762 /usr/lib64/ld-2.17.so
>>>
>>> so it should rather be:
>>> for (p = rbegin - 1; p >= rend; --p)
>>> if (p->offset == 0 && p->inode == rbegin->inode)
>>> return p;
>>>
>>> Fortunately it should not have any real performance impact.
>>
>> [AR] Ok, though we are not adding mappings with inode == 0. See
>> 'find_memory_region_callback'.
>
> Hmm, that's true, I do not see now why it failed for me. But that could be
> even non-zero-inode mapping so a change was appropriate.
>
>
> This is not yet a full review.
>
>
> Thanks,
> Jan
>
[-- Attachment #2: 0006-gdbserver-build-id-attribute-generator.patch --]
[-- Type: text/x-patch, Size: 19046 bytes --]
From 8a176b511f358b82d5b1f4c5556a501b62bf6dc6 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 11:56:57 -0400
Subject: [PATCH 6/8] gdbserver build-id attribute generator
* doc/gdb.texinfo (Library List Format for SVR4 Targets): Add
'build-id' in description, example, new attribute in dtd.
* features/library-list-svr4.dtd (library-list-svr4): New
'build-id' attribute.
* linux-low.c (linux-maps.h, search.h): Include.
(ElfXX_Ehdr, ElfXX_Phdr, ElfXX_Nhdr): New.
(ELFXX_FLD, ELFXX_SIZEOF, ELFXX_ROUNDUP, BUILD_ID_INVALID): New.
(find_phdr_p_ftype, find_phdr, find_phdr_p): New.
(get_dynamic): Use find_pdhr to traverse program headers.
(struct mapping_entry): New structure.
(mapping_entry_s): New typedef, new vector type def.
(free_mapping_entry, compare_mapping_entry,
compare_mapping_entry_range, compare_mapping_entry_inode): New.
(struct find_memory_region_callback_data): New.
(find_memory_region_callback): New fwd. declaration.
(read_build_id, find_memory_region_callback, get_hex_build_id): New.
(linux_qxfer_libraries_svr4): Add optional build-id attribute
to reply XML document.
---
gdb/doc/gdb.texinfo | 17 +-
gdb/features/library-list-svr4.dtd | 13 +-
gdb/gdbserver/linux-low.c | 409 +++++++++++++++++++++++++++++++++---
3 files changed, 402 insertions(+), 37 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8ae7259..0002d23 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40354,6 +40354,8 @@ memory address. It is a displacement of absolute memory address against
address the file was prelinked to during the library load.
@item
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
+@item
+@code{build-id}, hex encoded @code{NT_GNU_BUILD_ID} note, if it exists.
@end itemize
Additionally the single @code{main-lm} attribute specifies address of
@@ -40371,7 +40373,7 @@ looks like this:
<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="9afccf7cc41e6293476223fe72480854"/>
</library-list-svr>
@end smallexample
@@ -40380,13 +40382,14 @@ The format of an SVR4 library list is described by this DTD:
@smallexample
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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
diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd
index cae7fd8..fdd6ec0 100644
--- a/gdb/features/library-list-svr4.dtd
+++ b/gdb/features/library-list-svr4.dtd
@@ -6,11 +6,12 @@
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
<!ELEMENT library EMPTY>
-<!ATTLIST library name CDATA #REQUIRED>
-<!ATTLIST library lm CDATA #REQUIRED>
-<!ATTLIST library l_addr CDATA #REQUIRED>
-<!ATTLIST library l_ld CDATA #REQUIRED>
+<!ATTLIST library name CDATA #REQUIRED>
+<!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/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..61da37c 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -20,6 +20,7 @@
#include "linux-low.h"
#include "linux-osdata.h"
#include "agent.h"
+#include "linux-maps.h"
#include "gdb_wait.h"
#include <stdio.h>
@@ -43,6 +44,7 @@
#include "gdb_stat.h"
#include <sys/vfs.h>
#include <sys/uio.h>
+#include <search.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@@ -118,6 +120,33 @@ typedef struct
} Elf64_auxv_t;
#endif
+typedef union ElfXX_Ehdr
+{
+ Elf32_Ehdr _32;
+ Elf64_Ehdr _64;
+} ElfXX_Ehdr;
+
+typedef union ElfXX_Phdr
+{
+ Elf32_Phdr _32;
+ Elf64_Phdr _64;
+} ElfXX_Phdr;
+
+typedef union ElfXX_Nhdr
+{
+ Elf32_Nhdr _32;
+ Elf64_Nhdr _64;
+} ElfXX_Nhdr;
+
+#define ELFXX_FLD(hdr, fld) ((is_elf64) ? (hdr)._64.fld : (hdr)._32.fld)
+#define ELFXX_SIZEOF(hdr) ((is_elf64) ? sizeof ((hdr)._64) \
+ : sizeof ((hdr)._32))
+#define ELFXX_ROUNDUP(what) ((is_elf64) ? (((what) + sizeof (Elf64_Word) - 1) \
+ & ~(sizeof (Elf64_Word) - 1)) \
+ : (((what) + sizeof (Elf32_Word) - 1) \
+ & ~(sizeof (Elf32_Word) - 1)))
+#define BUILD_ID_INVALID "?"
+
/* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol
representation of the thread ID.
@@ -5432,15 +5461,76 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
return 0;
}
+/* Predicate function type returns 1 if the given phdr is what is
+ being looked for. Returns 0 otherwise. */
+
+typedef int (find_phdr_p_ftype) (const void *phdr, int is_elf64,
+ const void *data);
+
+/* Linearly traverse pheaders given in PHDR until supplied
+ predicate function returns 1. If supplied predicate function
+ did return 1, stop traversal and return that PHDR. */
+
+static const void *
+find_phdr (int is_elf64, const void *const phdr_begin,
+ const void *const phdr_end, find_phdr_p_ftype *const find_phdr_p,
+ const void *const data)
+{
+#define PHDR_NEXT(hdrp) ((const void *) ((const gdb_byte *) (hdrp) + \
+ ELFXX_SIZEOF (*hdrp)))
+
+ const ElfXX_Phdr *phdr = phdr_begin;
+
+ if (phdr == NULL)
+ return NULL;
+
+ while (PHDR_NEXT (phdr) <= phdr_end)
+ {
+ if (find_phdr_p (phdr, is_elf64, data) == 1)
+ return phdr;
+ phdr = PHDR_NEXT (phdr);
+ }
+
+ return NULL;
+#undef PHDR_NEXT
+}
+
+/* Predicate function for find_phdr iteration. */
+
+static int
+find_phdr_p (const void *const phdr, const int is_elf64,
+ const void *const data)
+{
+ const ULONGEST *const type = data;
+
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
+
+ if (p->p_type == *type)
+ return 1;
+ }
+ return 0;
+}
+
/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
static CORE_ADDR
get_dynamic (const int pid, const int is_elf64)
{
CORE_ADDR phdr_memaddr, relocation;
- int num_phdr, i;
+ int num_phdr;
unsigned char *phdr_buf;
const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
+ const void *phdr;
+ ULONGEST p_type;
if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
return 0;
@@ -5454,21 +5544,24 @@ get_dynamic (const int pid, const int is_elf64)
/* Compute relocation: it is expected to be 0 for "regular" executables,
non-zero for PIE ones. */
relocation = -1;
- for (i = 0; relocation == -1 && i < num_phdr; i++)
- if (is_elf64)
- {
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ p_type = PT_PHDR;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+ if (phdr != NULL)
+ {
+ if (is_elf64)
+ {
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
- else
- {
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ }
+ else
+ {
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_PHDR)
relocation = phdr_memaddr - p->p_vaddr;
- }
+ }
+ }
if (relocation == -1)
{
@@ -5485,21 +5578,23 @@ get_dynamic (const int pid, const int is_elf64)
return 0;
}
- for (i = 0; i < num_phdr; i++)
+ p_type = PT_DYNAMIC;
+ phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
+ find_phdr_p, &p_type);
+
+ if (phdr != NULL)
{
if (is_elf64)
{
- Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf64_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
else
{
- Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+ const Elf32_Phdr *const p = phdr;
- if (p->p_type == PT_DYNAMIC)
- return p->p_vaddr + relocation;
+ return p->p_vaddr + relocation;
}
}
@@ -5641,6 +5736,254 @@ struct link_map_offsets
int l_prev_offset;
};
+
+/* Structure for holding a mapping. Only mapping
+ containing l_ld can have hex_build_id set. */
+
+struct mapping_entry
+{
+ /* Fields are populated from linux_find_memory_region parameters. */
+
+ ULONGEST vaddr;
+ ULONGEST size;
+ ULONGEST offset;
+ ULONGEST inode;
+
+ /* Hex encoded string allocated using xmalloc, and
+ needs to be freed. It can be NULL. */
+
+ char *hex_build_id;
+};
+
+typedef struct mapping_entry mapping_entry_s;
+
+DEF_VEC_O(mapping_entry_s);
+
+static void
+free_mapping_entry (VEC (mapping_entry_s) *lst)
+{
+ int ix;
+ mapping_entry_s *p;
+
+ for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix)
+ xfree (p->hex_build_id);
+
+ VEC_free (mapping_entry_s, lst);
+}
+
+/* Used for finding a mapping containing the given
+ l_ld passed in K. */
+
+static int
+compare_mapping_entry_range (const void *const k, const void *const b)
+{
+ const ULONGEST key = *(CORE_ADDR*) k;
+ const mapping_entry_s *const p = b;
+
+ if (key < p->vaddr)
+ return -1;
+
+ if (key < p->vaddr + p->size)
+ return 0;
+
+ return 1;
+}
+
+struct find_memory_region_callback_data
+{
+ unsigned is_elf64;
+
+ /* Return. Ordered list of all object mappings sorted in
+ ascending order by VADDR. Must be freed with free_mapping_entry. */
+ VEC (mapping_entry_s) *list;
+};
+
+static linux_find_memory_region_ftype find_memory_region_callback;
+
+/* Read build-id from PT_NOTE. */
+
+static void
+read_build_id (struct find_memory_region_callback_data *const p,
+ mapping_entry_s *const bil, const CORE_ADDR load_addr,
+ const CORE_ADDR l_addr)
+{
+ const int is_elf64 = p->is_elf64;
+ ElfXX_Ehdr ehdr;
+
+ if (linux_read_memory (load_addr, (unsigned char *) &ehdr,
+ ELFXX_SIZEOF (ehdr)) == 0
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG0]) == ELFMAG0
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG1]) == ELFMAG1
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG2]) == ELFMAG2
+ && ELFXX_FLD (ehdr, e_ident[EI_MAG3]) == ELFMAG3)
+ {
+ const ElfXX_Phdr *phdr;
+ void *phdr_buf;
+ const ULONGEST p_type = PT_NOTE;
+ const unsigned e_phentsize = ELFXX_FLD (ehdr, e_phentsize);
+
+ gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); /* Basic sanity check. */
+ gdb_assert (e_phentsize == ELFXX_SIZEOF (*phdr));
+ phdr_buf = alloca (ELFXX_FLD (ehdr, e_phnum) * e_phentsize);
+
+ if (linux_read_memory (load_addr + ELFXX_FLD (ehdr, e_phoff), phdr_buf,
+ ELFXX_FLD (ehdr, e_phnum) * e_phentsize) != 0)
+ {
+ warning ("Could not read program header.");
+ return;
+ }
+
+ phdr = phdr_buf;
+
+ for (;;)
+ {
+ gdb_byte *pt_note;
+ const gdb_byte *pt_end;
+ const ElfXX_Nhdr *nhdr;
+
+ phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf
+ + ELFXX_FLD (ehdr, e_phnum) * e_phentsize,
+ find_phdr_p, &p_type);
+ if (phdr == NULL)
+ break;
+ pt_note = xmalloc (ELFXX_FLD (*phdr, p_memsz));
+ pt_end = (gdb_byte*) pt_note + ELFXX_FLD (*phdr, p_memsz);
+
+ if (linux_read_memory (ELFXX_FLD (*phdr, p_vaddr) + l_addr, pt_note,
+ ELFXX_FLD (*phdr, p_memsz)) != 0)
+ {
+ xfree (pt_note);
+ warning ("Could not read note.");
+ break;
+ }
+
+ nhdr = (void *) pt_note;
+ while ((void *) nhdr < (void *) pt_end)
+ {
+ const size_t namesz
+ = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_namesz));
+ const size_t descsz
+ = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_descsz));
+ const size_t note_sz = ELFXX_SIZEOF (*nhdr) + namesz + descsz;
+
+ if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0
+ || descsz == 0)
+ {
+ warning ("Malformed PT_NOTE\n");
+ break;
+ }
+ if (ELFXX_FLD (*nhdr, n_type) == NT_GNU_BUILD_ID
+ && ELFXX_FLD (*nhdr, n_namesz) == 4)
+ {
+ const char gnu[4] = "GNU\0";
+ const char *const pname
+ = (char *) nhdr + ELFXX_SIZEOF (*nhdr);
+
+ if (memcmp (pname, gnu, 4) == 0)
+ {
+ const size_t n_descsz = ELFXX_FLD (*nhdr, n_descsz);
+
+ bil->hex_build_id = xmalloc (n_descsz * 2 + 1);
+ bin2hex ((gdb_byte*) pname + namesz, bil->hex_build_id,
+ n_descsz);
+ xfree (pt_note);
+ return;
+ }
+ }
+ nhdr = (void*) ((gdb_byte *) nhdr + note_sz);
+ }
+ xfree (pt_note);
+ }
+ }
+}
+
+/* Add mapping_entry. */
+
+static int
+find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
+ ULONGEST inode, int read, int write, int exec,
+ int modified, const char *filename, void *data)
+{
+ if (inode != 0)
+ {
+ struct find_memory_region_callback_data *const p = data;
+ mapping_entry_s bil;
+
+ bil.vaddr = vaddr;
+ bil.size = size;
+ bil.offset = offset;
+ bil.inode = inode;
+ bil.hex_build_id = NULL;
+
+ VEC_safe_push (mapping_entry_s, p->list, &bil);
+ }
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Linear reverse find starting from RBEGIN towards REND looking for
+ the lowest vaddr mapping of the same inode and zero offset. */
+
+static mapping_entry_s *
+lrfind_mapping_entry (mapping_entry_s *const rbegin,
+ const mapping_entry_s *const rend)
+{
+ mapping_entry_s *p;
+
+ for (p = rbegin - 1; p >= rend; --p)
+ if (p->offset == 0 && p->inode == rbegin->inode)
+ return p;
+
+ return NULL;
+}
+
+/* Get build-id for the given L_LD. DATA must point to
+ already filled list of mapping_entry elements.
+
+ Return build_id as stored in the list element corresponding
+ to L_LD.
+
+ NULL may be returned if build-id could not be fetched.
+
+ Returned string must not be freed explicitly. */
+
+static const char *
+get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
+ struct find_memory_region_callback_data *const data)
+{
+ mapping_entry_s *bil;
+
+ if (VEC_address (mapping_entry_s, data->list) == NULL)
+ return NULL;
+
+ bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list),
+ VEC_length (mapping_entry_s, data->list),
+ sizeof (mapping_entry_s), compare_mapping_entry_range);
+
+ if (bil == NULL)
+ return NULL;
+
+ if (bil->hex_build_id == NULL)
+ {
+ mapping_entry_s *bil_min;
+
+ bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s,
+ data->list));
+ if (bil_min != NULL)
+ read_build_id (data, bil, bil_min->vaddr, l_addr);
+ else
+ {
+ /* Do not try to find hex_build_id again. */
+ bil->hex_build_id = xstrdup (BUILD_ID_INVALID);
+ warning ("Could not determine load address; "
+ "build-id can not be used.");
+ }
+ }
+
+ return bil->hex_build_id;
+}
+
/* Construct qXfer:libraries-svr4:read reply. */
static int
@@ -5653,6 +5996,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
struct process_info_private *const priv = current_process ()->private;
char filename[PATH_MAX];
int pid, is_elf64;
+ struct find_memory_region_callback_data data;
static const struct link_map_offsets lmo_32bit_offsets =
{
@@ -5688,6 +6032,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ data.is_elf64 = is_elf64;
+ data.list = NULL;
+ VEC_reserve (mapping_entry_s, data.list, 16);
+ if (linux_find_memory_regions_full (pid, find_memory_region_callback, &data,
+ NULL) < 0)
+ warning ("Finding memory regions failed");
+
if (priv->r_debug == 0)
priv->r_debug = get_r_debug (pid, is_elf64);
@@ -5762,6 +6113,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
/* 6x the size for xml_escape_text below. */
size_t len = 6 * strlen ((char *) libname);
char *name;
+ const char *hex_enc_build_id = NULL;
if (!header_done)
{
@@ -5770,21 +6122,29 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
header_done = 1;
}
- while (allocated < p - document + len + 200)
+ name = xml_escape_text ((char *) libname);
+ hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
+ while (allocated < (p - document + len + 200
+ + (hex_enc_build_id != NULL
+ ? strlen (hex_enc_build_id) : 0)))
{
/* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
+ const ptrdiff_t document_len = p - document;
- document = xrealloc (document, 2 * allocated);
allocated *= 2;
+ document = xrealloc (document, allocated);
p = document + document_len;
}
- name = xml_escape_text ((char *) libname);
p += sprintf (p, "<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
+ && strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0)
+ p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id);
+ p += sprintf(p, "/>");
free (name);
}
else if (lm_prev == 0)
@@ -5819,6 +6179,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
memcpy (readbuf, document + offset, len);
xfree (document);
+ free_mapping_entry (data.list);
return len;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-04-02 13:41 ` Jan Kratochvil
@ 2013-04-05 15:37 ` Aleksandar Ristovski
2013-04-07 14:28 ` Aleksandar Ristovski
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 15:37 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 439 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-04-02 09:39 AM, Jan Kratochvil wrote:
> On Tue, 02 Apr 2013 15:29:47 +0200, Aleksandar Ristovski wrote:
>> Ok, diff from the code at patch 4 (i.e. after applying patches 1-4)
>> that I will incorporate into patch 4 is pasted below.
>
> Yes...
>
>
>> I did not put any assert in target_fileio_read_alloc_1 - I don't
>> think it's useful.
>
> I agree.
>
>
> Thanks,
> Jan
>
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-co.-for-move.patch --]
[-- Type: text/x-patch, Size: 11958 bytes --]
From 9114031f08b95f2267ed47139aebf047a35edf20 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:49:36 -0400
Subject: [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
gdb/linux-tdep.c | 97 ++++++++++++++++++++++++++++++++++++---------------
gdb/target.c | 102 ++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 141 insertions(+), 58 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 24cc79d..ed0f3bf 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3476,55 +3476,67 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
- {
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
+ if (n < 0 || (n == 0 && buf_pos == 0))
xfree (buf);
else
*buf_p = buf;
- return buf_pos;
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = NULL;
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3534,12 +3546,34 @@ target_fileio_read_alloc_1 (const char *filename,
{
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
}
-
- QUIT;
}
}
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ do_cleanups (close_cleanup);
+ return retval;
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and return
the size of the transferred data. See the declaration in "target.h"
function for more information about the return value. */
@@ -3556,14 +3590,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
gdb_byte *buffer;
char *bufstr;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
+ transferred = func (filename, &buffer, 1);
bufstr = (char *) buffer;
if (transferred < 0)
@@ -3587,6 +3624,11 @@ target_fileio_read_stralloc (const char *filename)
return bufstr;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
2013-04-07 18:54 ` Aleksandar Ristovski
@ 2013-04-05 15:37 ` Aleksandar Ristovski
0 siblings, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 15:37 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 364 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-04-01 03:56 PM, Jan Kratochvil wrote:
> On Mon, 01 Apr 2013 21:46:05 +0200, Aleksandar Ristovski wrote:
>> Done, waiting for your feedback on #4/6 to proceed with commit.
>
> BTW the patchset should get checked in only as a whole, only some parts of it
> have no benefit to the user.
>
>
> Jan
>
[-- Attachment #2: 0005-Move-linux_find_memory_regions_full-co.patch --]
[-- Type: text/x-patch, Size: 19239 bytes --]
From 43124b3998f6eb8985e828d0fd78107fd0d1e7e4 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:54:36 -0400
Subject: [PATCH 5/8] Move linux_find_memory_regions_full & co.
* common/common-utils.c (read_alloc, read_stralloc): Move definitions
from target.c.
* common/common-utils.h (read_alloc_pread_ftype): New typedef.
(read_alloc): New declaration.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): New declaration.
* common/linux-maps.c (fcntl.h, unistd.h, target.h, gdb_assert.h,
ctype.h, string.h): Include.
(read_mapping): Move from linux-tdep.c.
(linux_find_memory_read_stralloc_1_pread): New function.
(linux_find_memory_read_stralloc_1): New function.
(linux_find_memory_read_stralloc): New function.
* common/linux-maps.h (read_mapping): New declaration.
(linux_find_memory_region_ftype): Moved typedef from linux-tdep.c.
(linux_find_memory_regions_full): New declaration.
* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to common/linux-maps.c.
(linux_find_memory_region_ftype): Moved typedef to common/linux-maps.h.
(linux_find_memory_regions_full): Moved definition to
common/linux-maps.c.
* target.c (read_alloc_pread_ftype): Moved typedef to
common/common-utils.h.
(read_alloc, read_stralloc): Moved definitions to
common/common-utils.c.
---
gdb/common/common-utils.c | 88 +++++++++++++++++++++
gdb/common/common-utils.h | 11 +++
gdb/common/linux-maps.c | 186 +++++++++++++++++++++++++++++++++++++++++++++
gdb/common/linux-maps.h | 25 ++++++
gdb/linux-tdep.c | 148 +-----------------------------------
gdb/target.c | 93 -----------------------
6 files changed, 311 insertions(+), 240 deletions(-)
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index c123ed7..31234fa 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -348,3 +348,91 @@ skip_spaces_const (const char *chp)
chp++;
return chp;
}
+
+LONGEST
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
+{
+ size_t buf_alloc, buf_pos;
+ gdb_byte *buf;
+ LONGEST n;
+ int target_errno;
+
+ /* Start by reading up to 4K at a time. The target will throttle
+ this number down if necessary. */
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
+ buf_pos = 0;
+ while (1)
+ {
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
+ {
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ xfree (buf);
+ else
+ *buf_p = buf;
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = NULL;
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
+ }
+
+ buf_pos += n;
+
+ /* If the buffer is filling up, expand it. */
+ if (buf_alloc < buf_pos * 2)
+ {
+ buf_alloc *= 2;
+ buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
+ }
+ }
+}
+
+char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
+{
+ gdb_byte *buffer;
+ char *bufstr;
+ LONGEST i, transferred;
+
+ transferred = func (filename, &buffer, 1);
+ bufstr = (char *) buffer;
+
+ if (transferred < 0)
+ return NULL;
+
+ if (transferred == 0)
+ return xstrdup ("");
+
+ bufstr[transferred] = 0;
+
+ /* Check for embedded NUL bytes; but allow trailing NULs. */
+ for (i = strlen (bufstr); i < transferred; i++)
+ if (bufstr[i] != 0)
+ {
+ warning (_("target file %s "
+ "contained unexpected null characters"),
+ filename);
+ break;
+ }
+
+ return bufstr;
+}
+
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 2c95d34..c7f8162 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -91,4 +91,15 @@ extern char *skip_spaces (char *inp);
extern const char *skip_spaces_const (const char *inp);
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
+ read_alloc_pread_ftype *pread_func, int padding,
+ void **memory_to_free_ptr);
+
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+extern char *read_stralloc (const char *filename,
+ read_stralloc_func_ftype *func);
+
#endif
diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c
index efb0875..a2566e1 100644
--- a/gdb/common/linux-maps.c
+++ b/gdb/common/linux-maps.c
@@ -18,8 +18,194 @@
#ifdef GDBSERVER
#include "server.h"
+#include <fcntl.h>
+#include <unistd.h>
#else
#include "defs.h"
+#include "target.h"
#endif
#include "linux-maps.h"
+#include "gdb_assert.h"
+#include <ctype.h>
+#include <string.h>
+
+/* 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);
+
+ p = skip_spaces_const (p);
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ p = skip_spaces_const (p);
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ p = skip_spaces_const (p);
+ *filename = p;
+}
+
+#ifdef GDBSERVER
+
+static int
+linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf,
+ int len, ULONGEST offset,
+ int *target_errno)
+{
+ int retval = pread (handle, read_buf, len, offset);
+
+ *target_errno = errno;
+ return retval;
+}
+
+static LONGEST
+linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p,
+ int padding)
+{
+ int fd;
+ LONGEST retval;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread,
+ padding, NULL);
+
+ close (fd);
+
+ return retval;
+}
+
+#endif /* GDBSERVER */
+
+static char *
+linux_find_memory_read_stralloc (const char *filename)
+{
+#ifndef GDBSERVER
+ return target_fileio_read_stralloc (filename);
+#else /* GDBSERVER */
+ return read_stralloc (filename, linux_find_memory_read_stralloc_1);
+#endif /* GDBSERVER */
+}
+
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
+
+int
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
+
+ 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. */
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
+ }
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
+ }
+
+ return -1;
+}
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
index da426e5..e989376 100644
--- a/gdb/common/linux-maps.h
+++ b/gdb/common/linux-maps.h
@@ -19,4 +19,29 @@
#ifndef COMMON_LINUX_MAPS_H
#define COMMON_LINUX_MAPS_H
+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);
+
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
+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);
+
+extern int
+ linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr);
+
#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index c48f4ec..4544e5f 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,44 +208,6 @@ 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);
-
- p = skip_spaces_const (p);
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- p = skip_spaces_const (p);
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- p = skip_spaces_const (p);
- *filename = p;
-}
-
/* Implement the "info proc" command. */
static void
@@ -661,115 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
-/* Callback function for linux_find_memory_regions_full. If it returns
- non-zero linux_find_memory_regions_full returns immediately with that
- value. */
-
-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 PID for a corefile. Call FUNC
- with FUNC_DATA for each such region. Return immediately with the
- value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
- be registered to be freed automatically if called FUNC throws an
- exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
- not used. Return -1 if error occurs, 0 if all memory regions have
- been processed or return the value from FUNC if FUNC returns
- non-zero. */
-
-static int
-linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
- void *func_data, void **memory_to_free_ptr)
-{
- char filename[100];
- char *data;
-
- xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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", (int) pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- char *line;
- int retval = 0;
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = data;
- }
-
- 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. */
- retval = func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, func_data);
- if (retval != 0)
- break;
- }
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (data == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (data);
- return retval;
- }
-
- return -1;
-}
-
/* A structure for passing information through
linux_find_memory_regions_full. */
diff --git a/gdb/target.c b/gdb/target.c
index ed0f3bf..0dbac02 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3493,65 +3493,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
target_fileio_read_alloc; see the declaration of that function for more
information. */
-typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
- ULONGEST offset, int *target_errno);
-
-static LONGEST
-read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
- int padding, void **memory_to_free_ptr)
-{
- size_t buf_alloc, buf_pos;
- gdb_byte *buf;
- LONGEST n;
- int target_errno;
-
- /* Start by reading up to 4K at a time. The target will throttle
- this number down if necessary. */
- buf_alloc = 4096;
- buf = xmalloc (buf_alloc);
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = buf;
- }
- buf_pos = 0;
- while (1)
- {
- n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
- buf_pos, &target_errno);
- if (n <= 0)
- {
- if (n < 0 || (n == 0 && buf_pos == 0))
- xfree (buf);
- else
- *buf_p = buf;
- if (memory_to_free_ptr != NULL)
- *memory_to_free_ptr = NULL;
- if (n < 0)
- {
- /* An error occurred. */
- return -1;
- }
- else
- {
- /* Read all there was. */
- return buf_pos;
- }
- }
-
- buf_pos += n;
-
- /* If the buffer is filling up, expand it. */
- if (buf_alloc < buf_pos * 2)
- {
- buf_alloc *= 2;
- buf = xrealloc (buf, buf_alloc);
- if (memory_to_free_ptr != NULL)
- *memory_to_free_ptr = buf;
- }
- }
-}
-
static LONGEST
target_fileio_read_alloc_1 (const char *filename,
gdb_byte **buf_p, int padding)
@@ -3590,40 +3531,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
- gdb_byte **buf_p, int padding);
-
-static char *
-read_stralloc (const char *filename, read_stralloc_func_ftype *func)
-{
- gdb_byte *buffer;
- char *bufstr;
- LONGEST i, transferred;
-
- transferred = func (filename, &buffer, 1);
- bufstr = (char *) buffer;
-
- if (transferred < 0)
- return NULL;
-
- if (transferred == 0)
- return xstrdup ("");
-
- bufstr[transferred] = 0;
-
- /* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (bufstr); i < transferred; i++)
- if (bufstr[i] != 0)
- {
- warning (_("target file %s "
- "contained unexpected null characters"),
- filename);
- break;
- }
-
- return bufstr;
-}
-
char *
target_fileio_read_stralloc (const char *filename)
{
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 2/6] Merge multiple hex conversions
2013-03-22 13:05 ` [patch " Aleksandar Ristovski
@ 2013-04-05 16:07 ` Aleksandar Ristovski
0 siblings, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-05 16:07 UTC (permalink / raw)
Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1050 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-03-22 09:04 AM, Aleksandar Ristovski wrote:
> As per the subject...
>
>
> (tohex): Make externally linkable.
> * common/common-utils.h (fromhex, tohex): New declaration.
> * gdbserver/gdbreplay.c (tohex): Rename to 'fromhex'.
> (logchar): Use fromhex.
> * gdbserver/remote-utils.c (fromhex, unhexify): Remove.
> (tohex, hexify): Remove.
> (look_up_one_symbol, monitor_output): Use bin2hex instead of hexify.
> * gdbserver/server.c (handle_query): Use bin2hex instead of hexify.
> (handle_v_run): Ditto.
> * gdbserver/server.h (unhexify, hexify): Remove declarations.
> * gdbserver/tracepoint.c (cmd_qtdpsrc, cmd_qtdv): Use hex2bin
> instead of unhexify.
> (cmd_qtstatus): Use bin2hex instead of hexify.
> (cmd_qtnotes): Use hex2bin instead of unhexify.
> * monitor.c (fromhex): Remove definition.
> * remote.c (tohex, fromhex): Remove fwd declarations, remove
> definitions.
> ---
>
> Aleksandar
>
[-- Attachment #2: 0002-Merge-multiple-hex-conversions.patch --]
[-- Type: text/x-patch, Size: 11878 bytes --]
From 84429b051840a96e81ca41772fd0dc87d21b8960 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:39:05 -0400
Subject: [PATCH 2/8] Merge multiple hex conversions
* common/common-utils.h (fromhex, tohex): New declaration.
* gdbserver/gdbreplay.c (tohex): Rename to 'fromhex'.
(logchar): Use fromhex.
* gdbserver/remote-utils.c (fromhex, unhexify): Remove.
(tohex, hexify): Remove.
(look_up_one_symbol, monitor_output): Use bin2hex instead of hexify.
* gdbserver/server.c (handle_query): Use bin2hex instead of hexify.
(handle_v_run): Ditto.
* gdbserver/server.h (unhexify, hexify): Remove declarations.
* gdbserver/tracepoint.c (cmd_qtdpsrc, cmd_qtdv): Use hex2bin
instead of unhexify.
(cmd_qtstatus): Use bin2hex instead of hexify.
(cmd_qtnotes): Use hex2bin instead of unhexify.
* monitor.c (fromhex): Remove definition.
* remote.c (tohex, fromhex): Remove fwd declarations, remove
definitions.
---
gdb/common/common-utils.c | 6 ++--
gdb/common/common-utils.h | 4 +++
gdb/gdbserver/gdbreplay.c | 6 ++--
gdb/gdbserver/remote-utils.c | 67 ++----------------------------------------
gdb/gdbserver/server.c | 5 ++--
gdb/gdbserver/server.h | 2 --
gdb/gdbserver/tracepoint.c | 16 +++++-----
gdb/monitor.c | 15 ----------
gdb/remote.c | 30 -------------------
9 files changed, 24 insertions(+), 127 deletions(-)
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 5e96692..c123ed7 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -264,7 +264,7 @@ strtoulst (const char *num, const char **trailer, int base)
/* Convert hex digit A to a number. */
-static int
+int
fromhex (int a)
{
if (a >= '0' && a <= '9')
@@ -274,7 +274,7 @@ fromhex (int a)
else if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
else
- error (_("Reply contains invalid hex digit %d"), a);
+ error (_("Invalid hex digit %d"), a);
}
int
@@ -298,7 +298,7 @@ hex2bin (const char *hex, gdb_byte *bin, int count)
/* Convert number NIB to a hex digit. */
-static int
+int
tohex (int nib)
{
if (nib < 10)
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index ee7870e..2c95d34 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -74,6 +74,10 @@ char *savestring (const char *ptr, size_t len);
ULONGEST strtoulst (const char *num, const char **trailer, int base);
+extern int fromhex (int a);
+
+extern int tohex (int nib);
+
extern int hex2bin (const char *hex, gdb_byte *bin, int count);
extern int bin2hex (const gdb_byte *bin, char *hex, int count);
diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c
index 0aa52d8..d0ff8c4 100644
--- a/gdb/gdbserver/gdbreplay.c
+++ b/gdb/gdbserver/gdbreplay.c
@@ -273,7 +273,7 @@ remote_open (char *name)
}
static int
-tohex (int ch)
+fromhex (int ch)
{
if (ch >= '0' && ch <= '9')
{
@@ -336,11 +336,11 @@ logchar (FILE *fp)
ch2 = fgetc (fp);
fputc (ch2, stdout);
fflush (stdout);
- ch = tohex (ch2) << 4;
+ ch = fromhex (ch2) << 4;
ch2 = fgetc (fp);
fputc (ch2, stdout);
fflush (stdout);
- ch |= tohex (ch2);
+ ch |= fromhex (ch2);
break;
default:
/* Treat any other char as just itself */
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 42c6a54..6ff491e 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -416,20 +416,6 @@ remote_close (void)
reset_readchar ();
}
-/* 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";
@@ -457,25 +443,6 @@ ishex (int ch, int *val)
#ifndef IN_PROCESS_AGENT
-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;
-}
-
void
decode_address (CORE_ADDR *addrp, const char *start, int len)
{
@@ -511,37 +478,8 @@ 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;
-}
-
/* Convert BUFFER, binary data at least LEN bytes long, into escaped
binary data in OUT_BUF. Set *OUT_LEN to the length of the data
encoded in OUT_BUF, and return the number of bytes in OUT_BUF
@@ -1608,7 +1546,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
/* Send the request. */
strcpy (own_buf, "qSymbol:");
- hexify (own_buf + strlen ("qSymbol:"), name, strlen (name));
+ bin2hex ((const gdb_byte *) name, own_buf + strlen ("qSymbol:"),
+ strlen (name));
if (putpkt (own_buf) < 0)
return -1;
@@ -1770,7 +1709,7 @@ monitor_output (const char *msg)
char *buf = xmalloc (strlen (msg) * 2 + 2);
buf[0] = 'O';
- hexify (buf + 1, msg, 0);
+ bin2hex ((const gdb_byte *) msg, buf + 1, 0);
putpkt (buf);
free (buf);
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6bb36d8..8b586dd 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1920,7 +1920,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
return;
}
- if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2)
+ if ((len % 2) != 0
+ || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2)
{
write_enn (own_buf);
free (mon);
@@ -2214,7 +2215,7 @@ handle_v_run (char *own_buf)
{
/* FIXME: Fail request if out of memory instead of dying. */
new_argv[i] = xmalloc (1 + (next_p - p) / 2);
- unhexify (new_argv[i], p, (next_p - p) / 2);
+ hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
new_argv[i][(next_p - p) / 2] = '\0';
}
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 139cd49..5e16088 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -322,8 +322,6 @@ int decode_search_memory_packet (const char *buf, int packet_len,
gdb_byte *pattern,
unsigned int *pattern_lenp);
-int unhexify (char *bin, const char *hex, int count);
-int hexify (char *hex, const char *bin, int count);
int remote_escape_output (const gdb_byte *buffer, int len,
gdb_byte *out_buf, int *out_len,
int out_maxlen);
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 419765b..f48e3b6 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -2679,7 +2679,7 @@ cmd_qtdpsrc (char *own_buf)
packet = unpack_varlen_hex (packet, &slen);
++packet; /* skip a colon */
src = xmalloc (slen + 1);
- nbytes = unhexify (src, packet, strlen (packet) / 2);
+ nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2);
src[nbytes] = '\0';
newlast = xmalloc (sizeof (struct source_string));
@@ -2721,7 +2721,7 @@ cmd_qtdv (char *own_buf)
nbytes = strlen (packet) / 2;
varname = xmalloc (nbytes + 1);
- nbytes = unhexify (varname, packet, nbytes);
+ nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes);
varname[nbytes] = '\0';
tsv = create_trace_state_variable (num, 1);
@@ -3594,17 +3594,17 @@ cmd_qtstatus (char *packet)
str = (tracing_user_name ? tracing_user_name : "");
slen = strlen (str);
buf1 = (char *) alloca (slen * 2 + 1);
- hexify (buf1, str, slen);
+ bin2hex ((const gdb_byte *) str, buf1, slen);
str = (tracing_notes ? tracing_notes : "");
slen = strlen (str);
buf2 = (char *) alloca (slen * 2 + 1);
- hexify (buf2, str, slen);
+ bin2hex ((const gdb_byte *) str, buf2, slen);
str = (tracing_stop_note ? tracing_stop_note : "");
slen = strlen (str);
buf3 = (char *) alloca (slen * 2 + 1);
- hexify (buf3, str, slen);
+ bin2hex ((const gdb_byte *) str, buf3, slen);
trace_debug ("Returning trace status as %d, stop reason %s",
tracing, tracing_stop_reason);
@@ -4078,7 +4078,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
user = xmalloc (nbytes + 1);
- nbytes = unhexify (user, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) user, nbytes);
user[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("User is '%s'", user);
@@ -4092,7 +4092,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
notes = xmalloc (nbytes + 1);
- nbytes = unhexify (notes, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes);
notes[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("Notes is '%s'", notes);
@@ -4106,7 +4106,7 @@ cmd_qtnotes (char *own_buf)
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
stopnote = xmalloc (nbytes + 1);
- nbytes = unhexify (stopnote, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes);
stopnote[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("tstop note is '%s'", stopnote);
diff --git a/gdb/monitor.c b/gdb/monitor.c
index 0337075..c3c623b 100644
--- a/gdb/monitor.c
+++ b/gdb/monitor.c
@@ -226,21 +226,6 @@ monitor_error (char *function, char *message,
message, safe_string);
}
-/* 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 (_("Invalid hex digit %d"), a);
-}
-
/* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses
This function exists to get around the problem that many host platforms
diff --git a/gdb/remote.c b/gdb/remote.c
index 6a11652..31d20d2 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -126,8 +126,6 @@ static void remote_serial_write (const char *str, int len);
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);
@@ -184,8 +182,6 @@ static void remote_find_new_threads (void);
static void record_currthread (ptid_t currthread);
-static int fromhex (int a);
-
static int putpkt_binary (char *buf, int cnt);
static void check_binary_download (CORE_ADDR addr);
@@ -4554,32 +4550,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);
-}
-
-/* Convert number NIB to a hex digit. */
-
-static int
-tohex (int nib)
-{
- if (nib < 10)
- return '0' + nib;
- else
- return 'a' + nib - 10;
-}
-
\f
/* Check for the availability of vCont. This function should also check
the response. */
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 4/6] Prepare linux_find_memory_regions_full & co. for move
2013-04-05 15:37 ` Aleksandar Ristovski
@ 2013-04-07 14:28 ` Aleksandar Ristovski
0 siblings, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-07 14:28 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 439 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-04-02 09:39 AM, Jan Kratochvil wrote:
> On Tue, 02 Apr 2013 15:29:47 +0200, Aleksandar Ristovski wrote:
>> Ok, diff from the code at patch 4 (i.e. after applying patches 1-4)
>> that I will incorporate into patch 4 is pasted below.
>
> Yes...
>
>
>> I did not put any assert in target_fileio_read_alloc_1 - I don't
>> think it's useful.
>
> I agree.
>
>
> Thanks,
> Jan
>
[-- Attachment #2: 0004-Prepare-linux_find_memory_regions_full-co.-for-move.patch --]
[-- Type: text/x-patch, Size: 11958 bytes --]
From 9114031f08b95f2267ed47139aebf047a35edf20 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:49:36 -0400
Subject: [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move
* linux-tdep.c (linux_find_memory_region_ftype): Comment.
(linux_find_memory_regions_full): Change signature and prepare
for moving to linux-maps.
(linux_find_memory_regions_data): Rename field 'obfd' to 'data'.
(linux_find_memory_regions_thunk): New.
(linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'.
(linux_find_memory_regions_gdb): New.
(linux_find_memory_regions): Rename argument 'obfd' to 'func_data'.
(linux_make_mappings_corefile_notes): Use
linux_find_memory_regions_gdb.
* target.c (target_fileio_read_alloc_1_pread): New function.
(read_alloc_pread_ftype): New typedef.
(read_alloc): Refactor from target_fileio_read_alloc_1.
(target_fileio_read_alloc_1): New implementation. Use read_alloc.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): Refactored from target_fileio_read_stralloc.
(target_fileio_read_stralloc): New implementation, use read_stralloc.
---
gdb/linux-tdep.c | 97 ++++++++++++++++++++++++++++++++++++---------------
gdb/target.c | 102 ++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 141 insertions(+), 58 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a132fc6..c48f4ec 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
@@ -668,34 +672,40 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
-/* List memory regions in the inferior for a corefile. */
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
static int
-linux_find_memory_regions_full (struct gdbarch *gdbarch,
- linux_find_memory_region_ftype *func,
- void *obfd)
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
{
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;
+ char *data;
- xsnprintf (filename, sizeof filename,
- "/proc/%d/smaps", current_inferior ()->pid);
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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);
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
data = target_fileio_read_stralloc (filename);
}
if (data)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
line = strtok (data, "\n");
while (line)
@@ -742,15 +752,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
modified = 1;
/* Invoke the callback function to create the corefile segment. */
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
}
- do_cleanups (cleanup);
- return 0;
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
}
- return 1;
+ return -1;
}
/* A structure for passing information through
@@ -764,9 +781,11 @@ struct linux_find_memory_regions_data
/* The original datum. */
- void *obfd;
+ void *data;
};
+static linux_find_memory_region_ftype linux_find_memory_regions_thunk;
+
/* A callback for linux_find_memory_regions that converts between the
"full"-style callback and find_memory_region_ftype. */
@@ -778,7 +797,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
{
struct linux_find_memory_regions_data *data = arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, data->data);
+}
+
+/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
+
+static int
+linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
+ linux_find_memory_region_ftype *func,
+ void *func_data)
+{
+ void *memory_to_free = NULL;
+ struct cleanup *cleanup;
+ int retval;
+
+ /* We need to know the real target PID so
+ linux_find_memory_regions_full can access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ cleanup = make_cleanup (free_current_contents, &memory_to_free);
+ retval = linux_find_memory_regions_full (current_inferior ()->pid,
+ func, func_data, &memory_to_free);
+ do_cleanups (cleanup);
+ return retval;
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -786,16 +828,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
static int
linux_find_memory_regions (struct gdbarch *gdbarch,
- find_memory_region_ftype func, void *obfd)
+ find_memory_region_ftype func, void *func_data)
{
struct linux_find_memory_regions_data data;
data.func = func;
- data.obfd = obfd;
+ data.data = func_data;
- return linux_find_memory_regions_full (gdbarch,
- linux_find_memory_regions_thunk,
- &data);
+ return linux_find_memory_regions_gdb (gdbarch,
+ linux_find_memory_regions_thunk, &data);
}
/* Determine which signal stopped execution. */
@@ -977,8 +1018,8 @@ 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);
+ linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
+ &mapping_data);
if (mapping_data.file_count != 0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 24cc79d..ed0f3bf 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3476,55 +3476,67 @@ target_fileio_close_cleanup (void *opaque)
target_fileio_close (fd, &target_errno);
}
+/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
+
+static int
+target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno)
+{
+ QUIT;
+
+ return target_fileio_pread (handle, read_buf, len, offset, target_errno);
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and
return the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for
target_fileio_read_alloc; see the declaration of that function for more
information. */
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+
static LONGEST
-target_fileio_read_alloc_1 (const char *filename,
- gdb_byte **buf_p, int padding)
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
{
- struct cleanup *close_cleanup;
size_t buf_alloc, buf_pos;
gdb_byte *buf;
LONGEST n;
- int fd;
int target_errno;
- fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
- if (fd == -1)
- return -1;
-
- close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
/* Start by reading up to 4K at a time. The target will throttle
this number down if necessary. */
buf_alloc = 4096;
buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
buf_pos = 0;
while (1)
{
- n = target_fileio_pread (fd, &buf[buf_pos],
- buf_alloc - buf_pos - padding, buf_pos,
- &target_errno);
- if (n < 0)
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
{
- /* An error occurred. */
- do_cleanups (close_cleanup);
- xfree (buf);
- return -1;
- }
- else if (n == 0)
- {
- /* Read all there was. */
- do_cleanups (close_cleanup);
- if (buf_pos == 0)
+ if (n < 0 || (n == 0 && buf_pos == 0))
xfree (buf);
else
*buf_p = buf;
- return buf_pos;
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = NULL;
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
}
buf_pos += n;
@@ -3534,12 +3546,34 @@ target_fileio_read_alloc_1 (const char *filename,
{
buf_alloc *= 2;
buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
}
-
- QUIT;
}
}
+static LONGEST
+target_fileio_read_alloc_1 (const char *filename,
+ gdb_byte **buf_p, int padding)
+{
+ struct cleanup *close_cleanup;
+ int fd, target_errno;
+ void *memory_to_free = NULL;
+ LONGEST retval;
+
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno);
+ if (fd == -1)
+ return -1;
+
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
+
+ make_cleanup (free_current_contents, &memory_to_free);
+ retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding,
+ &memory_to_free);
+ do_cleanups (close_cleanup);
+ return retval;
+}
+
/* Read target file FILENAME. Store the result in *BUF_P and return
the size of the transferred data. See the declaration in "target.h"
function for more information about the return value. */
@@ -3556,14 +3590,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-char *
-target_fileio_read_stralloc (const char *filename)
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+
+static char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
{
gdb_byte *buffer;
char *bufstr;
LONGEST i, transferred;
- transferred = target_fileio_read_alloc_1 (filename, &buffer, 1);
+ transferred = func (filename, &buffer, 1);
bufstr = (char *) buffer;
if (transferred < 0)
@@ -3587,6 +3624,11 @@ target_fileio_read_stralloc (const char *filename)
return bufstr;
}
+char *
+target_fileio_read_stralloc (const char *filename)
+{
+ return read_stralloc (filename, target_fileio_read_alloc_1);
+}
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 1/6] Move utility functions to common/
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
1 sibling, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-07 18:54 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1443 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-03-22 09:03 AM, Aleksandar Ristovski wrote:
> As per the subject...
>
>
> ChangeLog:
>
> * cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to
> common/common-utils.c.
> * cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to
> common/common-utils.h.
> * common/common-utils.c (ctype.h): Include.
> (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move
> from utils.c.
> (fromhex): Copy from remote.c.
> (hex2bin): Move from remote.c.
> (tohex): Copy from remote.c.
> (bin2hex): Move from remote.c.
> (skip_spaces, skip_spaces_const): Move from cli/cli-utils.c.
> * common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved
> from defs.h.
> (strtoulst): Move decl from utils.h.
> (hex2bin, bin2hex): Move decls from remote.h.
> (skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h.
> * defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to
> common/common-utils.h
> * remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c.
> * remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h.
> * utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int,
> strtoulst): Move to common/common-utils.c.
> * utils.h (strtoulst): Moved decl to common/common-utils.h.
>
>
>
> Thanks,
>
> Aleksandar
>
>
[-- Attachment #2: 0001-Move-utility-functions-to-common.patch --]
[-- Type: text/x-patch, Size: 14057 bytes --]
From d2cb04f1e90e14d72a63fa23ec5bb6421cc9e682 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:39:05 -0400
Subject: [PATCH 1/8] Move utility functions to common/
* cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to
common/common-utils.c.
* cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to
common/common-utils.h.
* common/common-utils.c (ctype.h): Include.
(HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move
from utils.c.
(fromhex): Copy from remote.c.
(hex2bin): Move from remote.c.
(tohex): Copy from remote.c.
(bin2hex): Move from remote.c.
(skip_spaces, skip_spaces_const): Move from cli/cli-utils.c.
* common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved
from defs.h.
(strtoulst): Move decl from utils.h.
(hex2bin, bin2hex): Move decls from remote.h.
(skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h.
* defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to
common/common-utils.h
* remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c.
* remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h.
* utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int,
strtoulst): Move to common/common-utils.c.
* utils.h (strtoulst): Moved decl to common/common-utils.h.
---
gdb/cli/cli-utils.c | 24 ------
gdb/cli/cli-utils.h | 9 ---
gdb/common/common-utils.c | 187 +++++++++++++++++++++++++++++++++++++++++++++
gdb/common/common-utils.h | 34 +++++++++
gdb/defs.h | 19 -----
gdb/remote.c | 36 ---------
gdb/remote.h | 4 -
gdb/utils.c | 99 ------------------------
gdb/utils.h | 2 -
9 files changed, 221 insertions(+), 193 deletions(-)
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index f74e6b1..60f7553 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -213,30 +213,6 @@ number_is_in_list (char *list, int number)
/* See documentation in cli-utils.h. */
-char *
-skip_spaces (char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* A const-correct version of the above. */
-
-const char *
-skip_spaces_const (const char *chp)
-{
- if (chp == NULL)
- return NULL;
- while (*chp && isspace (*chp))
- chp++;
- return chp;
-}
-
-/* See documentation in cli-utils.h. */
-
const char *
skip_to_space_const (const char *chp)
{
diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h
index 152fb89..2a8850d 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -89,15 +89,6 @@ extern int get_number_or_range (struct get_number_or_range_state *state);
extern int number_is_in_list (char *list, int number);
-/* Skip leading whitespace characters in INP, returning an updated
- pointer. If INP is NULL, return NULL. */
-
-extern char *skip_spaces (char *inp);
-
-/* A const-correct version of the above. */
-
-extern const char *skip_spaces_const (const char *inp);
-
/* Skip leading non-whitespace characters in INP, returning an updated
pointer. If INP is NULL, return NULL. */
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index 4204abf..5e96692 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
/* The xmalloc() (libiberty.h) family of memory management routines.
@@ -161,3 +162,189 @@ 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. */
+
+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;
+}
+
+/* See documentation in cli-utils.h. */
+
+char *
+skip_spaces (char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
+
+/* A const-correct version of the above. */
+
+const char *
+skip_spaces_const (const char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 9b659d8..ee7870e 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -25,6 +25,25 @@
#include <stddef.h>
#include <stdarg.h>
+/* Static target-system-dependent parameters for GDB. */
+
+/* Number of bits in a char or unsigned char for the target machine.
+ Just like CHAR_BIT in <limits.h> but describes the target machine. */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
+
+/* If we picked up a copy of CHAR_BIT from a configuration file
+ (which may get it by including <limits.h>) then use it to set
+ the number of bits in a host char. If not, use the same size
+ as the target. */
+
+#if defined (CHAR_BIT)
+#define HOST_CHAR_BIT CHAR_BIT
+#else
+#define HOST_CHAR_BIT TARGET_CHAR_BIT
+#endif
+
extern void malloc_failure (long size) ATTRIBUTE_NORETURN;
extern void internal_error (const char *file, int line, const char *, ...)
ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 4);
@@ -53,4 +72,19 @@ int xsnprintf (char *str, size_t size, const char *format, ...)
char *savestring (const char *ptr, size_t len);
+ULONGEST strtoulst (const char *num, const char **trailer, int base);
+
+extern int hex2bin (const char *hex, gdb_byte *bin, int count);
+
+extern int bin2hex (const gdb_byte *bin, char *hex, int count);
+
+/* Skip leading whitespace characters in INP, returning an updated
+ pointer. If INP is NULL, return NULL. */
+
+extern char *skip_spaces (char *inp);
+
+/* A const-correct version of the above. */
+
+extern const char *skip_spaces_const (const char *inp);
+
#endif
diff --git a/gdb/defs.h b/gdb/defs.h
index d8a1adb..ec7e4f3 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -648,25 +648,6 @@ extern void *alloca ();
enum { MAX_REGISTER_SIZE = 64 };
-/* Static target-system-dependent parameters for GDB. */
-
-/* Number of bits in a char or unsigned char for the target machine.
- Just like CHAR_BIT in <limits.h> but describes the target machine. */
-#if !defined (TARGET_CHAR_BIT)
-#define TARGET_CHAR_BIT 8
-#endif
-
-/* If we picked up a copy of CHAR_BIT from a configuration file
- (which may get it by including <limits.h>) then use it to set
- the number of bits in a host char. If not, use the same size
- as the target. */
-
-#if defined (CHAR_BIT)
-#define HOST_CHAR_BIT CHAR_BIT
-#else
-#define HOST_CHAR_BIT TARGET_CHAR_BIT
-#endif
-
/* In findvar.c. */
extern LONGEST extract_signed_integer (const gdb_byte *, int,
diff --git a/gdb/remote.c b/gdb/remote.c
index aefbcf1..6a11652 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4569,25 +4569,6 @@ fromhex (int a)
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
@@ -4599,23 +4580,6 @@ tohex (int nib)
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/remote.h b/gdb/remote.h
index b95370c..d49b427 100644
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -39,10 +39,6 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever);
extern int putpkt (char *buf);
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
extern void async_remote_interrupt_twice (void *arg);
diff --git a/gdb/utils.c b/gdb/utils.c
index a222c59..e1ced2c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3233,105 +3233,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 ad5bea4..e3b6fbf 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
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 5/6] Move linux_find_memory_regions_full & co.
2013-04-02 2:33 ` Jan Kratochvil
@ 2013-04-07 18:54 ` Aleksandar Ristovski
2013-04-05 15:37 ` Aleksandar Ristovski
0 siblings, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-07 18:54 UTC (permalink / raw)
To: gdb-patches; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 364 bytes --]
Rebased to master e96bd93d436e464a532a7e1161e1d201c9fc50c7
On 13-04-01 03:56 PM, Jan Kratochvil wrote:
> On Mon, 01 Apr 2013 21:46:05 +0200, Aleksandar Ristovski wrote:
>> Done, waiting for your feedback on #4/6 to proceed with commit.
>
> BTW the patchset should get checked in only as a whole, only some parts of it
> have no benefit to the user.
>
>
> Jan
>
[-- Attachment #2: 0005-Move-linux_find_memory_regions_full-co.patch --]
[-- Type: text/x-patch, Size: 19239 bytes --]
From 43124b3998f6eb8985e828d0fd78107fd0d1e7e4 Mon Sep 17 00:00:00 2001
From: Aleksandar Ristovski <ARistovski@qnx.com>
Date: Wed, 27 Mar 2013 09:54:36 -0400
Subject: [PATCH 5/8] Move linux_find_memory_regions_full & co.
* common/common-utils.c (read_alloc, read_stralloc): Move definitions
from target.c.
* common/common-utils.h (read_alloc_pread_ftype): New typedef.
(read_alloc): New declaration.
(read_stralloc_func_ftype): New typedef.
(read_stralloc): New declaration.
* common/linux-maps.c (fcntl.h, unistd.h, target.h, gdb_assert.h,
ctype.h, string.h): Include.
(read_mapping): Move from linux-tdep.c.
(linux_find_memory_read_stralloc_1_pread): New function.
(linux_find_memory_read_stralloc_1): New function.
(linux_find_memory_read_stralloc): New function.
* common/linux-maps.h (read_mapping): New declaration.
(linux_find_memory_region_ftype): Moved typedef from linux-tdep.c.
(linux_find_memory_regions_full): New declaration.
* linux-tdep.c (linux-maps.h): Include.
(read_mapping): Moved to common/linux-maps.c.
(linux_find_memory_region_ftype): Moved typedef to common/linux-maps.h.
(linux_find_memory_regions_full): Moved definition to
common/linux-maps.c.
* target.c (read_alloc_pread_ftype): Moved typedef to
common/common-utils.h.
(read_alloc, read_stralloc): Moved definitions to
common/common-utils.c.
---
gdb/common/common-utils.c | 88 +++++++++++++++++++++
gdb/common/common-utils.h | 11 +++
gdb/common/linux-maps.c | 186 +++++++++++++++++++++++++++++++++++++++++++++
gdb/common/linux-maps.h | 25 ++++++
gdb/linux-tdep.c | 148 +-----------------------------------
gdb/target.c | 93 -----------------------
6 files changed, 311 insertions(+), 240 deletions(-)
diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
index c123ed7..31234fa 100644
--- a/gdb/common/common-utils.c
+++ b/gdb/common/common-utils.c
@@ -348,3 +348,91 @@ skip_spaces_const (const char *chp)
chp++;
return chp;
}
+
+LONGEST
+read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
+ int padding, void **memory_to_free_ptr)
+{
+ size_t buf_alloc, buf_pos;
+ gdb_byte *buf;
+ LONGEST n;
+ int target_errno;
+
+ /* Start by reading up to 4K at a time. The target will throttle
+ this number down if necessary. */
+ buf_alloc = 4096;
+ buf = xmalloc (buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = buf;
+ }
+ buf_pos = 0;
+ while (1)
+ {
+ n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
+ buf_pos, &target_errno);
+ if (n <= 0)
+ {
+ if (n < 0 || (n == 0 && buf_pos == 0))
+ xfree (buf);
+ else
+ *buf_p = buf;
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = NULL;
+ if (n < 0)
+ {
+ /* An error occurred. */
+ return -1;
+ }
+ else
+ {
+ /* Read all there was. */
+ return buf_pos;
+ }
+ }
+
+ buf_pos += n;
+
+ /* If the buffer is filling up, expand it. */
+ if (buf_alloc < buf_pos * 2)
+ {
+ buf_alloc *= 2;
+ buf = xrealloc (buf, buf_alloc);
+ if (memory_to_free_ptr != NULL)
+ *memory_to_free_ptr = buf;
+ }
+ }
+}
+
+char *
+read_stralloc (const char *filename, read_stralloc_func_ftype *func)
+{
+ gdb_byte *buffer;
+ char *bufstr;
+ LONGEST i, transferred;
+
+ transferred = func (filename, &buffer, 1);
+ bufstr = (char *) buffer;
+
+ if (transferred < 0)
+ return NULL;
+
+ if (transferred == 0)
+ return xstrdup ("");
+
+ bufstr[transferred] = 0;
+
+ /* Check for embedded NUL bytes; but allow trailing NULs. */
+ for (i = strlen (bufstr); i < transferred; i++)
+ if (bufstr[i] != 0)
+ {
+ warning (_("target file %s "
+ "contained unexpected null characters"),
+ filename);
+ break;
+ }
+
+ return bufstr;
+}
+
diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
index 2c95d34..c7f8162 100644
--- a/gdb/common/common-utils.h
+++ b/gdb/common/common-utils.h
@@ -91,4 +91,15 @@ extern char *skip_spaces (char *inp);
extern const char *skip_spaces_const (const char *inp);
+typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
+ ULONGEST offset, int *target_errno);
+extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
+ read_alloc_pread_ftype *pread_func, int padding,
+ void **memory_to_free_ptr);
+
+typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
+ gdb_byte **buf_p, int padding);
+extern char *read_stralloc (const char *filename,
+ read_stralloc_func_ftype *func);
+
#endif
diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c
index efb0875..a2566e1 100644
--- a/gdb/common/linux-maps.c
+++ b/gdb/common/linux-maps.c
@@ -18,8 +18,194 @@
#ifdef GDBSERVER
#include "server.h"
+#include <fcntl.h>
+#include <unistd.h>
#else
#include "defs.h"
+#include "target.h"
#endif
#include "linux-maps.h"
+#include "gdb_assert.h"
+#include <ctype.h>
+#include <string.h>
+
+/* 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);
+
+ p = skip_spaces_const (p);
+ *permissions = p;
+ while (*p && !isspace (*p))
+ p++;
+ *permissions_len = p - *permissions;
+
+ *offset = strtoulst (p, &p, 16);
+
+ p = skip_spaces_const (p);
+ *device = p;
+ while (*p && !isspace (*p))
+ p++;
+ *device_len = p - *device;
+
+ *inode = strtoulst (p, &p, 10);
+
+ p = skip_spaces_const (p);
+ *filename = p;
+}
+
+#ifdef GDBSERVER
+
+static int
+linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf,
+ int len, ULONGEST offset,
+ int *target_errno)
+{
+ int retval = pread (handle, read_buf, len, offset);
+
+ *target_errno = errno;
+ return retval;
+}
+
+static LONGEST
+linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p,
+ int padding)
+{
+ int fd;
+ LONGEST retval;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread,
+ padding, NULL);
+
+ close (fd);
+
+ return retval;
+}
+
+#endif /* GDBSERVER */
+
+static char *
+linux_find_memory_read_stralloc (const char *filename)
+{
+#ifndef GDBSERVER
+ return target_fileio_read_stralloc (filename);
+#else /* GDBSERVER */
+ return read_stralloc (filename, linux_find_memory_read_stralloc_1);
+#endif /* GDBSERVER */
+}
+
+/* List memory regions in the inferior PID for a corefile. Call FUNC
+ with FUNC_DATA for each such region. Return immediately with the
+ value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
+ be registered to be freed automatically if called FUNC throws an
+ exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
+ not used. Return -1 if error occurs, 0 if all memory regions have
+ been processed or return the value from FUNC if FUNC returns
+ non-zero. */
+
+int
+linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr)
+{
+ char filename[100];
+ char *data;
+
+ xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid);
+ data = linux_find_memory_read_stralloc (filename);
+ }
+ if (data)
+ {
+ char *line;
+ int retval = 0;
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (*memory_to_free_ptr == NULL);
+ *memory_to_free_ptr = data;
+ }
+
+ 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. */
+ retval = func (addr, endaddr - addr, offset, inode,
+ read, write, exec, modified, filename, func_data);
+ if (retval != 0)
+ break;
+ }
+
+ if (memory_to_free_ptr != NULL)
+ {
+ gdb_assert (data == *memory_to_free_ptr);
+ *memory_to_free_ptr = NULL;
+ }
+ xfree (data);
+ return retval;
+ }
+
+ return -1;
+}
diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h
index da426e5..e989376 100644
--- a/gdb/common/linux-maps.h
+++ b/gdb/common/linux-maps.h
@@ -19,4 +19,29 @@
#ifndef COMMON_LINUX_MAPS_H
#define COMMON_LINUX_MAPS_H
+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);
+
+/* Callback function for linux_find_memory_regions_full. If it returns
+ non-zero linux_find_memory_regions_full returns immediately with that
+ value. */
+
+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);
+
+extern int
+ linux_find_memory_regions_full (pid_t pid,
+ linux_find_memory_region_ftype *func,
+ void *func_data, void **memory_to_free_ptr);
+
#endif /* COMMON_LINUX_MAPS_H */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index c48f4ec..4544e5f 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,44 +208,6 @@ 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);
-
- p = skip_spaces_const (p);
- *permissions = p;
- while (*p && !isspace (*p))
- p++;
- *permissions_len = p - *permissions;
-
- *offset = strtoulst (p, &p, 16);
-
- p = skip_spaces_const (p);
- *device = p;
- while (*p && !isspace (*p))
- p++;
- *device_len = p - *device;
-
- *inode = strtoulst (p, &p, 10);
-
- p = skip_spaces_const (p);
- *filename = p;
-}
-
/* Implement the "info proc" command. */
static void
@@ -661,115 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args,
error (_("unable to handle request"));
}
-/* Callback function for linux_find_memory_regions_full. If it returns
- non-zero linux_find_memory_regions_full returns immediately with that
- value. */
-
-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 PID for a corefile. Call FUNC
- with FUNC_DATA for each such region. Return immediately with the
- value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should
- be registered to be freed automatically if called FUNC throws an
- exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is
- not used. Return -1 if error occurs, 0 if all memory regions have
- been processed or return the value from FUNC if FUNC returns
- non-zero. */
-
-static int
-linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func,
- void *func_data, void **memory_to_free_ptr)
-{
- char filename[100];
- char *data;
-
- xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) 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", (int) pid);
- data = target_fileio_read_stralloc (filename);
- }
- if (data)
- {
- char *line;
- int retval = 0;
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = data;
- }
-
- 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. */
- retval = func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, func_data);
- if (retval != 0)
- break;
- }
-
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (data == *memory_to_free_ptr);
- *memory_to_free_ptr = NULL;
- }
- xfree (data);
- return retval;
- }
-
- return -1;
-}
-
/* A structure for passing information through
linux_find_memory_regions_full. */
diff --git a/gdb/target.c b/gdb/target.c
index ed0f3bf..0dbac02 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3493,65 +3493,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
target_fileio_read_alloc; see the declaration of that function for more
information. */
-typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
- ULONGEST offset, int *target_errno);
-
-static LONGEST
-read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
- int padding, void **memory_to_free_ptr)
-{
- size_t buf_alloc, buf_pos;
- gdb_byte *buf;
- LONGEST n;
- int target_errno;
-
- /* Start by reading up to 4K at a time. The target will throttle
- this number down if necessary. */
- buf_alloc = 4096;
- buf = xmalloc (buf_alloc);
- if (memory_to_free_ptr != NULL)
- {
- gdb_assert (*memory_to_free_ptr == NULL);
- *memory_to_free_ptr = buf;
- }
- buf_pos = 0;
- while (1)
- {
- n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
- buf_pos, &target_errno);
- if (n <= 0)
- {
- if (n < 0 || (n == 0 && buf_pos == 0))
- xfree (buf);
- else
- *buf_p = buf;
- if (memory_to_free_ptr != NULL)
- *memory_to_free_ptr = NULL;
- if (n < 0)
- {
- /* An error occurred. */
- return -1;
- }
- else
- {
- /* Read all there was. */
- return buf_pos;
- }
- }
-
- buf_pos += n;
-
- /* If the buffer is filling up, expand it. */
- if (buf_alloc < buf_pos * 2)
- {
- buf_alloc *= 2;
- buf = xrealloc (buf, buf_alloc);
- if (memory_to_free_ptr != NULL)
- *memory_to_free_ptr = buf;
- }
- }
-}
-
static LONGEST
target_fileio_read_alloc_1 (const char *filename,
gdb_byte **buf_p, int padding)
@@ -3590,40 +3531,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p)
are returned as allocated but empty strings. A warning is issued
if the result contains any embedded NUL bytes. */
-typedef LONGEST (read_stralloc_func_ftype) (const char *filename,
- gdb_byte **buf_p, int padding);
-
-static char *
-read_stralloc (const char *filename, read_stralloc_func_ftype *func)
-{
- gdb_byte *buffer;
- char *bufstr;
- LONGEST i, transferred;
-
- transferred = func (filename, &buffer, 1);
- bufstr = (char *) buffer;
-
- if (transferred < 0)
- return NULL;
-
- if (transferred == 0)
- return xstrdup ("");
-
- bufstr[transferred] = 0;
-
- /* Check for embedded NUL bytes; but allow trailing NULs. */
- for (i = strlen (bufstr); i < transferred; i++)
- if (bufstr[i] != 0)
- {
- warning (_("target file %s "
- "contained unexpected null characters"),
- filename);
- break;
- }
-
- return bufstr;
-}
-
char *
target_fileio_read_stralloc (const char *filename)
{
--
1.7.10.4
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-09 15:28 ` Gary Benson
@ 2013-04-09 15:28 ` Jan Kratochvil
2013-04-09 15:29 ` Gary Benson
2013-04-09 15:29 ` Aleksandar Ristovski
2013-04-09 15:28 ` Aleksandar Ristovski
1 sibling, 2 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-04-09 15:28 UTC (permalink / raw)
To: Aleksandar Ristovski, gdb-patches
On Tue, 09 Apr 2013 13:29:31 +0200, Gary Benson wrote:
> For the record this is the only part of your patchset that clashes
> with the gdbserver work I'm doing. It's not an *awful* clash, but
> it will require a manual merge.
It's not just about technical patch clash but rather a possible for example
runtime performance regression applying both patches together. But I do not
know your (Gary's) patch to say more.
Regards,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-09 15:28 ` Gary Benson
2013-04-09 15:28 ` Jan Kratochvil
@ 2013-04-09 15:28 ` Aleksandar Ristovski
2013-04-09 19:26 ` Gary Benson
1 sibling, 1 reply; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-09 15:28 UTC (permalink / raw)
To: Jan Kratochvil, gdb-patches
On 13-04-09 07:29 AM, Gary Benson wrote:
> Aleksandar Ristovski wrote:
>> (linux_qxfer_libraries_svr4): Add optional build-id attribute
>> to reply XML document.
>
> For the record this is the only part of your patchset that clashes
> with the gdbserver work I'm doing. It's not an *awful* clash, but
> it will require a manual merge. I'm happy to do that if necessary.
>
> Thanks,
> Gary
>
Thank you for your update. I'm sorry for the clash. If there is
something obvious I can do in this patch to reduce the clash let me know.
BTW, I am not familiar with your patch, if you want you can give me an
overview here or offline.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-05 15:05 ` Aleksandar Ristovski
@ 2013-04-09 15:28 ` Gary Benson
2013-04-09 15:28 ` Jan Kratochvil
2013-04-09 15:28 ` Aleksandar Ristovski
0 siblings, 2 replies; 79+ messages in thread
From: Gary Benson @ 2013-04-09 15:28 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: Jan Kratochvil, gdb-patches
Aleksandar Ristovski wrote:
> (linux_qxfer_libraries_svr4): Add optional build-id attribute
> to reply XML document.
For the record this is the only part of your patchset that clashes
with the gdbserver work I'm doing. It's not an *awful* clash, but
it will require a manual merge. I'm happy to do that if necessary.
Thanks,
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-09 15:28 ` Jan Kratochvil
@ 2013-04-09 15:29 ` Gary Benson
2013-04-09 15:29 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Gary Benson @ 2013-04-09 15:29 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Aleksandar Ristovski, gdb-patches
Jan Kratochvil wrote:
> On Tue, 09 Apr 2013 13:29:31 +0200, Gary Benson wrote:
> > For the record this is the only part of your patchset that clashes
> > with the gdbserver work I'm doing. It's not an *awful* clash, but
> > it will require a manual merge.
>
> It's not just about technical patch clash but rather a possible for
> example runtime performance regression applying both patches
> together. But I do not know your (Gary's) patch to say more.
I don't envisage any performance regression but I'll obviously check.
Cheers,
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-09 15:28 ` Jan Kratochvil
2013-04-09 15:29 ` Gary Benson
@ 2013-04-09 15:29 ` Aleksandar Ristovski
1 sibling, 0 replies; 79+ messages in thread
From: Aleksandar Ristovski @ 2013-04-09 15:29 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, Gary Benson
On 13-04-09 07:42 AM, Jan Kratochvil wrote:
> On Tue, 09 Apr 2013 13:29:31 +0200, Gary Benson wrote:
>> For the record this is the only part of your patchset that clashes
>> with the gdbserver work I'm doing. It's not an *awful* clash, but
>> it will require a manual merge.
>
> It's not just about technical patch clash but rather a possible for example
> runtime performance regression applying both patches together. But I do not
> know your (Gary's) patch to say more.
I will be posting new patchset (in a new thread) today, and we can
discuss more to see what is the impact.
Thanks,
Aleksandar
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-09 15:28 ` Aleksandar Ristovski
@ 2013-04-09 19:26 ` Gary Benson
2013-04-12 15:28 ` Jan Kratochvil
0 siblings, 1 reply; 79+ messages in thread
From: Gary Benson @ 2013-04-09 19:26 UTC (permalink / raw)
To: Aleksandar Ristovski; +Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]
Aleksandar Ristovski wrote:
> On 13-04-09 07:29 AM, Gary Benson wrote:
> > Aleksandar Ristovski wrote:
> > > (linux_qxfer_libraries_svr4): Add optional build-id attribute
> > > to reply XML document.
> >
> > For the record this is the only part of your patchset that clashes
> > with the gdbserver work I'm doing. It's not an *awful* clash, but
> > it will require a manual merge. I'm happy to do that if necessary.
>
> Thank you for your update. I'm sorry for the clash. If there is
> something obvious I can do in this patch to reduce the clash let me
> know.
There's nothing obvious, and you don't need to apologise. We just
both happen to be working in the same area at the same time.
> BTW, I am not familiar with your patch, if you want you can give me
> an overview here or offline.
The gdbserver side of it is that GDB can pass arguments in the annex
of qXfer:libraries-svr4:read+ to instruct the remote to transfer the
list starting from a specific link map rather than sending the whole
list.
I've attached my work-in-progress patch for the gdbserver side, but
you can see the full thing in the gbenson/rtld-probes branch in archer
git if you like. A lot of the code is actually the same, but somewhat
reordered and with indentation changes which makes the patch harder to
read.
Your work seems closer to being accepted than mine, so I imagine what
will happen is that you'll commit your patches and I'll rebase mine
on top of that. I have no problem with that.
Cheers,
Gary
--
http://gbenson.net/
[-- Attachment #2: gdbserver-changes.patch --]
[-- Type: text/plain, Size: 8812 bytes --]
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..beb3b8f 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5677,6 +5677,12 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
};
const struct link_map_offsets *lmo;
unsigned int machine;
+ int ptr_size;
+ CORE_ADDR lm_addr = 0, lm_prev = 0;
+ int allocated = 1024;
+ char *p;
+ CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
+ int header_done = 0;
if (writebuf != NULL)
return -2;
@@ -5687,128 +5693,146 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ ptr_size = is_elf64 ? 8 : 4;
- if (priv->r_debug == 0)
- priv->r_debug = get_r_debug (pid, is_elf64);
+ if (annex[0] == '\0')
+ {
+ int r_version = 0;
- /* We failed to find DT_DEBUG. Such situation will not change for this
- inferior - do not retry it. Report it to GDB as E01, see for the reasons
- at the GDB solib-svr4.c side. */
- if (priv->r_debug == (CORE_ADDR) -1)
- return -1;
+ if (priv->r_debug == 0)
+ priv->r_debug = get_r_debug (pid, is_elf64);
- if (priv->r_debug == 0)
- {
- document = xstrdup ("<library-list-svr4 version=\"1.0\"/>\n");
+ /* We failed to find DT_DEBUG. Such situation will not change
+ for this inferior - do not retry it. Report it to GDB as
+ E01, see for the reasons at the GDB solib-svr4.c side. */
+ if (priv->r_debug == (CORE_ADDR) -1)
+ return -1;
+
+ if (priv->r_debug != 0)
+ {
+ if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
+ (unsigned char *) &r_version,
+ sizeof (r_version)) != 0
+ || r_version != 1)
+ {
+ warning ("unexpected r_debug version %d", r_version);
+ }
+ else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
+ &lm_addr, ptr_size) != 0)
+ {
+ warning ("unable to read r_map from 0x%lx",
+ (long) priv->r_debug + lmo->r_map_offset);
+ }
+ }
}
else
{
- int allocated = 1024;
- char *p;
- const int ptr_size = is_elf64 ? 8 : 4;
- CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_prev;
- int r_version, header_done = 0;
-
- document = xmalloc (allocated);
- strcpy (document, "<library-list-svr4 version=\"1.0\"");
- p = document + strlen (document);
-
- r_version = 0;
- if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
- (unsigned char *) &r_version,
- sizeof (r_version)) != 0
- || r_version != 1)
+ while (annex[0] != '\0')
{
- warning ("unexpected r_debug version %d", r_version);
- goto done;
+ const char *sep;
+ CORE_ADDR *addrp;
+ int len;
+
+ sep = strchr (annex, '=');
+ if (!sep)
+ break;
+
+ len = sep - annex;
+ if (len == 5 && !strncmp (annex, "start", 5))
+ addrp = &lm_addr;
+ else if (len == 4 && !strncmp (annex, "prev", 4))
+ addrp = &lm_prev;
+ else
+ {
+ annex = strchr (sep, ';');
+ if (!annex)
+ break;
+ annex++;
+ continue;
+ }
+
+ annex = decode_address_to_semicolon (addrp, sep + 1);
}
+ }
- if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
- &lm_addr, ptr_size) != 0)
+ document = xmalloc (allocated);
+ strcpy (document, "<library-list-svr4 version=\"1.0\"");
+ p = document + strlen (document);
+
+ while (lm_addr
+ && read_one_ptr (lm_addr + lmo->l_name_offset,
+ &l_name, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_addr_offset,
+ &l_addr, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_ld_offset,
+ &l_ld, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_prev_offset,
+ &l_prev, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_next_offset,
+ &l_next, ptr_size) == 0)
+ {
+ unsigned char libname[PATH_MAX];
+
+ if (lm_prev != l_prev)
{
- warning ("unable to read r_map from 0x%lx",
- (long) priv->r_debug + lmo->r_map_offset);
- goto done;
+ warning ("Corrupted shared library list: 0x%lx != 0x%lx",
+ (long) lm_prev, (long) l_prev);
+ break;
}
- lm_prev = 0;
- while (read_one_ptr (lm_addr + lmo->l_name_offset,
- &l_name, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_addr_offset,
- &l_addr, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_ld_offset,
- &l_ld, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_prev_offset,
- &l_prev, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_next_offset,
- &l_next, ptr_size) == 0)
+ /* Not checking for error because reading may stop before
+ we've got PATH_MAX worth of characters. */
+ libname[0] = '\0';
+ linux_read_memory (l_name, libname, sizeof (libname) - 1);
+ libname[sizeof (libname) - 1] = '\0';
+ if (libname[0] != '\0')
{
- unsigned char libname[PATH_MAX];
+ /* 6x the size for xml_escape_text below. */
+ size_t len = 6 * strlen ((char *) libname);
+ char *name;
- if (lm_prev != l_prev)
+ if (!header_done)
{
- warning ("Corrupted shared library list: 0x%lx != 0x%lx",
- (long) lm_prev, (long) l_prev);
- break;
+ /* Terminate `<library-list-svr4'. */
+ *p++ = '>';
+ header_done = 1;
}
- /* Not checking for error because reading may stop before
- we've got PATH_MAX worth of characters. */
- libname[0] = '\0';
- linux_read_memory (l_name, libname, sizeof (libname) - 1);
- libname[sizeof (libname) - 1] = '\0';
- if (libname[0] != '\0')
+ while (allocated < p - document + len + 200)
{
- /* 6x the size for xml_escape_text below. */
- size_t len = 6 * strlen ((char *) libname);
- char *name;
-
- if (!header_done)
- {
- /* Terminate `<library-list-svr4'. */
- *p++ = '>';
- header_done = 1;
- }
-
- while (allocated < p - document + len + 200)
- {
- /* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
-
- document = xrealloc (document, 2 * allocated);
- allocated *= 2;
- p = document + document_len;
- }
+ /* Expand to guarantee sufficient storage. */
+ uintptr_t document_len = p - document;
- name = xml_escape_text ((char *) libname);
- p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
- "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
- name, (unsigned long) lm_addr,
- (unsigned long) l_addr, (unsigned long) l_ld);
- free (name);
- }
- else if (lm_prev == 0)
- {
- sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
- p = p + strlen (p);
+ document = xrealloc (document, 2 * allocated);
+ allocated *= 2;
+ p = document + document_len;
}
- if (l_next == 0)
- break;
-
- lm_prev = lm_addr;
- lm_addr = l_next;
+ name = xml_escape_text ((char *) libname);
+ p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
+ "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+ name, (unsigned long) lm_addr,
+ (unsigned long) l_addr, (unsigned long) l_ld);
+ free (name);
}
- done:
- if (!header_done)
+ else if (lm_prev == 0)
{
- /* Empty list; terminate `<library-list-svr4'. */
- strcpy (p, "/>");
+ sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
+ p = p + strlen (p);
}
- else
- strcpy (p, "</library-list-svr4>");
+
+ lm_prev = lm_addr;
+ lm_addr = l_next;
}
+ if (!header_done)
+ {
+ /* Empty list; terminate `<library-list-svr4'. */
+ strcpy (p, "/>");
+ }
+ else
+ strcpy (p, "</library-list-svr4>");
+
document_len = strlen (document);
if (offset < document_len)
document_len -= offset;
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6bb36d8..0a8f68b 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1115,8 +1115,7 @@ handle_qxfer_libraries_svr4 (const char *annex,
if (writebuf != NULL)
return -2;
- if (annex[0] != '\0' || !target_running ()
- || the_target->qxfer_libraries_svr4 == NULL)
+ if (!target_running () || the_target->qxfer_libraries_svr4 == NULL)
return -1;
return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len);
@@ -1743,7 +1742,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
PBUFSIZ - 1);
if (the_target->qxfer_libraries_svr4 != NULL)
- strcat (own_buf, ";qXfer:libraries-svr4:read+");
+ strcat (own_buf, ";qXfer:libraries-svr4:read+"
+ ";augmented-libraries-svr4-read+");
else
{
/* We do not have any hook to indicate whether the non-SVR4 target
^ permalink raw reply [flat|nested] 79+ messages in thread
* Re: [patch 6/6] gdbserver build-id attribute generator
2013-04-09 19:26 ` Gary Benson
@ 2013-04-12 15:28 ` Jan Kratochvil
0 siblings, 0 replies; 79+ messages in thread
From: Jan Kratochvil @ 2013-04-12 15:28 UTC (permalink / raw)
To: Aleksandar Ristovski, gdb-patches
On Tue, 09 Apr 2013 18:02:58 +0200, Gary Benson wrote:
> The gdbserver side of it is that GDB can pass arguments in the annex
> of qXfer:libraries-svr4:read+ to instruct the remote to transfer the
> list starting from a specific link map rather than sending the whole
> list.
OK, I agree it should not clash much with the Aleksandar's patch.
Thanks,
Jan
^ permalink raw reply [flat|nested] 79+ messages in thread
end of thread, other threads:[~2013-04-12 12:21 UTC | newest]
Thread overview: 79+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-22 15:07 [patch] gdbserver build-id in qxfer_libraries reply Aleksandar Ristovski
2013-02-22 18:39 ` Aleksandar Ristovski
2013-02-26 12:01 ` Pedro Alves
2013-02-27 17:25 ` Aleksandar Ristovski
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 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: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 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: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 ` Jan Kratochvil
2013-04-09 15:29 ` Gary Benson
2013-04-09 15:29 ` Aleksandar Ristovski
2013-04-09 15:28 ` Aleksandar Ristovski
2013-04-09 19:26 ` Gary Benson
2013-04-12 15:28 ` Jan Kratochvil
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-04-04 16:08 ` [patch] gdbserver build-id in qxfer_libraries reply Jan Kratochvil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox