[patchv6] compile: Use also inferior munmap

Message ID 20150516131850.GA16793@host1.jankratochvil.net
State New, archived
Headers

Commit Message

Jan Kratochvil May 16, 2015, 1:18 p.m. UTC
  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

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.


Jan
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.
  

Patch

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-c-symbols.c b/gdb/compile/compile-c-symbols.c
index 15efeff..455114c 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -338,7 +338,7 @@  convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
 	  && block_found != block_static_block (block_found))
 	{
 	  if (compile_debug)
-	    fprintf_unfiltered (gdb_stdout,
+	    fprintf_unfiltered (gdb_stdlog,
 				"gcc_convert_symbol \"%s\": global symbol\n",
 				identifier);
 	  convert_one_symbol (context, global_sym, 1, 0);
@@ -346,7 +346,7 @@  convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
     }
 
   if (compile_debug)
-    fprintf_unfiltered (gdb_stdout,
+    fprintf_unfiltered (gdb_stdlog,
 			"gcc_convert_symbol \"%s\": local symbol\n",
 			identifier);
   convert_one_symbol (context, sym, 0, is_local_symbol);
@@ -473,7 +473,7 @@  gcc_convert_symbol (void *datum,
   END_CATCH
 
   if (compile_debug && !found)
-    fprintf_unfiltered (gdb_stdout,
+    fprintf_unfiltered (gdb_stdlog,
 			"gcc_convert_symbol \"%s\": lookup_symbol failed\n",
 			identifier);
   return;
@@ -500,7 +500,7 @@  gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
       if (sym != NULL && SYMBOL_CLASS (sym) == LOC_BLOCK)
 	{
 	  if (compile_debug)
-	    fprintf_unfiltered (gdb_stdout,
+	    fprintf_unfiltered (gdb_stdlog,
 				"gcc_symbol_address \"%s\": full symbol\n",
 				identifier);
 	  result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
@@ -516,7 +516,7 @@  gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
 	  if (msym.minsym != NULL)
 	    {
 	      if (compile_debug)
-		fprintf_unfiltered (gdb_stdout,
+		fprintf_unfiltered (gdb_stdlog,
 				    "gcc_symbol_address \"%s\": minimal "
 				    "symbol\n",
 				    identifier);
@@ -535,7 +535,7 @@  gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
   END_CATCH
 
   if (compile_debug && !found)
-    fprintf_unfiltered (gdb_stdout,
+    fprintf_unfiltered (gdb_stdlog,
 			"gcc_symbol_address \"%s\": failed\n",
 			identifier);
   return result;
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index ed5ef88..31f4bde 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.  */
@@ -76,7 +132,7 @@  setup_sections (bfd *abfd, asection *sect, void *data_voidp)
 	prot |= GDB_MMAP_PROT_EXEC;
 
       if (compile_debug)
-	fprintf_unfiltered (gdb_stdout,
+	fprintf_unfiltered (gdb_stdlog,
 			    "module \"%s\" section \"%s\" size %s prot %u\n",
 			    bfd_get_filename (abfd),
 			    bfd_get_section_name (abfd, sect),
@@ -97,8 +153,9 @@  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,
+	    fprintf_unfiltered (gdb_stdlog,
 				"allocated %s bytes at %s prot %u\n",
 				paddress (target_gdbarch (), data->last_size),
 				paddress (target_gdbarch (), addr),
@@ -576,6 +633,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);
@@ -597,6 +655,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);
 
@@ -668,7 +728,7 @@  compile_object_load (const char *object_file, const char *source_file,
       if (sym->flags != 0)
 	continue;
       if (compile_debug)
-	fprintf_unfiltered (gdb_stdout,
+	fprintf_unfiltered (gdb_stdlog,
 			    "lookup undefined ELF symbol \"%s\"\n",
 			    sym->name);
       sym->flags = BSF_GLOBAL;
@@ -711,8 +771,9 @@  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,
+	fprintf_unfiltered (gdb_stdlog,
 			    "allocated %s bytes at %s for registers\n",
 			    paddress (target_gdbarch (),
 				      TYPE_LENGTH (regs_type)),
@@ -735,8 +796,10 @@  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,
+	fprintf_unfiltered (gdb_stdlog,
 			    "allocated %s bytes at %s for printed value\n",
 			    paddress (target_gdbarch (),
 				      TYPE_LENGTH (out_value_type)),
@@ -744,7 +807,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;
@@ -755,5 +817,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;
 }
diff --git a/gdb/compile/compile-object-load.h b/gdb/compile/compile-object-load.h
index 5afacda..44a7592 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
   /* 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 */
diff --git a/gdb/compile/compile-object-run.c b/gdb/compile/compile-object-run.c
index 771a209..ce47831 100644
--- a/gdb/compile/compile-object-run.c
+++ b/gdb/compile/compile-object-run.c
@@ -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);
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index fbecf8c..499c530 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -528,7 +528,7 @@  compile_to_object (struct command_line *cmd, const char *cmd_string,
 					       expr_block, expr_pc);
   make_cleanup (xfree, code);
   if (compile_debug)
-    fprintf_unfiltered (gdb_stdout, "debug output:\n\n%s", code);
+    fprintf_unfiltered (gdb_stdlog, "debug output:\n\n%s", code);
 
   os_rx = osabi_triplet_regexp (gdbarch_osabi (gdbarch));
   arch_rx = gdbarch_gnu_triplet_regexp (gdbarch);
@@ -553,9 +553,9 @@  compile_to_object (struct command_line *cmd, const char *cmd_string,
     {
       int argi;
 
-      fprintf_unfiltered (gdb_stdout, "Passing %d compiler options:\n", argc);
+      fprintf_unfiltered (gdb_stdlog, "Passing %d compiler options:\n", argc);
       for (argi = 0; argi < argc; argi++)
-	fprintf_unfiltered (gdb_stdout, "Compiler option %d: <%s>\n",
+	fprintf_unfiltered (gdb_stdlog, "Compiler option %d: <%s>\n",
 			    argi, argv[argi]);
     }
 
@@ -572,7 +572,7 @@  compile_to_object (struct command_line *cmd, const char *cmd_string,
   fclose (src);
 
   if (compile_debug)
-    fprintf_unfiltered (gdb_stdout, "source file produced: %s\n\n",
+    fprintf_unfiltered (gdb_stdlog, "source file produced: %s\n\n",
 			source_file);
 
   /* Call the compiler and start the compilation process.  */
@@ -583,7 +583,7 @@  compile_to_object (struct command_line *cmd, const char *cmd_string,
     error (_("Compilation failed."));
 
   if (compile_debug)
-    fprintf_unfiltered (gdb_stdout, "object file produced: %s\n\n",
+    fprintf_unfiltered (gdb_stdlog, "object file produced: %s\n\n",
 			object_file);
 
   discard_cleanups (inner_cleanup);
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 df42097..8ce2f34 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 .*"