Re: [patch 5/6] Move linux_find_memory_regions_full & co.

Aleksandar Ristovski
2013-04-06T19:13:17Z

[-- 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