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:
parent
f277626b45
commit
7f36105668
@ -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
|
||||
|
@ -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). */
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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 .*"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user