From patchwork Wed May 13 20:17:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kratochvil X-Patchwork-Id: 6718 Received: (qmail 12487 invoked by alias); 13 May 2015 20:17:22 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 12435 invoked by uid 89); 13 May 2015 20:17:21 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.3 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Wed, 13 May 2015 20:17:17 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t4DKHF4I027758 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Wed, 13 May 2015 16:17:16 -0400 Received: from host1.jankratochvil.net (ovpn-116-27.ams2.redhat.com [10.36.116.27]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t4DKHD6G026675; Wed, 13 May 2015 16:17:14 -0400 Subject: [PATCH v5 7/7] RFC only: compile: Use also inferior munmap From: Jan Kratochvil To: gdb-patches@sourceware.org Cc: Phil Muldoon Date: Wed, 13 May 2015 22:17:13 +0200 Message-ID: <20150513201713.4051.94462.stgit@host1.jankratochvil.net> In-Reply-To: <20150513201615.4051.5261.stgit@host1.jankratochvil.net> References: <20150513201615.4051.5261.stgit@host1.jankratochvil.net> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-IsSubscribed: yes Hi, 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 This patch at least introduces code which will be needed for the part/cases of really freeing all the resources of an injected module. It is "RFC only" as given the patch as is it regresses GDB functionality. Jan gdb/ChangeLog 2015-04-28 Jan Kratochvil * 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 * 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. --- gdb/arch-utils.c | 6 +++ gdb/arch-utils.h | 1 gdb/compile/compile-object-load.c | 71 +++++++++++++++++++++++++++++++++ gdb/compile/compile-object-load.h | 6 +++ gdb/compile/compile-object-run.c | 6 +++ gdb/gdbarch.c | 23 +++++++++++ gdb/gdbarch.h | 7 +++ gdb/gdbarch.sh | 4 ++ gdb/linux-tdep.c | 30 ++++++++++++++ gdb/testsuite/gdb.compile/compile.exp | 4 +- 10 files changed, 155 insertions(+), 3 deletions(-) diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index e1c8ab0..362c71b 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -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). */ diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index ed3bec9..f40e076 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -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); diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c index ad940b2..50d02bf 100644 --- a/gdb/compile/compile-object-load.c +++ b/gdb/compile/compile-object-load.c @@ -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_stdout, "allocated %s bytes at %s prot %u\n", @@ -578,6 +635,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); @@ -599,6 +657,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); @@ -713,6 +773,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_stdout, "allocated %s bytes at %s for registers\n", @@ -737,6 +798,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_stdout, "allocated %s bytes at %s for printed value\n", @@ -746,7 +809,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; @@ -757,5 +819,12 @@ compile_object_load (const char *object_file, const char *source_file, retval->scope_data = scope_data; retval->out_value_addr = out_value_addr; retval->out_value_type = out_value_type; + + /* CLEANUPS will free MUNMAP_LIST_HEAD. */ + retval->munmap_list_head = munmap_list_head; + munmap_list_head = NULL; + + do_cleanups (cleanups); + return retval; } diff --git a/gdb/compile/compile-object-load.h b/gdb/compile/compile-object-load.h index 3e0e45b..61d8563 100644 --- a/gdb/compile/compile-object-load.h +++ b/gdb/compile/compile-object-load.h @@ -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 /* Inferior parameter out value type or NULL if the inferior function does not have one. */ struct type *out_value_type; + + /* 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 */ diff --git a/gdb/compile/compile-object-run.c b/gdb/compile/compile-object-run.c index 9e11c00..d5cc892 100644 --- a/gdb/compile/compile-object-run.c +++ b/gdb/compile/compile-object-run.c @@ -47,6 +47,9 @@ struct do_module_cleanup CORE_ADDR out_value_addr; struct type *out_value_type; + /* 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_addr = module->out_value_addr; data->out_value_type = module->out_value_type; + data->munmap_list_head = module->munmap_list_head; xfree (module->source_file); xfree (module); diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 97874c9..aa2789e 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -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); @@ -1029,6 +1032,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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)); fprintf_unfiltered (file, @@ -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) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index c94c19c..59882df 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -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 diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 0f303a4..f719ec1 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -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 diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 9d75b66..8cb91c9 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -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. */ diff --git a/gdb/testsuite/gdb.compile/compile.exp b/gdb/testsuite/gdb.compile/compile.exp index 07276bd..dd46a5f 100644 --- a/gdb/testsuite/gdb.compile/compile.exp +++ b/gdb/testsuite/gdb.compile/compile.exp @@ -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 .*"