compile: Use also inferior munmap

Currently inferior memory is allocated by inferior mmap() but it is never
deallocated; despite the injected objfile incl. its symbols is freed.  This was
intentional so that one can do for example:
inferior:
	char *str = "foo";
GDB:
	(gdb) compile code str = "bar";

I believe later patches will be needed to introduce full control over keeping
vs. discarding the injected module as being discussed in:
	compile: objfiles lifetime UI
	https://sourceware.org/ml/gdb/2015-04/msg00051.html
	Message-ID: <20150429135735.GA16974@host1.jankratochvil.net>
	https://sourceware.org/ml/gdb/2015-05/msg00007.html

As decided by Phil it is better not to leak inferior pages as users can
workaround the issue above for example by:
	(gdb) compile code str = strdup ("bar");

I have checked that in fact gdb/doc/ (written by Phil) already expects the
injected code will be unmapped so that does not need to be changed:
	compile code int ff = 5; p = &ff;
	In this example, @code{p} would point to @code{ff} when the
	@code{compile} command is executing the source code provided to it.
	However, as variables in the (example) program persist with their
	assigned values, the variable @code{p} would point to an invalid
	location when the command exists.

gdb/ChangeLog
2015-04-28  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* arch-utils.c (default_infcall_munmap): New.
	* arch-utils.h (default_infcall_munmap): New declaration.
	* compile/compile-object-load.c (struct munmap_list, munmap_list_add)
	(munmap_list_free, munmap_listp_free_cleanup): New.
	(struct setup_sections_data): Add field munmap_list_headp.
	(setup_sections): Call munmap_list_add.
	(compile_object_load): New variable munmap_list_head, initialize
	setup_sections_data.munmap_list_headp, return munmap_list_head.
	* compile/compile-object-load.h (struct munmap_list): New declaration.
	(struct compile_module): Add field munmap_list_head.
	(munmap_list_free): New declaration.
	* compile/compile-object-run.c (struct do_module_cleanup): Add field
	munmap_list_head.
	(do_module_cleanup): Call munmap_list_free.
	(compile_object_run): Pass munmap_list_head to do_module_cleanup.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.
	* gdbarch.sh (infcall_munmap): New.
	* linux-tdep.c (linux_infcall_munmap): New.
	(linux_init_abi): Install it.

gdb/testsuite/ChangeLog
2015-04-28  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.compile/compile.exp (keep jit in memory): Rename to ...
	(do not keep jit in memory): ... this.
	(expect 5): Change it to ...
	(expect no 5): ... this.
This commit is contained in:
Jan Kratochvil 2015-06-03 21:22:56 +02:00
parent f277626b45
commit 7f36105668
12 changed files with 185 additions and 3 deletions

View File

@ -1,3 +1,26 @@
2015-06-03 Jan Kratochvil <jan.kratochvil@redhat.com>
* arch-utils.c (default_infcall_munmap): New.
* arch-utils.h (default_infcall_munmap): New declaration.
* compile/compile-object-load.c (struct munmap_list, munmap_list_add)
(munmap_list_free, munmap_listp_free_cleanup): New.
(struct setup_sections_data): Add field munmap_list_headp.
(setup_sections): Call munmap_list_add.
(compile_object_load): New variable munmap_list_head, initialize
setup_sections_data.munmap_list_headp, return munmap_list_head.
* compile/compile-object-load.h (struct munmap_list): New declaration.
(struct compile_module): Add field munmap_list_head.
(munmap_list_free): New declaration.
* compile/compile-object-run.c (struct do_module_cleanup): Add field
munmap_list_head.
(do_module_cleanup): Call munmap_list_free.
(compile_object_run): Pass munmap_list_head to do_module_cleanup.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* gdbarch.sh (infcall_munmap): New.
* linux-tdep.c (linux_infcall_munmap): New.
(linux_init_abi): Install it.
2015-06-02 Simon Marchi <simon.marchi@ericsson.com>
PR gdb/15564

View File

@ -864,6 +864,12 @@ default_infcall_mmap (CORE_ADDR size, unsigned prot)
error (_("This target does not support inferior memory allocation by mmap."));
}
void
default_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
{
/* Memory reserved by inferior mmap is kept leaked. */
}
/* -mcmodel=large is used so that no GOT (Global Offset Table) is needed to be
created in inferior memory by GDB (normally it is set by ld.so). */

View File

@ -200,6 +200,7 @@ extern void default_skip_permanent_breakpoint (struct regcache *regcache);
#define GDB_MMAP_PROT_EXEC 0x4 /* Page can be executed. */
extern CORE_ADDR default_infcall_mmap (CORE_ADDR size, unsigned prot);
extern void default_infcall_munmap (CORE_ADDR addr, CORE_ADDR size);
extern char *default_gcc_target_options (struct gdbarch *gdbarch);
extern const char *default_gnu_triplet_regexp (struct gdbarch *gdbarch);

View File

@ -32,6 +32,58 @@
#include "block.h"
#include "arch-utils.h"
/* Track inferior memory reserved by inferior mmap. */
struct munmap_list
{
struct munmap_list *next;
CORE_ADDR addr, size;
};
/* Add inferior mmap memory range ADDR..ADDR+SIZE (exclusive) to list
HEADP. *HEADP needs to be initialized to NULL. */
static void
munmap_list_add (struct munmap_list **headp, CORE_ADDR addr, CORE_ADDR size)
{
struct munmap_list *head_new = xmalloc (sizeof (*head_new));
head_new->next = *headp;
*headp = head_new;
head_new->addr = addr;
head_new->size = size;
}
/* Free list of inferior mmap memory ranges HEAD. HEAD is the first
element of the list, it can be NULL. After calling this function
HEAD pointer is invalid and the possible list needs to be
reinitialized by caller to NULL. */
void
munmap_list_free (struct munmap_list *head)
{
while (head)
{
struct munmap_list *todo = head;
head = todo->next;
gdbarch_infcall_munmap (target_gdbarch (), todo->addr, todo->size);
xfree (todo);
}
}
/* Stub for munmap_list_free suitable for make_cleanup. Contrary to
munmap_list_free this function's parameter is a pointer to the first
list element pointer. */
static void
munmap_listp_free_cleanup (void *headp_voidp)
{
struct munmap_list **headp = headp_voidp;
munmap_list_free (*headp);
}
/* Helper data for setup_sections. */
struct setup_sections_data
@ -48,6 +100,10 @@ struct setup_sections_data
/* Maximum of alignments of all sections matching LAST_PROT.
This value is always at least 1. This value is always a power of 2. */
CORE_ADDR last_max_alignment;
/* List of inferior mmap ranges where setup_sections should add its
next range. */
struct munmap_list **munmap_list_headp;
};
/* Place all ABFD sections next to each other obeying all constraints. */
@ -97,6 +153,7 @@ setup_sections (bfd *abfd, asection *sect, void *data_voidp)
{
addr = gdbarch_infcall_mmap (target_gdbarch (), data->last_size,
data->last_prot);
munmap_list_add (data->munmap_list_headp, addr, data->last_size);
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"allocated %s bytes at %s prot %u\n",
@ -580,6 +637,7 @@ compile_object_load (const char *object_file, const char *source_file,
struct objfile *objfile;
int expect_parameters;
struct type *expect_return_type;
struct munmap_list *munmap_list_head = NULL;
filename = tilde_expand (object_file);
cleanups = make_cleanup (xfree, filename);
@ -601,6 +659,8 @@ compile_object_load (const char *object_file, const char *source_file,
setup_sections_data.last_section_first = abfd->sections;
setup_sections_data.last_prot = -1;
setup_sections_data.last_max_alignment = 1;
setup_sections_data.munmap_list_headp = &munmap_list_head;
make_cleanup (munmap_listp_free_cleanup, &munmap_list_head);
bfd_map_over_sections (abfd, setup_sections, &setup_sections_data);
setup_sections (abfd, NULL, &setup_sections_data);
@ -715,6 +775,7 @@ compile_object_load (const char *object_file, const char *source_file,
TYPE_LENGTH (regs_type),
GDB_MMAP_PROT_READ);
gdb_assert (regs_addr != 0);
munmap_list_add (&munmap_list_head, regs_addr, TYPE_LENGTH (regs_type));
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"allocated %s bytes at %s for registers\n",
@ -739,6 +800,8 @@ compile_object_load (const char *object_file, const char *source_file,
(GDB_MMAP_PROT_READ
| GDB_MMAP_PROT_WRITE));
gdb_assert (out_value_addr != 0);
munmap_list_add (&munmap_list_head, out_value_addr,
TYPE_LENGTH (out_value_type));
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"allocated %s bytes at %s for printed value\n",
@ -748,7 +811,6 @@ compile_object_load (const char *object_file, const char *source_file,
}
discard_cleanups (cleanups_free_objfile);
do_cleanups (cleanups);
retval = xmalloc (sizeof (*retval));
retval->objfile = objfile;
@ -759,5 +821,12 @@ compile_object_load (const char *object_file, const char *source_file,
retval->scope_data = scope_data;
retval->out_value_type = out_value_type;
retval->out_value_addr = out_value_addr;
/* CLEANUPS will free MUNMAP_LIST_HEAD. */
retval->munmap_list_head = munmap_list_head;
munmap_list_head = NULL;
do_cleanups (cleanups);
return retval;
}

View File

@ -17,6 +17,8 @@
#ifndef GDB_COMPILE_OBJECT_LOAD_H
#define GDB_COMPILE_OBJECT_LOAD_H
struct munmap_list;
struct compile_module
{
/* objfile for the compiled module. */
@ -45,10 +47,14 @@ struct compile_module
/* If the inferior function has an out value, this is its address.
Otherwise it is zero. */
CORE_ADDR out_value_addr;
/* Track inferior memory reserved by inferior mmap. */
struct munmap_list *munmap_list_head;
};
extern struct compile_module *compile_object_load
(const char *object_file, const char *source_file,
enum compile_i_scope_types scope, void *scope_data);
extern void munmap_list_free (struct munmap_list *head);
#endif /* GDB_COMPILE_OBJECT_LOAD_H */

View File

@ -47,6 +47,9 @@ struct do_module_cleanup
struct type *out_value_type;
CORE_ADDR out_value_addr;
/* Copy from struct compile_module. */
struct munmap_list *munmap_list_head;
/* objfile_name of our objfile. */
char objfile_name_string[1];
};
@ -96,6 +99,8 @@ do_module_cleanup (void *arg, int registers_valid)
unlink (data->source_file);
xfree (data->source_file);
munmap_list_free (data->munmap_list_head);
/* Delete the .o file. */
unlink (data->objfile_name_string);
xfree (data);
@ -128,6 +133,7 @@ compile_object_run (struct compile_module *module)
data->scope_data = module->scope_data;
data->out_value_type = module->out_value_type;
data->out_value_addr = module->out_value_addr;
data->munmap_list_head = module->munmap_list_head;
xfree (module->source_file);
xfree (module);

View File

@ -326,6 +326,7 @@ struct gdbarch
gdbarch_auxv_parse_ftype *auxv_parse;
gdbarch_vsyscall_range_ftype *vsyscall_range;
gdbarch_infcall_mmap_ftype *infcall_mmap;
gdbarch_infcall_munmap_ftype *infcall_munmap;
gdbarch_gcc_target_options_ftype *gcc_target_options;
gdbarch_gnu_triplet_regexp_ftype *gnu_triplet_regexp;
};
@ -426,6 +427,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
gdbarch->insn_is_jump = default_insn_is_jump;
gdbarch->vsyscall_range = default_vsyscall_range;
gdbarch->infcall_mmap = default_infcall_mmap;
gdbarch->infcall_munmap = default_infcall_munmap;
gdbarch->gcc_target_options = default_gcc_target_options;
gdbarch->gnu_triplet_regexp = default_gnu_triplet_regexp;
/* gdbarch_alloc() */
@ -658,6 +660,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of auxv_parse, has predicate. */
/* Skip verify of vsyscall_range, invalid_p == 0 */
/* Skip verify of infcall_mmap, invalid_p == 0 */
/* Skip verify of infcall_munmap, invalid_p == 0 */
/* Skip verify of gcc_target_options, invalid_p == 0 */
/* Skip verify of gnu_triplet_regexp, invalid_p == 0 */
buf = ui_file_xstrdup (log, &length);
@ -1028,6 +1031,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: infcall_mmap = <%s>\n",
host_address_to_string (gdbarch->infcall_mmap));
fprintf_unfiltered (file,
"gdbarch_dump: infcall_munmap = <%s>\n",
host_address_to_string (gdbarch->infcall_munmap));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_info_proc_p() = %d\n",
gdbarch_info_proc_p (gdbarch));
@ -4673,6 +4679,23 @@ set_gdbarch_infcall_mmap (struct gdbarch *gdbarch,
gdbarch->infcall_mmap = infcall_mmap;
}
void
gdbarch_infcall_munmap (struct gdbarch *gdbarch, CORE_ADDR addr, CORE_ADDR size)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->infcall_munmap != NULL);
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_infcall_munmap called\n");
gdbarch->infcall_munmap (addr, size);
}
void
set_gdbarch_infcall_munmap (struct gdbarch *gdbarch,
gdbarch_infcall_munmap_ftype infcall_munmap)
{
gdbarch->infcall_munmap = infcall_munmap;
}
char *
gdbarch_gcc_target_options (struct gdbarch *gdbarch)
{

View File

@ -1440,6 +1440,13 @@ typedef CORE_ADDR (gdbarch_infcall_mmap_ftype) (CORE_ADDR size, unsigned prot);
extern CORE_ADDR gdbarch_infcall_mmap (struct gdbarch *gdbarch, CORE_ADDR size, unsigned prot);
extern void set_gdbarch_infcall_mmap (struct gdbarch *gdbarch, gdbarch_infcall_mmap_ftype *infcall_mmap);
/* Deallocate SIZE bytes of memory at ADDR in inferior from gdbarch_infcall_mmap.
Print a warning if it is not possible. */
typedef void (gdbarch_infcall_munmap_ftype) (CORE_ADDR addr, CORE_ADDR size);
extern void gdbarch_infcall_munmap (struct gdbarch *gdbarch, CORE_ADDR addr, CORE_ADDR size);
extern void set_gdbarch_infcall_munmap (struct gdbarch *gdbarch, gdbarch_infcall_munmap_ftype *infcall_munmap);
/* Return string (caller has to use xfree for it) with options for GCC
to produce code for this target, typically "-m64", "-m32" or "-m31".
These options are put before CU's DW_AT_producer compilation options so that

View File

@ -1097,6 +1097,10 @@ m:int:vsyscall_range:struct mem_range *range:range::default_vsyscall_range::0
# Throw an error if it is not possible. Returned address is always valid.
f:CORE_ADDR:infcall_mmap:CORE_ADDR size, unsigned prot:size, prot::default_infcall_mmap::0
# Deallocate SIZE bytes of memory at ADDR in inferior from gdbarch_infcall_mmap.
# Print a warning if it is not possible.
f:void:infcall_munmap:CORE_ADDR addr, CORE_ADDR size:addr, size::default_infcall_munmap::0
# Return string (caller has to use xfree for it) with options for GCC
# to produce code for this target, typically "-m64", "-m32" or "-m31".
# These options are put before CU's DW_AT_producer compilation options so that

View File

@ -2348,6 +2348,35 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
return retval;
}
/* See gdbarch.sh 'infcall_munmap'. */
static void
linux_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
{
struct objfile *objf;
struct value *munmap_val = find_function_in_inferior ("munmap", &objf);
struct value *retval_val;
struct gdbarch *gdbarch = get_objfile_arch (objf);
LONGEST retval;
enum
{
ARG_ADDR, ARG_LENGTH, ARG_LAST
};
struct value *arg[ARG_LAST];
arg[ARG_ADDR] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr,
addr);
/* Assuming sizeof (unsigned long) == sizeof (size_t). */
arg[ARG_LENGTH] = value_from_ulongest
(builtin_type (gdbarch)->builtin_unsigned_long, size);
retval_val = call_function_by_hand (munmap_val, ARG_LAST, arg);
retval = value_as_long (retval_val);
if (retval != 0)
warning (_("Failed inferior munmap call at %s for %s bytes, "
"errno is changed."),
hex_string (addr), pulongest (size));
}
/* See linux-tdep.h. */
CORE_ADDR
@ -2409,6 +2438,7 @@ linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
linux_gdb_signal_to_target);
set_gdbarch_vsyscall_range (gdbarch, linux_vsyscall_range);
set_gdbarch_infcall_mmap (gdbarch, linux_infcall_mmap);
set_gdbarch_infcall_munmap (gdbarch, linux_infcall_munmap);
}
/* Provide a prototype to silence -Wmissing-prototypes. */

View File

@ -1,3 +1,10 @@
2015-06-03 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.compile/compile.exp (keep jit in memory): Rename to ...
(do not keep jit in memory): ... this.
(expect 5): Change it to ...
(expect no 5): ... this.
2015-06-02 Simon Marchi <simon.marchi@ericsson.com>
PR gdb/15564

View File

@ -131,8 +131,8 @@ gdb_test_no_output "compile code globalvar = static_local"
gdb_test "p globalvar" " = 77000" "check static_local"
gdb_test_no_output "compile code static int staticvar = 5; intptr = &staticvar" \
"keep jit in memory"
gdb_test "p *intptr" " = 5" "expect 5"
"do not keep jit in memory"
gdb_test "p *intptr" "Cannot access memory at address 0x\[0-9a-f\]+" "expect no 5"
gdb_test "compile code func_doesnotexist ();" "warning: Could not find symbol \"func_doesnotexist\" for .*"