+++ /dev/null
-#include <dlfcn.h>
-#include <stdio.h>
-
-int main (int argc, char *argv[])
-{
- /* jit_libname is updated by jit-so.exp */
- const char *jit_libname = "jit-dlmain-so.so";
- void *h;
- int (*p_main) (int, char **);
-
- h = NULL; /* break here before-dlopen */
- h = dlopen (jit_libname, RTLD_LAZY);
- if (h == NULL) return 1;
-
- p_main = dlsym (h, "jit_dl_main");
- if (p_main == NULL) return 2;
-
- h = h; /* break here after-dlopen */
- return (*p_main) (argc, argv);
-}
--- /dev/null
+#include <dlfcn.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[])
+{
+ /* jit_libname is updated by jit-so.exp */
+ const char *jit_libname = "jit-dlmain-so.so";
+ void *h;
+ int (*p_main) (int, char **);
+
+ h = NULL; /* break here before-dlopen */
+ h = dlopen (jit_libname, RTLD_LAZY);
+ if (h == NULL) return 1;
+
+ p_main = dlsym (h, "jit_dl_main");
+ if (p_main == NULL) return 2;
+
+ h = h; /* break here after-dlopen */
+ return (*p_main) (argc, argv);
+}
--- /dev/null
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 2011-2020 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Simulate loading of JIT code. */
+
+#include <elf.h>
+#include <link.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* ElfW is coming from linux. On other platforms it does not exist.
+ Let us define it here. */
+#ifndef ElfW
+# if (defined (_LP64) || defined (__LP64__))
+# define WORDSIZE 64
+# else
+# define WORDSIZE 32
+# endif /* _LP64 || __LP64__ */
+#define ElfW(type) _ElfW (Elf, WORDSIZE, type)
+#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
+#define _ElfW_1(e,w,t) e##w##t
+#endif /* !ElfW */
+
+typedef enum
+{
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry
+{
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ uint64_t symfile_size;
+};
+
+struct jit_descriptor
+{
+ uint32_t version;
+ /* This type should be jit_actions_t, but we use uint32_t
+ to be explicit about the bitwidth. */
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+
+/* GDB puts a breakpoint in this function. */
+void __attribute__((noinline)) __jit_debug_register_code () { }
+
+/* Make sure to specify the version statically, because the
+ debugger may check the version before we can set it. */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+static void
+usage (const char *const argv0)
+{
+ fprintf (stderr, "Usage: %s library [count]\n", argv0);
+ exit (1);
+}
+
+/* Update .p_vaddr and .sh_addr as if the code was JITted to ADDR. */
+
+static void
+update_locations (const void *const addr, int idx)
+{
+ const ElfW (Ehdr) *const ehdr = (ElfW (Ehdr) *)addr;
+ ElfW (Shdr) *const shdr = (ElfW (Shdr) *)((char *)addr + ehdr->e_shoff);
+ ElfW (Phdr) *const phdr = (ElfW (Phdr) *)((char *)addr + ehdr->e_phoff);
+ int i;
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ if (phdr[i].p_type == PT_LOAD)
+ phdr[i].p_vaddr += (ElfW (Addr))addr;
+
+ for (i = 0; i < ehdr->e_shnum; ++i)
+ {
+ if (shdr[i].sh_type == SHT_STRTAB)
+ {
+ /* Note: we update both .strtab and .dynstr. The latter would
+ not be correct if this were a regular shared library (.hash
+ would be wrong), but this is a simulation -- the library is
+ never exposed to the dynamic loader, so it all ends up ok. */
+ char *const strtab = (char *)((ElfW (Addr))addr + shdr[i].sh_offset);
+ char *const strtab_end = strtab + shdr[i].sh_size;
+ char *p;
+
+ for (p = strtab; p < strtab_end; p += strlen (p) + 1)
+ if (strcmp (p, "jit_function_XXXX") == 0)
+ sprintf (p, "jit_function_%04d", idx);
+ }
+
+ if (shdr[i].sh_flags & SHF_ALLOC)
+ shdr[i].sh_addr += (ElfW (Addr))addr;
+ }
+}
+
+/* Defined by the .exp file if testing attach. */
+#ifndef ATTACH
+#define ATTACH 0
+#endif
+
+#ifndef MAIN
+#define MAIN main
+#endif
+
+/* Used to spin waiting for GDB. */
+volatile int wait_for_gdb = ATTACH;
+#define WAIT_FOR_GDB do {} while (wait_for_gdb)
+
+/* The current process's PID. GDB retrieves this. */
+int mypid;
+
+int
+MAIN (int argc, char *argv[])
+{
+ /* These variables are here so they can easily be set from jit.exp. */
+ const char *libname = NULL;
+ int count = 0, i, fd;
+ struct stat st;
+
+ alarm (300);
+
+ mypid = getpid ();
+
+ count = count; /* gdb break here 0 */
+
+ if (argc < 2)
+ {
+ usage (argv[0]);
+ exit (1);
+ }
+
+ if (libname == NULL)
+ /* Only set if not already set from GDB. */
+ libname = argv[1];
+
+ if (argc > 2 && count == 0)
+ /* Only set if not already set from GDB. */
+ count = atoi (argv[2]);
+
+ printf ("%s:%d: libname = %s, count = %d\n", __FILE__, __LINE__,
+ libname, count);
+
+ if ((fd = open (libname, O_RDONLY)) == -1)
+ {
+ fprintf (stderr, "open (\"%s\", O_RDONLY): %s\n", libname,
+ strerror (errno));
+ exit (1);
+ }
+
+ if (fstat (fd, &st) != 0)
+ {
+ fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno));
+ exit (1);
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ const void *const addr = mmap (0, st.st_size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ struct jit_code_entry *const entry = calloc (1, sizeof (*entry));
+
+ if (addr == MAP_FAILED)
+ {
+ fprintf (stderr, "mmap: %s\n", strerror (errno));
+ exit (1);
+ }
+
+ update_locations (addr, i);
+
+ /* Link entry at the end of the list. */
+ entry->symfile_addr = (const char *)addr;
+ entry->symfile_size = st.st_size;
+ entry->prev_entry = __jit_debug_descriptor.relevant_entry;
+ __jit_debug_descriptor.relevant_entry = entry;
+
+ if (entry->prev_entry != NULL)
+ entry->prev_entry->next_entry = entry;
+ else
+ __jit_debug_descriptor.first_entry = entry;
+
+ /* Notify GDB. */
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+ __jit_debug_register_code ();
+ }
+
+ WAIT_FOR_GDB; i = 0; /* gdb break here 1 */
+
+ /* Now unregister them all in reverse order. */
+ while (__jit_debug_descriptor.relevant_entry != NULL)
+ {
+ struct jit_code_entry *const entry =
+ __jit_debug_descriptor.relevant_entry;
+ struct jit_code_entry *const prev_entry = entry->prev_entry;
+
+ if (prev_entry != NULL)
+ {
+ prev_entry->next_entry = NULL;
+ entry->prev_entry = NULL;
+ }
+ else
+ __jit_debug_descriptor.first_entry = NULL;
+
+ /* Notify GDB. */
+ __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
+ __jit_debug_register_code ();
+
+ __jit_debug_descriptor.relevant_entry = prev_entry;
+ free (entry);
+ }
+
+ WAIT_FOR_GDB; return 0; /* gdb break here 2 */
+}
--- /dev/null
+# Copyright 2011-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# The same tests as in jit.exp, but loading JITer itself from a shared
+# library.
+
+if {[skip_shlib_tests]} {
+ untested "skipping shared library tests"
+ return -1
+}
+
+if {[get_compiler_info]} {
+ untested "could not get compiler info"
+ return 1
+}
+
+#
+# test running programs
+#
+
+set testfile jit-elf-dlmain
+set srcfile ${testfile}.c
+set binfile [standard_output_file ${testfile}]
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug shlib_load}] != "" } {
+ untested "failed to compile"
+ return -1
+}
+
+set testfile2 jit-elf-main
+set srcfile2 ${testfile2}.c
+set binfile2 [standard_output_file ${testfile2}.so]
+set binfile2_dlopen [shlib_target_file ${testfile2}.so]
+if { [gdb_compile_shlib "${srcdir}/${subdir}/${srcfile2}" ${binfile2} {debug additional_flags="-DMAIN=jit_dl_main"}] != "" } {
+ untested "failed to compile main shared library"
+ return -1
+}
+
+set solib_testfile "jit-elf-solib"
+set solib_srcfile "${srcdir}/${subdir}/${solib_testfile}.c"
+set solib_binfile [standard_output_file ${solib_testfile}.so]
+set solib_binfile_test_msg "SHLIBDIR/${solib_testfile}.so"
+
+# Note: compiling without debug info: the library goes through symbol
+# renaming by munging on its symbol table, and that wouldn't work for .debug
+# sections. Also, output for "info function" changes when debug info is resent.
+if { [gdb_compile_shlib ${solib_srcfile} ${solib_binfile} {}] != "" } {
+ untested "failed to compile jit shared library"
+ return -1
+}
+
+set solib_binfile_target [gdb_remote_download target ${solib_binfile}]
+
+proc one_jit_test {count match_str} {
+ with_test_prefix "one_jit_test-$count" {
+ global verbose testfile srcfile2 binfile2 binfile2_dlopen solib_binfile_target solib_binfile_test_msg
+
+ clean_restart $testfile
+ gdb_load_shlib $binfile2
+
+ # This is just to help debugging when things fail
+ if {$verbose > 0} {
+ gdb_test "set debug jit 1"
+ }
+
+ if { ![runto_main] } {
+ fail "can't run to main"
+ return
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break here before-dlopen" ]
+ gdb_continue_to_breakpoint "break here before-dlopen"
+ # Poke desired values directly into inferior instead of using "set args"
+ # because "set args" does not work under gdbserver.
+ gdb_test_no_output "set var jit_libname = \"$binfile2_dlopen\""
+
+ gdb_breakpoint [gdb_get_line_number "break here after-dlopen" ]
+ gdb_continue_to_breakpoint "break here after-dlopen"
+
+ gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 0} $srcfile2]"
+ gdb_continue_to_breakpoint "break here 0"
+
+ gdb_test_no_output "set var argc = 2"
+ gdb_test_no_output "set var libname = \"$solib_binfile_target\"" "set var libname = \"$solib_binfile_test_msg\""
+ gdb_test_no_output "set var count = $count"
+
+ gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 1} $srcfile2]"
+ gdb_continue_to_breakpoint "break here 1"
+
+ gdb_test "info function jit_function" "$match_str"
+
+ # This is just to help debugging when things fail
+ if {$verbose > 0} {
+ gdb_test "maintenance print objfiles"
+ gdb_test "maintenance info break"
+ }
+
+ gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 2} $srcfile2]"
+ gdb_continue_to_breakpoint "break here 2"
+ # All jit librares must have been unregistered
+ gdb_test "info function jit_function" \
+ "All functions matching regular expression \"jit_function\":"
+ }
+}
+
+one_jit_test 1 "${hex} jit_function_0000"
+one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001"
+
+# We don't intend to load the .so as a JIT debuginfo reader, but we
+# need some handy file name for a completion test.
+gdb_test \
+ "complete jit-reader-load [standard_output_file ${solib_testfile}.s]" \
+ "jit-reader-load $solib_binfile" \
+ "test jit-reader-load filename completion"
--- /dev/null
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 2011-2020 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This simulates a JIT library. The function is "renamed" after being
+ loaded into memory. */
+
+int jit_function_XXXX() { return 42; }
--- /dev/null
+# Copyright 2011-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if {[skip_shlib_tests]} {
+ untested "skipping shared library tests"
+ return -1
+}
+
+if {[get_compiler_info]} {
+ untested "could not get compiler info"
+ return 1
+}
+
+# Compile the testcase program and library. BINSUFFIX is the suffix
+# to append to the program and library filenames, to make them unique
+# between invocations. OPTIONS is passed to gdb_compile when
+# compiling the program.
+
+proc compile_jit_test {testname binsuffix options} {
+ global testfile srcfile binfile srcdir subdir
+ global solib_testfile solib_srcfile solib_binfile solib_binfile_test_msg
+ global solib_binfile_target
+
+ set testfile jit-elf-main
+ set srcfile ${testfile}.c
+ set binfile [standard_output_file $testfile$binsuffix]
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+ executable [concat debug $options]] != "" } {
+ untested $testname
+ return -1
+ }
+
+ set solib_testfile "jit-elf-solib"
+ set solib_srcfile "${srcdir}/${subdir}/${solib_testfile}.c"
+ set solib_binfile [standard_output_file ${solib_testfile}$binsuffix.so]
+ set solib_binfile_test_msg "SHLIBDIR/${solib_testfile}$binsuffix.so"
+
+ # Note: compiling without debug info: the library goes through
+ # symbol renaming by munging on its symbol table, and that
+ # wouldn't work for .debug sections. Also, output for "info
+ # function" changes when debug info is present.
+ if { [gdb_compile_shlib ${solib_srcfile} ${solib_binfile} {-fPIC}] != "" } {
+ untested $testname
+ return -1
+ }
+
+ set solib_binfile_target [gdb_remote_download target ${solib_binfile}]
+
+ return 0
+}
+
+# Detach, restart GDB, and re-attach to the program.
+
+proc clean_reattach {} {
+ global decimal gdb_prompt srcfile testfile
+
+ # Get PID of test program.
+ set testpid -1
+ set test "get inferior process ID"
+ gdb_test_multiple "p mypid" $test {
+ -re ".* = ($decimal).*$gdb_prompt $" {
+ set testpid $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ gdb_test_no_output "set var wait_for_gdb = 1"
+ gdb_test "detach" "Detaching from .*"
+
+ clean_restart $testfile
+
+ set test "attach"
+ gdb_test_multiple "attach $testpid" "$test" {
+ -re "Attaching to program.*.*main.*at .*$srcfile:.*$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+
+ gdb_test_no_output "set var wait_for_gdb = 0"
+}
+
+# Continue to LOCATION in the program. If REATTACH, detach and
+# re-attach to the program from scratch.
+proc continue_to_test_location {location reattach} {
+ gdb_breakpoint [gdb_get_line_number $location]
+ gdb_continue_to_breakpoint $location
+ if {$reattach} {
+ with_test_prefix "$location" {
+ clean_reattach
+ }
+ }
+}
+
+proc one_jit_test {count match_str reattach} {
+ with_test_prefix "one_jit_test-$count" {
+ global verbose testfile solib_binfile_target solib_binfile_test_msg
+
+ clean_restart $testfile
+
+ # This is just to help debugging when things fail
+ if {$verbose > 0} {
+ gdb_test "set debug jit 1"
+ }
+
+ if { ![runto_main] } {
+ fail "can't run to main"
+ return
+ }
+
+ gdb_breakpoint [gdb_get_line_number "break here 0"]
+ gdb_continue_to_breakpoint "break here 0"
+
+ # Poke desired values directly into inferior instead of using "set args"
+ # because "set args" does not work under gdbserver.
+ gdb_test_no_output "set var argc = 2"
+ gdb_test_no_output "set var libname = \"$solib_binfile_target\"" "set var libname = \"$solib_binfile_test_msg\""
+ gdb_test_no_output "set var count = $count"
+
+ continue_to_test_location "break here 1" $reattach
+
+ gdb_test "info function ^jit_function" "$match_str"
+
+ # This is just to help debugging when things fail
+ if {$verbose > 0} {
+ gdb_test "maintenance print objfiles"
+ gdb_test "maintenance info break"
+ }
+
+ continue_to_test_location "break here 2" $reattach
+
+ # All jit librares must have been unregistered
+ gdb_test "info function jit_function" \
+ "All functions matching regular expression \"jit_function\":"
+ }
+}
+
+if {[compile_jit_test jit.exp "" {}] < 0} {
+ return
+}
+one_jit_test 1 "${hex} jit_function_0000" 0
+one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001" 0
+
+# Test attaching to an inferior with some JIT libraries already
+# registered. We reuse the normal test, and detach/reattach at
+# specific interesting points.
+if {[can_spawn_for_attach]} {
+ if {[compile_jit_test "jit.exp attach tests" \
+ "-attach" {additional_flags=-DATTACH=1}] < 0} {
+ return
+ }
+
+ with_test_prefix attach {
+ one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001" 1
+ }
+}
+
+with_test_prefix PIE {
+ if {[compile_jit_test "jit.exp PIE tests" \
+ "-pie" {additional_flags=-fPIE ldflags=-pie}] < 0} {
+ return
+ }
+
+ one_jit_test 1 "${hex} jit_function_0000" 0
+}
+++ /dev/null
-/* This testcase is part of GDB, the GNU debugger.
-
- Copyright 2018-2020 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Simple standalone program using the JIT API. */
-
-#include "jit-simple-jit.c"
-#include <unistd.h>
-
-int
-main (int argc, char **argv)
-{
- execl (PROGRAM, PROGRAM, (char *) 0);
- return 99;
-}
+++ /dev/null
-# Copyright 2018-2020 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# Regression test for a jit.c bug. Previously it would crash if an
-# inferior that used the JIT API then exec'd a program that did not
-# use it.
-
-if { ![istarget "*-linux*"] } then {
- return
-}
-
-standard_testfile jit-exec.c
-
-set testfile2 "jit-execd"
-set srcfile2 ${testfile2}.c
-set binfile2 [standard_output_file ${testfile2}]
-
-set compile_options [list debug additional_flags=-DPROGRAM=\"$binfile2\"]
-
-if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
- executable $compile_options] != ""} {
- untested "failed to compile"
- return -1
-}
-
-if {[gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" \
- executable $compile_options] != ""} {
- untested "failed to compile"
- return -1
-}
-
-clean_restart $binfile
-
-if {![runto_main]} {
- fail "can't run to main"
- return
-}
-
-delete_breakpoints
-gdb_test "continue" "Inferior .* exited normally.*"
+++ /dev/null
-/* This testcase is part of GDB, the GNU debugger.
-
- Copyright 2018-2020 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-int
-main (int argc, char **argv)
-{
- return 0;
-}
+++ /dev/null
-/* This test program is part of GDB, the GNU debugger.
-
- Copyright 2011-2020 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Simulate loading of JIT code. */
-
-#include <elf.h>
-#include <link.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-/* ElfW is coming from linux. On other platforms it does not exist.
- Let us define it here. */
-#ifndef ElfW
-# if (defined (_LP64) || defined (__LP64__))
-# define WORDSIZE 64
-# else
-# define WORDSIZE 32
-# endif /* _LP64 || __LP64__ */
-#define ElfW(type) _ElfW (Elf, WORDSIZE, type)
-#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
-#define _ElfW_1(e,w,t) e##w##t
-#endif /* !ElfW */
-
-typedef enum
-{
- JIT_NOACTION = 0,
- JIT_REGISTER_FN,
- JIT_UNREGISTER_FN
-} jit_actions_t;
-
-struct jit_code_entry
-{
- struct jit_code_entry *next_entry;
- struct jit_code_entry *prev_entry;
- const char *symfile_addr;
- uint64_t symfile_size;
-};
-
-struct jit_descriptor
-{
- uint32_t version;
- /* This type should be jit_actions_t, but we use uint32_t
- to be explicit about the bitwidth. */
- uint32_t action_flag;
- struct jit_code_entry *relevant_entry;
- struct jit_code_entry *first_entry;
-};
-
-/* GDB puts a breakpoint in this function. */
-void __attribute__((noinline)) __jit_debug_register_code () { }
-
-/* Make sure to specify the version statically, because the
- debugger may check the version before we can set it. */
-struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
-
-static void
-usage (const char *const argv0)
-{
- fprintf (stderr, "Usage: %s library [count]\n", argv0);
- exit (1);
-}
-
-/* Update .p_vaddr and .sh_addr as if the code was JITted to ADDR. */
-
-static void
-update_locations (const void *const addr, int idx)
-{
- const ElfW (Ehdr) *const ehdr = (ElfW (Ehdr) *)addr;
- ElfW (Shdr) *const shdr = (ElfW (Shdr) *)((char *)addr + ehdr->e_shoff);
- ElfW (Phdr) *const phdr = (ElfW (Phdr) *)((char *)addr + ehdr->e_phoff);
- int i;
-
- for (i = 0; i < ehdr->e_phnum; ++i)
- if (phdr[i].p_type == PT_LOAD)
- phdr[i].p_vaddr += (ElfW (Addr))addr;
-
- for (i = 0; i < ehdr->e_shnum; ++i)
- {
- if (shdr[i].sh_type == SHT_STRTAB)
- {
- /* Note: we update both .strtab and .dynstr. The latter would
- not be correct if this were a regular shared library (.hash
- would be wrong), but this is a simulation -- the library is
- never exposed to the dynamic loader, so it all ends up ok. */
- char *const strtab = (char *)((ElfW (Addr))addr + shdr[i].sh_offset);
- char *const strtab_end = strtab + shdr[i].sh_size;
- char *p;
-
- for (p = strtab; p < strtab_end; p += strlen (p) + 1)
- if (strcmp (p, "jit_function_XXXX") == 0)
- sprintf (p, "jit_function_%04d", idx);
- }
-
- if (shdr[i].sh_flags & SHF_ALLOC)
- shdr[i].sh_addr += (ElfW (Addr))addr;
- }
-}
-
-/* Defined by the .exp file if testing attach. */
-#ifndef ATTACH
-#define ATTACH 0
-#endif
-
-#ifndef MAIN
-#define MAIN main
-#endif
-
-/* Used to spin waiting for GDB. */
-volatile int wait_for_gdb = ATTACH;
-#define WAIT_FOR_GDB do {} while (wait_for_gdb)
-
-/* The current process's PID. GDB retrieves this. */
-int mypid;
-
-int
-MAIN (int argc, char *argv[])
-{
- /* These variables are here so they can easily be set from jit.exp. */
- const char *libname = NULL;
- int count = 0, i, fd;
- struct stat st;
-
- alarm (300);
-
- mypid = getpid ();
-
- count = count; /* gdb break here 0 */
-
- if (argc < 2)
- {
- usage (argv[0]);
- exit (1);
- }
-
- if (libname == NULL)
- /* Only set if not already set from GDB. */
- libname = argv[1];
-
- if (argc > 2 && count == 0)
- /* Only set if not already set from GDB. */
- count = atoi (argv[2]);
-
- printf ("%s:%d: libname = %s, count = %d\n", __FILE__, __LINE__,
- libname, count);
-
- if ((fd = open (libname, O_RDONLY)) == -1)
- {
- fprintf (stderr, "open (\"%s\", O_RDONLY): %s\n", libname,
- strerror (errno));
- exit (1);
- }
-
- if (fstat (fd, &st) != 0)
- {
- fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno));
- exit (1);
- }
-
- for (i = 0; i < count; ++i)
- {
- const void *const addr = mmap (0, st.st_size, PROT_READ|PROT_WRITE,
- MAP_PRIVATE, fd, 0);
- struct jit_code_entry *const entry = calloc (1, sizeof (*entry));
-
- if (addr == MAP_FAILED)
- {
- fprintf (stderr, "mmap: %s\n", strerror (errno));
- exit (1);
- }
-
- update_locations (addr, i);
-
- /* Link entry at the end of the list. */
- entry->symfile_addr = (const char *)addr;
- entry->symfile_size = st.st_size;
- entry->prev_entry = __jit_debug_descriptor.relevant_entry;
- __jit_debug_descriptor.relevant_entry = entry;
-
- if (entry->prev_entry != NULL)
- entry->prev_entry->next_entry = entry;
- else
- __jit_debug_descriptor.first_entry = entry;
-
- /* Notify GDB. */
- __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
- __jit_debug_register_code ();
- }
-
- WAIT_FOR_GDB; i = 0; /* gdb break here 1 */
-
- /* Now unregister them all in reverse order. */
- while (__jit_debug_descriptor.relevant_entry != NULL)
- {
- struct jit_code_entry *const entry =
- __jit_debug_descriptor.relevant_entry;
- struct jit_code_entry *const prev_entry = entry->prev_entry;
-
- if (prev_entry != NULL)
- {
- prev_entry->next_entry = NULL;
- entry->prev_entry = NULL;
- }
- else
- __jit_debug_descriptor.first_entry = NULL;
-
- /* Notify GDB. */
- __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
- __jit_debug_register_code ();
-
- __jit_debug_descriptor.relevant_entry = prev_entry;
- free (entry);
- }
-
- WAIT_FOR_GDB; return 0; /* gdb break here 2 */
-}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2018-2020 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Simple standalone program using the JIT API. */
+
+#include "jit-reader-simple-jit.c"
+#include <unistd.h>
+
+int
+main (int argc, char **argv)
+{
+ execl (PROGRAM, PROGRAM, (char *) 0);
+ return 99;
+}
--- /dev/null
+# Copyright 2018-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Regression test for a jit.c bug. Previously it would crash if an
+# inferior that used the JIT API then exec'd a program that did not
+# use it.
+
+if { ![istarget "*-linux*"] } then {
+ return
+}
+
+standard_testfile jit-reader-exec.c
+
+set testfile2 "jit-reader-execd"
+set srcfile2 ${testfile2}.c
+set binfile2 [standard_output_file ${testfile2}]
+
+set compile_options [list debug additional_flags=-DPROGRAM=\"$binfile2\"]
+
+if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+ executable $compile_options] != ""} {
+ untested "failed to compile"
+ return -1
+}
+
+if {[gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" \
+ executable $compile_options] != ""} {
+ untested "failed to compile"
+ return -1
+}
+
+clean_restart $binfile
+
+if {![runto_main]} {
+ fail "can't run to main"
+ return
+}
+
+delete_breakpoints
+gdb_test "continue" "Inferior .* exited normally.*"
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2018-2020 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int
+main (int argc, char **argv)
+{
+ return 0;
+}
--- /dev/null
+/* Copyright (C) 2009-2020 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#include JIT_READER_H /* Please see jit-reader.exp for an explanation. */
+#include "jit-reader-host.h"
+#include "jit-protocol.h"
+
+void __attribute__((noinline)) __jit_debug_register_code () { }
+
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+struct jit_code_entry only_entry;
+
+typedef void (jit_function_stack_mangle_t) (void);
+typedef long (jit_function_add_t) (long a, long b);
+
+/* The code of the jit_function_00 function that is copied into an
+ mmapped buffer in the inferior at run time.
+
+ The second instruction mangles the stack pointer, meaning that when
+ stopped at the third instruction, GDB needs assistance from the JIT
+ unwinder in order to be able to unwind successfully. */
+static const unsigned char jit_function_stack_mangle_code[] = {
+ 0xcc, /* int3 */
+ 0x48, 0x83, 0xf4, 0xff, /* xor $0xffffffffffffffff, %rsp */
+ 0x48, 0x83, 0xf4, 0xff, /* xor $0xffffffffffffffff, %rsp */
+ 0xc3 /* ret */
+};
+
+/* And another "JIT-ed" function, with the prototype `jit_function_add_t`. */
+static const unsigned char jit_function_add_code[] = {
+ 0x48, 0x01, 0xfe, /* add %rdi,%rsi */
+ 0x48, 0x89, 0xf0, /* mov %rsi,%rax */
+ 0xc3, /* retq */
+};
+
+int
+main (int argc, char **argv)
+{
+ struct jithost_abi *symfile = malloc (sizeof (struct jithost_abi));
+ char *code = mmap (NULL, getpagesize (), PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ char *code_end = code;
+
+ /* "JIT" function_stack_mangle. */
+ memcpy (code_end, jit_function_stack_mangle_code,
+ sizeof (jit_function_stack_mangle_code));
+ jit_function_stack_mangle_t *function_stack_mangle
+ = (jit_function_stack_mangle_t *) code_end;
+ symfile->function_stack_mangle.begin = code_end;
+ code_end += sizeof (jit_function_stack_mangle_code);
+ symfile->function_stack_mangle.end = code_end;
+
+ /* "JIT" function_add. */
+ memcpy (code_end, jit_function_add_code, sizeof (jit_function_add_code));
+ jit_function_add_t *function_add = (jit_function_add_t *) code_end;
+ symfile->function_add.begin = code_end;
+ code_end += sizeof (jit_function_add_code);
+ symfile->function_add.end = code_end;
+
+ /* Bounds of the whole object. */
+ symfile->object.begin = code;
+ symfile->object.end = code_end;
+
+ only_entry.symfile_addr = symfile;
+ only_entry.symfile_size = sizeof (struct jithost_abi);
+
+ __jit_debug_descriptor.first_entry = &only_entry;
+ __jit_debug_descriptor.relevant_entry = &only_entry;
+ __jit_debug_descriptor.action_flag = JIT_REGISTER;
+ __jit_debug_descriptor.version = 1;
+ __jit_debug_register_code ();
+
+ function_stack_mangle ();
+ function_add (5, 6);
+
+ return 0;
+}
--- /dev/null
+/* Copyright (C) 2009-2020 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef JITHOST_H
+#define JITHOST_H
+
+struct jithost_abi_bounds
+{
+ const char *begin, *end;
+};
+
+struct jithost_abi
+{
+ /* Beginning and past-the-end for the whole object. */
+ struct jithost_abi_bounds object;
+
+ /* Beginning and past-the-end for function_stack_mangle. */
+ struct jithost_abi_bounds function_stack_mangle;
+
+ /* Beginning and past-the-end for function_add. */
+ struct jithost_abi_bounds function_add;
+};
+
+#endif /* JITHOST_H */
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2016-2020 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* A stub program that links with a simple library that uses the JIT
+ API. */
+
+int
+main (void)
+{
+ return 0;
+}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012-2020 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Simple library using the JIT API. */
+
+#include <stdint.h>
+
+struct jit_code_entry
+{
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ uint64_t symfile_size;
+};
+
+struct jit_descriptor
+{
+ uint32_t version;
+ /* This type should be jit_actions_t, but we use uint32_t
+ to be explicit about the bitwidth. */
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+
+#ifdef SPACER
+/* This exists to change the address of __jit_debug_descriptor. */
+int spacer = 4;
+#endif
+
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+void
+__jit_debug_register_code (void)
+{
+}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2016-2020 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Simple standalone program using the JIT API. */
+
+#include "jit-reader-simple-jit.c"
+
+int
+main (void)
+{
+ return 0;
+}
--- /dev/null
+# Copyright 2012-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test re-running an inferior with a JIT descriptor, where the JIT
+# descriptor changes address between runs.
+# http://sourceware.org/bugzilla/show_bug.cgi?id=13431
+
+# Test both the case of the JIT reader being included in the main
+# program directly, and the case of the JIT reader being split out to
+# a shared library.
+
+# For completeness, also test when the JIT descriptor does not change
+# address between runs.
+
+if {[skip_shlib_tests]} {
+ untested "skipping shared library tests"
+ return -1
+}
+
+standard_testfile
+
+set libname $testfile-jit
+set srcfile_lib $srcdir/$subdir/$libname.c
+set binfile_lib [standard_output_file $libname.so]
+
+# Build a standalone JIT binary.
+
+proc build_standalone_jit {{options ""}} {
+ global testfile srcfile binfile
+
+ lappend options "debug"
+
+ if {[build_executable $testfile.exp $testfile $srcfile $options] == -1} {
+ return -1
+ }
+
+ return 0
+}
+
+# Build the shared library JIT.
+
+proc build_shared_jit {{options ""}} {
+ global testfile
+ global srcfile_lib binfile_lib
+
+ lappend options "debug additional_flags=-fPIC"
+ if { [gdb_compile_shlib $srcfile_lib $binfile_lib $options] != "" } {
+ return -1
+ }
+
+ return 0
+}
+
+if {[build_standalone_jit] == -1} {
+ untested "failed to compile standalone testcase"
+ return
+}
+
+if {[build_shared_jit] == -1} {
+ untested "failed to compile shared library testcase"
+ return
+}
+
+# Built the program that loads the JIT library.
+set srcfile_dl $testfile-dl.c
+set binfile_dl $binfile-dl
+set options [list debug shlib=${binfile_lib}]
+if {[gdb_compile ${srcdir}/${subdir}/${srcfile_dl} $binfile_dl executable \
+ [list debug shlib=$binfile_lib]] == -1 } {
+ untested "failed to compile"
+ return -1
+}
+
+# STANDALONE is true when the JIT reader is included directly in the
+# main program. False when the JIT reader is in a separate shared
+# library. If CHANGE_ADDR is true, force changing the JIT descriptor
+# changes address between runs.
+proc jit_test_reread {standalone change_addr} {
+ global testfile binfile subdir srcfile srcdir binfile_lib binfile_dl
+ global hex
+
+ with_test_prefix "initial run" {
+ if {$standalone} {
+ clean_restart $binfile
+ } else {
+ clean_restart $binfile_dl
+ }
+
+ runto_main
+
+ set addr_before [get_hexadecimal_valueof "&__jit_debug_descriptor" 0 \
+ "get address of __jit_debug_descriptor"]
+
+ gdb_test "maint info breakpoints" \
+ "jit events keep y $hex <__jit_debug_register_code>.*" \
+ "maint info breakpoints shows jit breakpoint"
+ }
+
+ with_test_prefix "second run" {
+ # Ensure that the new executable is at least one second newer
+ # than the old. If the recompilation happens in the same
+ # second, gdb might not reload the executable automatically.
+ sleep 1
+
+ if ${change_addr} {
+ set options "additional_flags=-DSPACER"
+ if {$standalone} {
+ gdb_rename_execfile $binfile ${binfile}x
+ set res [build_standalone_jit $options]
+ } else {
+ gdb_rename_execfile $binfile_lib ${binfile_lib}x
+ set res [build_shared_jit $options]
+ }
+ if { $res == -1 } {
+ fail "recompile"
+ return
+ } else {
+ pass "recompile"
+ }
+ }
+
+ runto_main
+
+ set addr_after [get_hexadecimal_valueof "&__jit_debug_descriptor" 0 \
+ "get address of __jit_debug_descriptor"]
+
+ # This used to crash in the JIT-in-shared-library case:
+ # https://sourceware.org/bugzilla/show_bug.cgi?id=11094
+ gdb_test "maint info breakpoints" \
+ "jit events keep y $hex <__jit_debug_register_code>.*" \
+ "maint info breakpoints shows jit breakpoint"
+ }
+
+ if ${change_addr} {
+ gdb_assert {$addr_before != $addr_after} "address changed"
+ } else {
+ gdb_assert {$addr_before == $addr_after} "address didn't change"
+ }
+}
+
+foreach standalone {1 0} {
+ with_test_prefix [expr ($standalone)?"standalone":"shared"] {
+ with_test_prefix "change addr" {
+ jit_test_reread $standalone 1
+ }
+ with_test_prefix "same addr" {
+ jit_test_reread $standalone 0
+ }
+ }
+}
--- /dev/null
+/* Copyright (C) 2009-2020 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include JIT_READER_H /* Please see jit-reader.exp for an explanation. */
+#include "jit-reader-host.h"
+
+GDB_DECLARE_GPL_COMPATIBLE_READER;
+
+enum register_mapping
+{
+ AMD64_RA = 16,
+ AMD64_RBP = 6,
+ AMD64_RSP = 7,
+};
+
+struct reader_state
+{
+ struct {
+ uintptr_t begin;
+ uintptr_t end;
+ } func_stack_mangle;
+};
+
+static enum gdb_status
+read_debug_info (struct gdb_reader_funcs *self,
+ struct gdb_symbol_callbacks *cbs,
+ void *memory, long memory_sz)
+{
+ struct jithost_abi *symfile = memory;
+ struct gdb_object *object = cbs->object_open (cbs);
+ struct gdb_symtab *symtab = cbs->symtab_open (cbs, object, "");
+
+ struct reader_state *state = (struct reader_state *) self->priv_data;
+
+ /* Record the stack mangle function's range, for the unwinder. */
+ state->func_stack_mangle.begin
+ = (uintptr_t) symfile->function_stack_mangle.begin;
+ state->func_stack_mangle.end
+ = (uintptr_t) symfile->function_stack_mangle.end;
+
+ cbs->block_open (cbs, symtab, NULL,
+ (GDB_CORE_ADDR) symfile->function_stack_mangle.begin,
+ (GDB_CORE_ADDR) symfile->function_stack_mangle.end,
+ "jit_function_stack_mangle");
+
+ cbs->block_open (cbs, symtab, NULL,
+ (GDB_CORE_ADDR) symfile->function_add.begin,
+ (GDB_CORE_ADDR) symfile->function_add.end,
+ "jit_function_add");
+
+ cbs->symtab_close (cbs, symtab);
+ cbs->object_close (cbs, object);
+ return GDB_SUCCESS;
+}
+
+static void
+free_reg_value (struct gdb_reg_value *value)
+{
+ free (value);
+}
+
+static void
+write_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
+ uintptr_t value)
+{
+ const int size = sizeof (uintptr_t);
+ struct gdb_reg_value *reg_val =
+ malloc (sizeof (struct gdb_reg_value) + size - 1);
+ reg_val->defined = 1;
+ reg_val->free = free_reg_value;
+
+ memcpy (reg_val->value, &value, size);
+ callbacks->reg_set (callbacks, dw_reg, reg_val);
+}
+
+static int
+read_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
+ uintptr_t *value)
+{
+ const int size = sizeof (uintptr_t);
+ struct gdb_reg_value *reg_val = callbacks->reg_get (callbacks, dw_reg);
+ if (reg_val->size != size || !reg_val->defined)
+ {
+ reg_val->free (reg_val);
+ return 0;
+ }
+ memcpy (value, reg_val->value, size);
+ reg_val->free (reg_val);
+ return 1;
+}
+
+/* Read the stack pointer into *VALUE. IP is the address the inferior
+ is currently stopped at. Takes care of demangling the stack
+ pointer if necessary. */
+
+static int
+read_sp (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs,
+ uintptr_t ip, uintptr_t *value)
+{
+ struct reader_state *state = (struct reader_state *) self->priv_data;
+ uintptr_t sp;
+
+ if (!read_register (cbs, AMD64_RSP, &sp))
+ return GDB_FAIL;
+
+ /* If stopped at the instruction after the "xor $-1, %rsp", demangle
+ the stack pointer back. */
+ if (ip == state->func_stack_mangle.begin + 5)
+ sp ^= (uintptr_t) -1;
+
+ *value = sp;
+ return GDB_SUCCESS;
+}
+
+static enum gdb_status
+unwind_frame (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
+{
+ const int word_size = sizeof (uintptr_t);
+ uintptr_t prev_sp, this_sp;
+ uintptr_t prev_ip, this_ip;
+ uintptr_t prev_bp, this_bp;
+ struct reader_state *state = (struct reader_state *) self->priv_data;
+
+ if (!read_register (cbs, AMD64_RA, &this_ip))
+ return GDB_FAIL;
+
+ if (this_ip >= state->func_stack_mangle.end
+ || this_ip < state->func_stack_mangle.begin)
+ return GDB_FAIL;
+
+ /* Unwind RBP in order to make the unwinder that tries to unwind
+ from the just-unwound frame happy. */
+ if (!read_register (cbs, AMD64_RBP, &this_bp))
+ return GDB_FAIL;
+ /* RBP is unmodified. */
+ prev_bp = this_bp;
+
+ /* Fetch the demangled stack pointer. */
+ if (!read_sp (self, cbs, this_ip, &this_sp))
+ return GDB_FAIL;
+
+ /* The return address is saved on the stack. */
+ if (cbs->target_read (this_sp, &prev_ip, word_size) == GDB_FAIL)
+ return GDB_FAIL;
+ prev_sp = this_sp + word_size;
+
+ write_register (cbs, AMD64_RA, prev_ip);
+ write_register (cbs, AMD64_RSP, prev_sp);
+ write_register (cbs, AMD64_RBP, prev_bp);
+ return GDB_SUCCESS;
+}
+
+static struct gdb_frame_id
+get_frame_id (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
+{
+ struct reader_state *state = (struct reader_state *) self->priv_data;
+ struct gdb_frame_id frame_id;
+ uintptr_t ip;
+ uintptr_t sp;
+
+ read_register (cbs, AMD64_RA, &ip);
+ read_sp (self, cbs, ip, &sp);
+
+ frame_id.code_address = (GDB_CORE_ADDR) state->func_stack_mangle.begin;
+ frame_id.stack_address = (GDB_CORE_ADDR) sp;
+
+ return frame_id;
+}
+
+static void
+destroy_reader (struct gdb_reader_funcs *self)
+{
+ free (self->priv_data);
+ free (self);
+}
+
+struct gdb_reader_funcs *
+gdb_init_reader (void)
+{
+ struct reader_state *state = calloc (1, sizeof (struct reader_state));
+ struct gdb_reader_funcs *reader_funcs =
+ malloc (sizeof (struct gdb_reader_funcs));
+
+ reader_funcs->reader_version = GDB_READER_INTERFACE_VERSION;
+ reader_funcs->priv_data = state;
+ reader_funcs->read = read_debug_info;
+ reader_funcs->unwind = unwind_frame;
+ reader_funcs->get_frame_id = get_frame_id;
+ reader_funcs->destroy = destroy_reader;
+
+ return reader_funcs;
+}
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-standard_testfile jithost.c
+standard_testfile jit-reader-host.c
if { (![istarget x86_64-*-*] && ![istarget i?86-*-*]) || ![is_lp64_target] } {
return -1;
return -1
}
-set jit_reader jitreader
+set jit_reader jit-reader
set jit_reader_src ${jit_reader}.c
set jit_reader_bin [standard_output_file ${jit_reader}.so]
+++ /dev/null
-/* This testcase is part of GDB, the GNU debugger.
-
- Copyright 2016-2020 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* A stub program that links with a simple library that uses the JIT
- API. */
-
-int
-main (void)
-{
- return 0;
-}
+++ /dev/null
-/* This testcase is part of GDB, the GNU debugger.
-
- Copyright 2012-2020 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Simple library using the JIT API. */
-
-#include <stdint.h>
-
-struct jit_code_entry
-{
- struct jit_code_entry *next_entry;
- struct jit_code_entry *prev_entry;
- const char *symfile_addr;
- uint64_t symfile_size;
-};
-
-struct jit_descriptor
-{
- uint32_t version;
- /* This type should be jit_actions_t, but we use uint32_t
- to be explicit about the bitwidth. */
- uint32_t action_flag;
- struct jit_code_entry *relevant_entry;
- struct jit_code_entry *first_entry;
-};
-
-#ifdef SPACER
-/* This exists to change the address of __jit_debug_descriptor. */
-int spacer = 4;
-#endif
-
-struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
-
-void
-__jit_debug_register_code (void)
-{
-}
+++ /dev/null
-/* This testcase is part of GDB, the GNU debugger.
-
- Copyright 2016-2020 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Simple standalone program using the JIT API. */
-
-#include "jit-simple-jit.c"
-
-int
-main (void)
-{
- return 0;
-}
+++ /dev/null
-# Copyright 2012-2020 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# Test re-running an inferior with a JIT descriptor, where the JIT
-# descriptor changes address between runs.
-# http://sourceware.org/bugzilla/show_bug.cgi?id=13431
-
-# Test both the case of the JIT reader being included in the main
-# program directly, and the case of the JIT reader being split out to
-# a shared library.
-
-# For completeness, also test when the JIT descriptor does not change
-# address between runs.
-
-if {[skip_shlib_tests]} {
- untested "skipping shared library tests"
- return -1
-}
-
-standard_testfile
-
-set libname $testfile-jit
-set srcfile_lib $srcdir/$subdir/$libname.c
-set binfile_lib [standard_output_file $libname.so]
-
-# Build a standalone JIT binary.
-
-proc build_standalone_jit {{options ""}} {
- global testfile srcfile binfile
-
- lappend options "debug"
-
- if {[build_executable $testfile.exp $testfile $srcfile $options] == -1} {
- return -1
- }
-
- return 0
-}
-
-# Build the shared library JIT.
-
-proc build_shared_jit {{options ""}} {
- global testfile
- global srcfile_lib binfile_lib
-
- lappend options "debug additional_flags=-fPIC"
- if { [gdb_compile_shlib $srcfile_lib $binfile_lib $options] != "" } {
- return -1
- }
-
- return 0
-}
-
-if {[build_standalone_jit] == -1} {
- untested "failed to compile standalone testcase"
- return
-}
-
-if {[build_shared_jit] == -1} {
- untested "failed to compile shared library testcase"
- return
-}
-
-# Built the program that loads the JIT library.
-set srcfile_dl $testfile-dl.c
-set binfile_dl $binfile-dl
-set options [list debug shlib=${binfile_lib}]
-if {[gdb_compile ${srcdir}/${subdir}/${srcfile_dl} $binfile_dl executable \
- [list debug shlib=$binfile_lib]] == -1 } {
- untested "failed to compile"
- return -1
-}
-
-# STANDALONE is true when the JIT reader is included directly in the
-# main program. False when the JIT reader is in a separate shared
-# library. If CHANGE_ADDR is true, force changing the JIT descriptor
-# changes address between runs.
-proc jit_test_reread {standalone change_addr} {
- global testfile binfile subdir srcfile srcdir binfile_lib binfile_dl
- global hex
-
- with_test_prefix "initial run" {
- if {$standalone} {
- clean_restart $binfile
- } else {
- clean_restart $binfile_dl
- }
-
- runto_main
-
- set addr_before [get_hexadecimal_valueof "&__jit_debug_descriptor" 0 \
- "get address of __jit_debug_descriptor"]
-
- gdb_test "maint info breakpoints" \
- "jit events keep y $hex <__jit_debug_register_code>.*" \
- "maint info breakpoints shows jit breakpoint"
- }
-
- with_test_prefix "second run" {
- # Ensure that the new executable is at least one second newer
- # than the old. If the recompilation happens in the same
- # second, gdb might not reload the executable automatically.
- sleep 1
-
- if ${change_addr} {
- set options "additional_flags=-DSPACER"
- if {$standalone} {
- gdb_rename_execfile $binfile ${binfile}x
- set res [build_standalone_jit $options]
- } else {
- gdb_rename_execfile $binfile_lib ${binfile_lib}x
- set res [build_shared_jit $options]
- }
- if { $res == -1 } {
- fail "recompile"
- return
- } else {
- pass "recompile"
- }
- }
-
- runto_main
-
- set addr_after [get_hexadecimal_valueof "&__jit_debug_descriptor" 0 \
- "get address of __jit_debug_descriptor"]
-
- # This used to crash in the JIT-in-shared-library case:
- # https://sourceware.org/bugzilla/show_bug.cgi?id=11094
- gdb_test "maint info breakpoints" \
- "jit events keep y $hex <__jit_debug_register_code>.*" \
- "maint info breakpoints shows jit breakpoint"
- }
-
- if ${change_addr} {
- gdb_assert {$addr_before != $addr_after} "address changed"
- } else {
- gdb_assert {$addr_before == $addr_after} "address didn't change"
- }
-}
-
-foreach standalone {1 0} {
- with_test_prefix [expr ($standalone)?"standalone":"shared"] {
- with_test_prefix "change addr" {
- jit_test_reread $standalone 1
- }
- with_test_prefix "same addr" {
- jit_test_reread $standalone 0
- }
- }
-}
+++ /dev/null
-# Copyright 2011-2020 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# The same tests as in jit.exp, but loading JITer itself from a shared
-# library.
-
-if {[skip_shlib_tests]} {
- untested "skipping shared library tests"
- return -1
-}
-
-if {[get_compiler_info]} {
- untested "could not get compiler info"
- return 1
-}
-
-#
-# test running programs
-#
-
-set testfile jit-dlmain
-set srcfile ${testfile}.c
-set binfile [standard_output_file ${testfile}]
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug shlib_load}] != "" } {
- untested "failed to compile"
- return -1
-}
-
-set testfile2 jit-main
-set srcfile2 ${testfile2}.c
-set binfile2 [standard_output_file ${testfile2}.so]
-set binfile2_dlopen [shlib_target_file ${testfile2}.so]
-if { [gdb_compile_shlib "${srcdir}/${subdir}/${srcfile2}" ${binfile2} {debug additional_flags="-DMAIN=jit_dl_main"}] != "" } {
- untested "failed to compile main shared library"
- return -1
-}
-
-set solib_testfile "jit-solib"
-set solib_srcfile "${srcdir}/${subdir}/${solib_testfile}.c"
-set solib_binfile [standard_output_file ${solib_testfile}.so]
-set solib_binfile_test_msg "SHLIBDIR/${solib_testfile}.so"
-
-# Note: compiling without debug info: the library goes through symbol
-# renaming by munging on its symbol table, and that wouldn't work for .debug
-# sections. Also, output for "info function" changes when debug info is resent.
-if { [gdb_compile_shlib ${solib_srcfile} ${solib_binfile} {}] != "" } {
- untested "failed to compile jit shared library"
- return -1
-}
-
-set solib_binfile_target [gdb_remote_download target ${solib_binfile}]
-
-proc one_jit_test {count match_str} {
- with_test_prefix "one_jit_test-$count" {
- global verbose testfile srcfile2 binfile2 binfile2_dlopen solib_binfile_target solib_binfile_test_msg
-
- clean_restart $testfile
- gdb_load_shlib $binfile2
-
- # This is just to help debugging when things fail
- if {$verbose > 0} {
- gdb_test "set debug jit 1"
- }
-
- if { ![runto_main] } {
- fail "can't run to main"
- return
- }
-
- gdb_breakpoint [gdb_get_line_number "break here before-dlopen" ]
- gdb_continue_to_breakpoint "break here before-dlopen"
- # Poke desired values directly into inferior instead of using "set args"
- # because "set args" does not work under gdbserver.
- gdb_test_no_output "set var jit_libname = \"$binfile2_dlopen\""
-
- gdb_breakpoint [gdb_get_line_number "break here after-dlopen" ]
- gdb_continue_to_breakpoint "break here after-dlopen"
-
- gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 0} $srcfile2]"
- gdb_continue_to_breakpoint "break here 0"
-
- gdb_test_no_output "set var argc = 2"
- gdb_test_no_output "set var libname = \"$solib_binfile_target\"" "set var libname = \"$solib_binfile_test_msg\""
- gdb_test_no_output "set var count = $count"
-
- gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 1} $srcfile2]"
- gdb_continue_to_breakpoint "break here 1"
-
- gdb_test "info function jit_function" "$match_str"
-
- # This is just to help debugging when things fail
- if {$verbose > 0} {
- gdb_test "maintenance print objfiles"
- gdb_test "maintenance info break"
- }
-
- gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 2} $srcfile2]"
- gdb_continue_to_breakpoint "break here 2"
- # All jit librares must have been unregistered
- gdb_test "info function jit_function" \
- "All functions matching regular expression \"jit_function\":"
- }
-}
-
-one_jit_test 1 "${hex} jit_function_0000"
-one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001"
-
-# We don't intend to load the .so as a JIT debuginfo reader, but we
-# need some handy file name for a completion test.
-gdb_test \
- "complete jit-reader-load [standard_output_file ${solib_testfile}.s]" \
- "jit-reader-load $solib_binfile" \
- "test jit-reader-load filename completion"
+++ /dev/null
-/* This test program is part of GDB, the GNU debugger.
-
- Copyright 2011-2020 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* This simulates a JIT library. The function is "renamed" after being
- loaded into memory. */
-
-int jit_function_XXXX() { return 42; }
+++ /dev/null
-# Copyright 2011-2020 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-if {[skip_shlib_tests]} {
- untested "skipping shared library tests"
- return -1
-}
-
-if {[get_compiler_info]} {
- untested "could not get compiler info"
- return 1
-}
-
-# Compile the testcase program and library. BINSUFFIX is the suffix
-# to append to the program and library filenames, to make them unique
-# between invocations. OPTIONS is passed to gdb_compile when
-# compiling the program.
-
-proc compile_jit_test {testname binsuffix options} {
- global testfile srcfile binfile srcdir subdir
- global solib_testfile solib_srcfile solib_binfile solib_binfile_test_msg
- global solib_binfile_target
-
- set testfile jit-main
- set srcfile ${testfile}.c
- set binfile [standard_output_file $testfile$binsuffix]
- if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
- executable [concat debug $options]] != "" } {
- untested $testname
- return -1
- }
-
- set solib_testfile "jit-solib"
- set solib_srcfile "${srcdir}/${subdir}/${solib_testfile}.c"
- set solib_binfile [standard_output_file ${solib_testfile}$binsuffix.so]
- set solib_binfile_test_msg "SHLIBDIR/${solib_testfile}$binsuffix.so"
-
- # Note: compiling without debug info: the library goes through
- # symbol renaming by munging on its symbol table, and that
- # wouldn't work for .debug sections. Also, output for "info
- # function" changes when debug info is present.
- if { [gdb_compile_shlib ${solib_srcfile} ${solib_binfile} {-fPIC}] != "" } {
- untested $testname
- return -1
- }
-
- set solib_binfile_target [gdb_remote_download target ${solib_binfile}]
-
- return 0
-}
-
-# Detach, restart GDB, and re-attach to the program.
-
-proc clean_reattach {} {
- global decimal gdb_prompt srcfile testfile
-
- # Get PID of test program.
- set testpid -1
- set test "get inferior process ID"
- gdb_test_multiple "p mypid" $test {
- -re ".* = ($decimal).*$gdb_prompt $" {
- set testpid $expect_out(1,string)
- pass $test
- }
- }
-
- gdb_test_no_output "set var wait_for_gdb = 1"
- gdb_test "detach" "Detaching from .*"
-
- clean_restart $testfile
-
- set test "attach"
- gdb_test_multiple "attach $testpid" "$test" {
- -re "Attaching to program.*.*main.*at .*$srcfile:.*$gdb_prompt $" {
- pass "$test"
- }
- }
-
- gdb_test_no_output "set var wait_for_gdb = 0"
-}
-
-# Continue to LOCATION in the program. If REATTACH, detach and
-# re-attach to the program from scratch.
-proc continue_to_test_location {location reattach} {
- gdb_breakpoint [gdb_get_line_number $location]
- gdb_continue_to_breakpoint $location
- if {$reattach} {
- with_test_prefix "$location" {
- clean_reattach
- }
- }
-}
-
-proc one_jit_test {count match_str reattach} {
- with_test_prefix "one_jit_test-$count" {
- global verbose testfile solib_binfile_target solib_binfile_test_msg
-
- clean_restart $testfile
-
- # This is just to help debugging when things fail
- if {$verbose > 0} {
- gdb_test "set debug jit 1"
- }
-
- if { ![runto_main] } {
- fail "can't run to main"
- return
- }
-
- gdb_breakpoint [gdb_get_line_number "break here 0"]
- gdb_continue_to_breakpoint "break here 0"
-
- # Poke desired values directly into inferior instead of using "set args"
- # because "set args" does not work under gdbserver.
- gdb_test_no_output "set var argc = 2"
- gdb_test_no_output "set var libname = \"$solib_binfile_target\"" "set var libname = \"$solib_binfile_test_msg\""
- gdb_test_no_output "set var count = $count"
-
- continue_to_test_location "break here 1" $reattach
-
- gdb_test "info function ^jit_function" "$match_str"
-
- # This is just to help debugging when things fail
- if {$verbose > 0} {
- gdb_test "maintenance print objfiles"
- gdb_test "maintenance info break"
- }
-
- continue_to_test_location "break here 2" $reattach
-
- # All jit librares must have been unregistered
- gdb_test "info function jit_function" \
- "All functions matching regular expression \"jit_function\":"
- }
-}
-
-if {[compile_jit_test jit.exp "" {}] < 0} {
- return
-}
-one_jit_test 1 "${hex} jit_function_0000" 0
-one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001" 0
-
-# Test attaching to an inferior with some JIT libraries already
-# registered. We reuse the normal test, and detach/reattach at
-# specific interesting points.
-if {[can_spawn_for_attach]} {
- if {[compile_jit_test "jit.exp attach tests" \
- "-attach" {additional_flags=-DATTACH=1}] < 0} {
- return
- }
-
- with_test_prefix attach {
- one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001" 1
- }
-}
-
-with_test_prefix PIE {
- if {[compile_jit_test "jit.exp PIE tests" \
- "-pie" {additional_flags=-fPIE ldflags=-pie}] < 0} {
- return
- }
-
- one_jit_test 1 "${hex} jit_function_0000" 0
-}
+++ /dev/null
-/* Copyright (C) 2009-2020 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/mman.h>
-
-#include JIT_READER_H /* Please see jit-reader.exp for an explanation. */
-#include "jithost.h"
-#include "jit-protocol.h"
-
-void __attribute__((noinline)) __jit_debug_register_code () { }
-
-struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
-struct jit_code_entry only_entry;
-
-typedef void (jit_function_stack_mangle_t) (void);
-typedef long (jit_function_add_t) (long a, long b);
-
-/* The code of the jit_function_00 function that is copied into an
- mmapped buffer in the inferior at run time.
-
- The second instruction mangles the stack pointer, meaning that when
- stopped at the third instruction, GDB needs assistance from the JIT
- unwinder in order to be able to unwind successfully. */
-static const unsigned char jit_function_stack_mangle_code[] = {
- 0xcc, /* int3 */
- 0x48, 0x83, 0xf4, 0xff, /* xor $0xffffffffffffffff, %rsp */
- 0x48, 0x83, 0xf4, 0xff, /* xor $0xffffffffffffffff, %rsp */
- 0xc3 /* ret */
-};
-
-/* And another "JIT-ed" function, with the prototype `jit_function_add_t`. */
-static const unsigned char jit_function_add_code[] = {
- 0x48, 0x01, 0xfe, /* add %rdi,%rsi */
- 0x48, 0x89, 0xf0, /* mov %rsi,%rax */
- 0xc3, /* retq */
-};
-
-int
-main (int argc, char **argv)
-{
- struct jithost_abi *symfile = malloc (sizeof (struct jithost_abi));
- char *code = mmap (NULL, getpagesize (), PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- char *code_end = code;
-
- /* "JIT" function_stack_mangle. */
- memcpy (code_end, jit_function_stack_mangle_code,
- sizeof (jit_function_stack_mangle_code));
- jit_function_stack_mangle_t *function_stack_mangle
- = (jit_function_stack_mangle_t *) code_end;
- symfile->function_stack_mangle.begin = code_end;
- code_end += sizeof (jit_function_stack_mangle_code);
- symfile->function_stack_mangle.end = code_end;
-
- /* "JIT" function_add. */
- memcpy (code_end, jit_function_add_code, sizeof (jit_function_add_code));
- jit_function_add_t *function_add = (jit_function_add_t *) code_end;
- symfile->function_add.begin = code_end;
- code_end += sizeof (jit_function_add_code);
- symfile->function_add.end = code_end;
-
- /* Bounds of the whole object. */
- symfile->object.begin = code;
- symfile->object.end = code_end;
-
- only_entry.symfile_addr = symfile;
- only_entry.symfile_size = sizeof (struct jithost_abi);
-
- __jit_debug_descriptor.first_entry = &only_entry;
- __jit_debug_descriptor.relevant_entry = &only_entry;
- __jit_debug_descriptor.action_flag = JIT_REGISTER;
- __jit_debug_descriptor.version = 1;
- __jit_debug_register_code ();
-
- function_stack_mangle ();
- function_add (5, 6);
-
- return 0;
-}
+++ /dev/null
-/* Copyright (C) 2009-2020 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef JITHOST_H
-#define JITHOST_H
-
-struct jithost_abi_bounds
-{
- const char *begin, *end;
-};
-
-struct jithost_abi
-{
- /* Beginning and past-the-end for the whole object. */
- struct jithost_abi_bounds object;
-
- /* Beginning and past-the-end for function_stack_mangle. */
- struct jithost_abi_bounds function_stack_mangle;
-
- /* Beginning and past-the-end for function_add. */
- struct jithost_abi_bounds function_add;
-};
-
-#endif /* JITHOST_H */
+++ /dev/null
-/* Copyright (C) 2009-2020 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include JIT_READER_H /* Please see jit-reader.exp for an explanation. */
-#include "jithost.h"
-
-GDB_DECLARE_GPL_COMPATIBLE_READER;
-
-enum register_mapping
-{
- AMD64_RA = 16,
- AMD64_RBP = 6,
- AMD64_RSP = 7,
-};
-
-struct reader_state
-{
- struct {
- uintptr_t begin;
- uintptr_t end;
- } func_stack_mangle;
-};
-
-static enum gdb_status
-read_debug_info (struct gdb_reader_funcs *self,
- struct gdb_symbol_callbacks *cbs,
- void *memory, long memory_sz)
-{
- struct jithost_abi *symfile = memory;
- struct gdb_object *object = cbs->object_open (cbs);
- struct gdb_symtab *symtab = cbs->symtab_open (cbs, object, "");
-
- struct reader_state *state = (struct reader_state *) self->priv_data;
-
- /* Record the stack mangle function's range, for the unwinder. */
- state->func_stack_mangle.begin
- = (uintptr_t) symfile->function_stack_mangle.begin;
- state->func_stack_mangle.end
- = (uintptr_t) symfile->function_stack_mangle.end;
-
- cbs->block_open (cbs, symtab, NULL,
- (GDB_CORE_ADDR) symfile->function_stack_mangle.begin,
- (GDB_CORE_ADDR) symfile->function_stack_mangle.end,
- "jit_function_stack_mangle");
-
- cbs->block_open (cbs, symtab, NULL,
- (GDB_CORE_ADDR) symfile->function_add.begin,
- (GDB_CORE_ADDR) symfile->function_add.end,
- "jit_function_add");
-
- cbs->symtab_close (cbs, symtab);
- cbs->object_close (cbs, object);
- return GDB_SUCCESS;
-}
-
-static void
-free_reg_value (struct gdb_reg_value *value)
-{
- free (value);
-}
-
-static void
-write_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
- uintptr_t value)
-{
- const int size = sizeof (uintptr_t);
- struct gdb_reg_value *reg_val =
- malloc (sizeof (struct gdb_reg_value) + size - 1);
- reg_val->defined = 1;
- reg_val->free = free_reg_value;
-
- memcpy (reg_val->value, &value, size);
- callbacks->reg_set (callbacks, dw_reg, reg_val);
-}
-
-static int
-read_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
- uintptr_t *value)
-{
- const int size = sizeof (uintptr_t);
- struct gdb_reg_value *reg_val = callbacks->reg_get (callbacks, dw_reg);
- if (reg_val->size != size || !reg_val->defined)
- {
- reg_val->free (reg_val);
- return 0;
- }
- memcpy (value, reg_val->value, size);
- reg_val->free (reg_val);
- return 1;
-}
-
-/* Read the stack pointer into *VALUE. IP is the address the inferior
- is currently stopped at. Takes care of demangling the stack
- pointer if necessary. */
-
-static int
-read_sp (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs,
- uintptr_t ip, uintptr_t *value)
-{
- struct reader_state *state = (struct reader_state *) self->priv_data;
- uintptr_t sp;
-
- if (!read_register (cbs, AMD64_RSP, &sp))
- return GDB_FAIL;
-
- /* If stopped at the instruction after the "xor $-1, %rsp", demangle
- the stack pointer back. */
- if (ip == state->func_stack_mangle.begin + 5)
- sp ^= (uintptr_t) -1;
-
- *value = sp;
- return GDB_SUCCESS;
-}
-
-static enum gdb_status
-unwind_frame (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
-{
- const int word_size = sizeof (uintptr_t);
- uintptr_t prev_sp, this_sp;
- uintptr_t prev_ip, this_ip;
- uintptr_t prev_bp, this_bp;
- struct reader_state *state = (struct reader_state *) self->priv_data;
-
- if (!read_register (cbs, AMD64_RA, &this_ip))
- return GDB_FAIL;
-
- if (this_ip >= state->func_stack_mangle.end
- || this_ip < state->func_stack_mangle.begin)
- return GDB_FAIL;
-
- /* Unwind RBP in order to make the unwinder that tries to unwind
- from the just-unwound frame happy. */
- if (!read_register (cbs, AMD64_RBP, &this_bp))
- return GDB_FAIL;
- /* RBP is unmodified. */
- prev_bp = this_bp;
-
- /* Fetch the demangled stack pointer. */
- if (!read_sp (self, cbs, this_ip, &this_sp))
- return GDB_FAIL;
-
- /* The return address is saved on the stack. */
- if (cbs->target_read (this_sp, &prev_ip, word_size) == GDB_FAIL)
- return GDB_FAIL;
- prev_sp = this_sp + word_size;
-
- write_register (cbs, AMD64_RA, prev_ip);
- write_register (cbs, AMD64_RSP, prev_sp);
- write_register (cbs, AMD64_RBP, prev_bp);
- return GDB_SUCCESS;
-}
-
-static struct gdb_frame_id
-get_frame_id (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
-{
- struct reader_state *state = (struct reader_state *) self->priv_data;
- struct gdb_frame_id frame_id;
- uintptr_t ip;
- uintptr_t sp;
-
- read_register (cbs, AMD64_RA, &ip);
- read_sp (self, cbs, ip, &sp);
-
- frame_id.code_address = (GDB_CORE_ADDR) state->func_stack_mangle.begin;
- frame_id.stack_address = (GDB_CORE_ADDR) sp;
-
- return frame_id;
-}
-
-static void
-destroy_reader (struct gdb_reader_funcs *self)
-{
- free (self->priv_data);
- free (self);
-}
-
-struct gdb_reader_funcs *
-gdb_init_reader (void)
-{
- struct reader_state *state = calloc (1, sizeof (struct reader_state));
- struct gdb_reader_funcs *reader_funcs =
- malloc (sizeof (struct gdb_reader_funcs));
-
- reader_funcs->reader_version = GDB_READER_INTERFACE_VERSION;
- reader_funcs->priv_data = state;
- reader_funcs->read = read_debug_info;
- reader_funcs->unwind = unwind_frame;
- reader_funcs->get_frame_id = get_frame_id;
- reader_funcs->destroy = destroy_reader;
-
- return reader_funcs;
-}