From: Mihails Strasuns Date: Tue, 11 Feb 2020 12:23:25 +0000 (+0100) Subject: [gdb/testsuite] structured rename of jit test files X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=922a7c7c5d4040f9e4ab75a059b9ca33f45ab952;p=binutils-gdb.git [gdb/testsuite] structured rename of jit test files Reorganizes how JIT related test files to be more clear what are related to JIT reader system tests and what use JIT from ELF objfiles. Those two approaches are quite different in GDB implementation and require very different test setup. Keeping distinction clear at the file name level makes it easier to maintain the testsuite. gdb/testsuite/ChangeLog: 2020-02-18 Mihails Strasuns * gdb.base: Rename all jit related test and source files. --- diff --git a/gdb/testsuite/gdb.base/jit-dlmain.c b/gdb/testsuite/gdb.base/jit-dlmain.c deleted file mode 100644 index 03b8d3cc284..00000000000 --- a/gdb/testsuite/gdb.base/jit-dlmain.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -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); -} diff --git a/gdb/testsuite/gdb.base/jit-elf-dlmain.c b/gdb/testsuite/gdb.base/jit-elf-dlmain.c new file mode 100644 index 00000000000..03b8d3cc284 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-elf-dlmain.c @@ -0,0 +1,20 @@ +#include +#include + +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); +} diff --git a/gdb/testsuite/gdb.base/jit-elf-main.c b/gdb/testsuite/gdb.base/jit-elf-main.c new file mode 100644 index 00000000000..37c2a31b3f2 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-elf-main.c @@ -0,0 +1,236 @@ +/* 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 . */ + +/* Simulate loading of JIT code. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 */ +} diff --git a/gdb/testsuite/gdb.base/jit-elf-so.exp b/gdb/testsuite/gdb.base/jit-elf-so.exp new file mode 100644 index 00000000000..526414f43cf --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-elf-so.exp @@ -0,0 +1,125 @@ +# 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 . + +# 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" diff --git a/gdb/testsuite/gdb.base/jit-elf-solib.c b/gdb/testsuite/gdb.base/jit-elf-solib.c new file mode 100644 index 00000000000..3bdebe9ed0f --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-elf-solib.c @@ -0,0 +1,21 @@ +/* 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 . */ + +/* This simulates a JIT library. The function is "renamed" after being + loaded into memory. */ + +int jit_function_XXXX() { return 42; } diff --git a/gdb/testsuite/gdb.base/jit-elf.exp b/gdb/testsuite/gdb.base/jit-elf.exp new file mode 100644 index 00000000000..71d3e37dfb8 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-elf.exp @@ -0,0 +1,176 @@ +# 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 . + +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 +} diff --git a/gdb/testsuite/gdb.base/jit-exec.c b/gdb/testsuite/gdb.base/jit-exec.c deleted file mode 100644 index 809308fabec..00000000000 --- a/gdb/testsuite/gdb.base/jit-exec.c +++ /dev/null @@ -1,28 +0,0 @@ -/* 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 . */ - -/* Simple standalone program using the JIT API. */ - -#include "jit-simple-jit.c" -#include - -int -main (int argc, char **argv) -{ - execl (PROGRAM, PROGRAM, (char *) 0); - return 99; -} diff --git a/gdb/testsuite/gdb.base/jit-exec.exp b/gdb/testsuite/gdb.base/jit-exec.exp deleted file mode 100644 index 327646bb653..00000000000 --- a/gdb/testsuite/gdb.base/jit-exec.exp +++ /dev/null @@ -1,52 +0,0 @@ -# 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 . - -# 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.*" diff --git a/gdb/testsuite/gdb.base/jit-execd.c b/gdb/testsuite/gdb.base/jit-execd.c deleted file mode 100644 index a4b6f476efa..00000000000 --- a/gdb/testsuite/gdb.base/jit-execd.c +++ /dev/null @@ -1,22 +0,0 @@ -/* 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 . */ - -int -main (int argc, char **argv) -{ - return 0; -} diff --git a/gdb/testsuite/gdb.base/jit-main.c b/gdb/testsuite/gdb.base/jit-main.c deleted file mode 100644 index 37c2a31b3f2..00000000000 --- a/gdb/testsuite/gdb.base/jit-main.c +++ /dev/null @@ -1,236 +0,0 @@ -/* 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 . */ - -/* Simulate loading of JIT code. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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 */ -} diff --git a/gdb/testsuite/gdb.base/jit-reader-exec.c b/gdb/testsuite/gdb.base/jit-reader-exec.c new file mode 100644 index 00000000000..f92aa5d9daf --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-exec.c @@ -0,0 +1,28 @@ +/* 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 . */ + +/* Simple standalone program using the JIT API. */ + +#include "jit-reader-simple-jit.c" +#include + +int +main (int argc, char **argv) +{ + execl (PROGRAM, PROGRAM, (char *) 0); + return 99; +} diff --git a/gdb/testsuite/gdb.base/jit-reader-exec.exp b/gdb/testsuite/gdb.base/jit-reader-exec.exp new file mode 100644 index 00000000000..4235309f774 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-exec.exp @@ -0,0 +1,52 @@ +# 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 . + +# 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.*" diff --git a/gdb/testsuite/gdb.base/jit-reader-execd.c b/gdb/testsuite/gdb.base/jit-reader-execd.c new file mode 100644 index 00000000000..a4b6f476efa --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-execd.c @@ -0,0 +1,22 @@ +/* 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 . */ + +int +main (int argc, char **argv) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/jit-reader-host.c b/gdb/testsuite/gdb.base/jit-reader-host.c new file mode 100644 index 00000000000..d07acd54bb1 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-host.c @@ -0,0 +1,98 @@ +/* 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 . */ + +#include +#include +#include +#include + +#include + +#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; +} diff --git a/gdb/testsuite/gdb.base/jit-reader-host.h b/gdb/testsuite/gdb.base/jit-reader-host.h new file mode 100644 index 00000000000..28aec5d2644 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-host.h @@ -0,0 +1,38 @@ +/* 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 . */ + +#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 */ diff --git a/gdb/testsuite/gdb.base/jit-reader-simple-dl.c b/gdb/testsuite/gdb.base/jit-reader-simple-dl.c new file mode 100644 index 00000000000..aee6dbff05f --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-simple-dl.c @@ -0,0 +1,25 @@ +/* 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 . */ + +/* A stub program that links with a simple library that uses the JIT + API. */ + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/jit-reader-simple-jit.c b/gdb/testsuite/gdb.base/jit-reader-simple-jit.c new file mode 100644 index 00000000000..407666b98bf --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-simple-jit.c @@ -0,0 +1,50 @@ +/* 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 . */ + +/* Simple library using the JIT API. */ + +#include + +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) +{ +} diff --git a/gdb/testsuite/gdb.base/jit-reader-simple.c b/gdb/testsuite/gdb.base/jit-reader-simple.c new file mode 100644 index 00000000000..bcb83f09bf6 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-simple.c @@ -0,0 +1,26 @@ +/* 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 . */ + +/* Simple standalone program using the JIT API. */ + +#include "jit-reader-simple-jit.c" + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/jit-reader-simple.exp b/gdb/testsuite/gdb.base/jit-reader-simple.exp new file mode 100644 index 00000000000..c036e71c3fb --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader-simple.exp @@ -0,0 +1,162 @@ +# 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 . + +# 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 + } + } +} diff --git a/gdb/testsuite/gdb.base/jit-reader.c b/gdb/testsuite/gdb.base/jit-reader.c new file mode 100644 index 00000000000..c5fd7a99be7 --- /dev/null +++ b/gdb/testsuite/gdb.base/jit-reader.c @@ -0,0 +1,211 @@ +/* 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 . */ + +#include +#include +#include +#include + +#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; +} diff --git a/gdb/testsuite/gdb.base/jit-reader.exp b/gdb/testsuite/gdb.base/jit-reader.exp index 8663f0021de..c0af2fc6a1f 100644 --- a/gdb/testsuite/gdb.base/jit-reader.exp +++ b/gdb/testsuite/gdb.base/jit-reader.exp @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -standard_testfile jithost.c +standard_testfile jit-reader-host.c if { (![istarget x86_64-*-*] && ![istarget i?86-*-*]) || ![is_lp64_target] } { return -1; @@ -47,7 +47,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${jit_host_src}" "${jit_host_bin}" \ 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] diff --git a/gdb/testsuite/gdb.base/jit-simple-dl.c b/gdb/testsuite/gdb.base/jit-simple-dl.c deleted file mode 100644 index aee6dbff05f..00000000000 --- a/gdb/testsuite/gdb.base/jit-simple-dl.c +++ /dev/null @@ -1,25 +0,0 @@ -/* 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 . */ - -/* A stub program that links with a simple library that uses the JIT - API. */ - -int -main (void) -{ - return 0; -} diff --git a/gdb/testsuite/gdb.base/jit-simple-jit.c b/gdb/testsuite/gdb.base/jit-simple-jit.c deleted file mode 100644 index 407666b98bf..00000000000 --- a/gdb/testsuite/gdb.base/jit-simple-jit.c +++ /dev/null @@ -1,50 +0,0 @@ -/* 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 . */ - -/* Simple library using the JIT API. */ - -#include - -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) -{ -} diff --git a/gdb/testsuite/gdb.base/jit-simple.c b/gdb/testsuite/gdb.base/jit-simple.c deleted file mode 100644 index 8ea6aec1f1f..00000000000 --- a/gdb/testsuite/gdb.base/jit-simple.c +++ /dev/null @@ -1,26 +0,0 @@ -/* 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 . */ - -/* Simple standalone program using the JIT API. */ - -#include "jit-simple-jit.c" - -int -main (void) -{ - return 0; -} diff --git a/gdb/testsuite/gdb.base/jit-simple.exp b/gdb/testsuite/gdb.base/jit-simple.exp deleted file mode 100644 index c036e71c3fb..00000000000 --- a/gdb/testsuite/gdb.base/jit-simple.exp +++ /dev/null @@ -1,162 +0,0 @@ -# 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 . - -# 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 - } - } -} diff --git a/gdb/testsuite/gdb.base/jit-so.exp b/gdb/testsuite/gdb.base/jit-so.exp deleted file mode 100644 index 27dcdfa58e2..00000000000 --- a/gdb/testsuite/gdb.base/jit-so.exp +++ /dev/null @@ -1,125 +0,0 @@ -# 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 . - -# 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" diff --git a/gdb/testsuite/gdb.base/jit-solib.c b/gdb/testsuite/gdb.base/jit-solib.c deleted file mode 100644 index 3bdebe9ed0f..00000000000 --- a/gdb/testsuite/gdb.base/jit-solib.c +++ /dev/null @@ -1,21 +0,0 @@ -/* 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 . */ - -/* This simulates a JIT library. The function is "renamed" after being - loaded into memory. */ - -int jit_function_XXXX() { return 42; } diff --git a/gdb/testsuite/gdb.base/jit.exp b/gdb/testsuite/gdb.base/jit.exp deleted file mode 100644 index 094c37fa3d7..00000000000 --- a/gdb/testsuite/gdb.base/jit.exp +++ /dev/null @@ -1,176 +0,0 @@ -# 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 . - -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 -} diff --git a/gdb/testsuite/gdb.base/jithost.c b/gdb/testsuite/gdb.base/jithost.c deleted file mode 100644 index 19cc3e16c04..00000000000 --- a/gdb/testsuite/gdb.base/jithost.c +++ /dev/null @@ -1,98 +0,0 @@ -/* 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 . */ - -#include -#include -#include -#include - -#include - -#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; -} diff --git a/gdb/testsuite/gdb.base/jithost.h b/gdb/testsuite/gdb.base/jithost.h deleted file mode 100644 index 28aec5d2644..00000000000 --- a/gdb/testsuite/gdb.base/jithost.h +++ /dev/null @@ -1,38 +0,0 @@ -/* 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 . */ - -#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 */ diff --git a/gdb/testsuite/gdb.base/jitreader.c b/gdb/testsuite/gdb.base/jitreader.c deleted file mode 100644 index d0dc488fec4..00000000000 --- a/gdb/testsuite/gdb.base/jitreader.c +++ /dev/null @@ -1,211 +0,0 @@ -/* 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 . */ - -#include -#include -#include -#include - -#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; -}