[PATCH 1/4] Improve identification of memory mappings

Sergio Durigan Junior
2015-03-18T19:39:24Z

This commit implements the new 'enum memory_mapping_state', which can
be used to represent the different states of each memory mapping from
the inferior. These states are:

- MODIFIED, which means that the mapping should be dumped in
corefiles

- UNMODIFIED, which means that the mapping should not be dumped in
corefiles (e.g., mappings that have been marked as VM_DONTDUMP), and

- UNKNOWN, which means that we don't know whether the mapping should
or should not be dumped.

The last state is not used in this patch, but will be used in the
following patches of this series.

It is also worth mentioning that I do not intend to commit this patch
independently. IOW, I will merge everything before pushing one single
commit.

Changes from v2:

- Moved declaration of 'enum memory_mapping_state' from
gdb/common/common-defs.h to gdb/defs.h.

- Renamed variable to 'modified_state' (instead of 'state').

gdb/ChangeLog:
2015-03-18 Sergio Durigan Junior <sergiodj@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
Oleg Nesterov <oleg@redhat.com>

PR corefiles/16092
* defs.h (enum memory_mapping_state): New enum.
(find_memory_region_ftype): Remove 'int modified' parameter,
replacing by 'enum memory_mapping_state modified_state'.
* gcore.c (gcore_create_callback): Likewise.
(objfile_find_memory_regions): Passing
'MEMORY_MAPPING_UNKNOWN_STATE' or 'MEMORY_MAPPING_MODIFIED' when
needed to 'func' callback, instead of saying the memory mapping
was modified even without knowing it.
* gnu-nat.c (gnu_find_memory_regions): Likewise.
* linux-tdep.c (linux_find_memory_region_ftype): Remove 'int
modified' parameter, replacing by 'enum memory_mapping_state
modified_state'.
(linux_find_memory_regions_thunk): Likewise.
(linux_make_mappings_callback): Likewise.
(find_mapping_size): Likewise.
* procfs.c (find_memory_regions_callback): Likewise.
---
gdb/defs.h | 13 ++++++++++++-
gdb/gcore.c | 16 ++++++++++------
gdb/gnu-nat.c | 4 ++--
gdb/linux-tdep.c | 25 ++++++++++++++++---------
gdb/procfs.c | 2 +-
5 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/gdb/defs.h b/gdb/defs.h
index 72512f6..37b1430 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -330,6 +330,16 @@ extern void init_source_path (void);

/* From exec.c */

+/* Enum used to inform the state of a memory mapping. This is used in
+ functions implementing find_memory_region_ftype. */
+
+enum memory_mapping_state
+ {
+ MEMORY_MAPPING_MODIFIED,
+ MEMORY_MAPPING_UNMODIFIED,
+ MEMORY_MAPPING_UNKNOWN_STATE,
+ };
+
/* * Process memory area starting at ADDR with length SIZE. Area is
readable iff READ is non-zero, writable if WRITE is non-zero,
executable if EXEC is non-zero. Area is possibly changed against
@@ -338,7 +348,8 @@ extern void init_source_path (void);

typedef int (*find_memory_region_ftype) (CORE_ADDR addr, unsigned long size,
int read, int write, int exec,
- int modified, void *data);
+ enum memory_mapping_state state,
+ void *data);

/* * Possible lvalue types. Like enum language, this should be in
value.h, but needs to be here for the same reason. */
diff --git a/gdb/gcore.c b/gdb/gcore.c
index 44b9d0c..751ddac 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -415,7 +415,8 @@ make_output_phdrs (bfd *obfd, asection *osec, void *ignored)

static int
gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read,
- int write, int exec, int modified, void *data)
+ int write, int exec,
+ enum memory_mapping_state modified_state, void *data)
{
bfd *obfd = data;
asection *osec;
@@ -424,7 +425,8 @@ gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read,
/* If the memory segment has no permissions set, ignore it, otherwise
when we later try to access it for read/write, we'll get an error
or jam the kernel. */
- if (read == 0 && write == 0 && exec == 0 && modified == 0)
+ if (read == 0 && write == 0 && exec == 0
+ && modified_state == MEMORY_MAPPING_UNMODIFIED)
{
if (info_verbose)
{
@@ -435,7 +437,8 @@ gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read,
return 0;
}

- if (write == 0 && modified == 0 && !solib_keep_data_in_core (vaddr, size))
+ if (write == 0 && modified_state == MEMORY_MAPPING_UNMODIFIED
+ && !solib_keep_data_in_core (vaddr, size))
{
/* See if this region of memory lies inside a known file on disk.
If so, we can avoid copying its contents by clearing SEC_LOAD. */
@@ -528,7 +531,8 @@ objfile_find_memory_regions (struct target_ops *self,
1, /* All sections will be readable. */
(flags & SEC_READONLY) == 0, /* Writable. */
(flags & SEC_CODE) != 0, /* Executable. */
- 1, /* MODIFIED is unknown, pass it as true. */
+ MEMORY_MAPPING_UNKNOWN_STATE, /* MODIFIED is
+ unknown. */
obfd);
if (ret != 0)
return ret;
@@ -541,7 +545,7 @@ objfile_find_memory_regions (struct target_ops *self,
1, /* Stack section will be readable. */
1, /* Stack section will be writable. */
0, /* Stack section will not be executable. */
- 1, /* Stack section will be modified. */
+ MEMORY_MAPPING_MODIFIED, /* Stack section will be modified. */
obfd);

/* Make a heap segment. */
@@ -550,7 +554,7 @@ objfile_find_memory_regions (struct target_ops *self,
1, /* Heap section will be readable. */
1, /* Heap section will be writable. */
0, /* Heap section will not be executable. */
- 1, /* Heap section will be modified. */
+ MEMORY_MAPPING_MODIFIED, /* Heap section will be modified. */
obfd);

return 0;
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index d830773..60612a7 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2611,7 +2611,7 @@ gnu_find_memory_regions (struct target_ops *self,
last_protection & VM_PROT_READ,
last_protection & VM_PROT_WRITE,
last_protection & VM_PROT_EXECUTE,
- 1, /* MODIFIED is unknown, pass it as true. */
+ MEMORY_MAPPING_UNKNOWN_STATE, /* MODIFIED is unknown. */
data);
last_region_address = region_address;
last_region_end = region_address += region_length;
@@ -2625,7 +2625,7 @@ gnu_find_memory_regions (struct target_ops *self,
last_protection & VM_PROT_READ,
last_protection & VM_PROT_WRITE,
last_protection & VM_PROT_EXECUTE,
- 1, /* MODIFIED is unknown, pass it as true. */
+ MEMORY_MAPPING_UNKNOWN_STATE, /* MODIFIED is unknown. */
data);

return 0;
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index ea0d4cd..15725c7 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -807,7 +807,9 @@ linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
- int exec, int modified,
+ int exec,
+ enum memory_mapping_state
+ modified_state,
const char *filename,
void *data);

@@ -847,7 +849,8 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
const char *permissions, *device, *filename;
size_t permissions_len, device_len;
int read, write, exec;
- int modified = 0, has_anonymous = 0;
+ enum memory_mapping_state modified_state = MEMORY_MAPPING_UNMODIFIED;
+ int has_anonymous = 0;

read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
&offset, &device, &device_len, &inode, &filename);
@@ -885,18 +888,18 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
break;
}
if (number != 0)
- modified = 1;
+ modified_state = MEMORY_MAPPING_MODIFIED;
}
}

/* 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;
+ modified_state = MEMORY_MAPPING_MODIFIED;

/* Invoke the callback function to create the corefile segment. */
func (addr, endaddr - addr, offset, inode,
- read, write, exec, modified, filename, obfd);
+ read, write, exec, modified_state, filename, obfd);
}

do_cleanups (cleanup);
@@ -926,12 +929,14 @@ struct linux_find_memory_regions_data
static int
linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
- int read, int write, int exec, int modified,
+ int read, int write, int exec,
+ enum memory_mapping_state modified_state,
const char *filename, void *arg)
{
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_state,
+ data->obfd);
}

/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -1074,7 +1079,8 @@ static linux_find_memory_region_ftype linux_make_mappings_callback;
static int
linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
- int read, int write, int exec, int modified,
+ int read, int write, int exec,
+ enum memory_mapping_state modified_state,
const char *filename, void *data)
{
struct linux_make_mappings_data *map_data = data;
@@ -1872,7 +1878,8 @@ linux_gdb_signal_to_target (struct gdbarch *gdbarch,

static int
find_mapping_size (CORE_ADDR vaddr, unsigned long size,
- int read, int write, int exec, int modified,
+ int read, int write, int exec,
+ enum memory_mapping_state modified_state,
void *data)
{
struct mem_range *range = data;
diff --git a/gdb/procfs.c b/gdb/procfs.c
index b62539f..d074dd3 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4967,7 +4967,7 @@ find_memory_regions_callback (struct prmap *map,
(map->pr_mflags & MA_READ) != 0,
(map->pr_mflags & MA_WRITE) != 0,
(map->pr_mflags & MA_EXEC) != 0,
- 1, /* MODIFIED is unknown, pass it as true. */
+ MEMORY_MAPPING_UNKNOWN_STATE, /* MODIFIED is unknown. */
data);
}

--
1.9.3