From 9a94694506c636f573b9194d9820fd4842b8fe51 Mon Sep 17 00:00:00 2001 From: Mihails Strasuns via Gdb-patches Date: Tue, 31 Mar 2020 19:13:51 +0200 Subject: [PATCH] [gdb/testsuite] use args as lib list for jit-elf tests Old usage: jit-elf-main lib.so 2 New usage: jit-elf-main lib.so.1 lib.so.2 Refactoring necessary to support running tests over multiple jit binaries rather than mapping the same binary muultiple times. gdb/testsuite/ChangeLog: 2020-02-18 Mihails Strasuns * gdb.base/jit-elf-main.c: Read lib list from argc/argv. * gdb.base/jit-elf.exp: Compile N jit libraries and use the list. * gdb.base/jit-elf-so.exp: Ditto. --- gdb/testsuite/gdb.base/jit-elf-main.c | 56 ++++---- gdb/testsuite/gdb.base/jit-elf-so.exp | 183 +++++++++++++++++++------- gdb/testsuite/gdb.base/jit-elf.exp | 155 +++++++++++++--------- 3 files changed, 252 insertions(+), 142 deletions(-) diff --git a/gdb/testsuite/gdb.base/jit-elf-main.c b/gdb/testsuite/gdb.base/jit-elf-main.c index 4eaac514b53..acfd17d4179 100644 --- a/gdb/testsuite/gdb.base/jit-elf-main.c +++ b/gdb/testsuite/gdb.base/jit-elf-main.c @@ -45,9 +45,9 @@ #endif /* !ElfW */ static void -usage (const char *const argv0) +usage (void) { - fprintf (stderr, "Usage: %s library [count]\n", argv0); + fprintf (stderr, "Usage: jit-elf-main libraries...\n"); exit (1); } @@ -106,49 +106,39 @@ 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; - + int i; alarm (300); + /* Used as backing storage for GDB to populate argv. */ + char *fake_argv[10]; mypid = getpid (); - - count = count; /* gdb break here 0 */ + /* gdb break here 0 */ if (argc < 2) { - usage (argv[0]); + usage (); 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) + for (i = 1; i < argc; ++i) { - fprintf (stderr, "open (\"%s\", O_RDONLY): %s\n", libname, - strerror (errno)); - exit (1); - } + struct stat st; + int fd; - if (fstat (fd, &st) != 0) - { - fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno)); - exit (1); - } + printf ("%s:%d: libname = %s, i = %d\n", __FILE__, __LINE__, argv[i], i); + if ((fd = open (argv[i], O_RDONLY)) == -1) + { + fprintf (stderr, "open (\"%s\", O_RDONLY): %s\n", argv[i], + 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)); diff --git a/gdb/testsuite/gdb.base/jit-elf-so.exp b/gdb/testsuite/gdb.base/jit-elf-so.exp index 0f05221a62a..4f50c443f0f 100644 --- a/gdb/testsuite/gdb.base/jit-elf-so.exp +++ b/gdb/testsuite/gdb.base/jit-elf-so.exp @@ -26,48 +26,105 @@ if {[get_compiler_info]} { return 1 } +# The "real" main of this test, which loads jit-elf-main +# as a shared library. +set main_loader_basename jit-elf-dlmain +set main_loader_srcfile ${srcdir}/${subdir}/${main_loader_basename}.c +set main_loader_binfile [standard_output_file ${main_loader_basename}] + +# The main code that loads and registers JIT objects. +set main_solib_basename jit-elf-main +set main_solib_srcfile ${srcdir}/${subdir}/${main_solib_basename}.c +set main_solib_binfile [standard_output_file ${main_solib_basename}.so] + +# The shared library that gets loaded as JIT objects. +set jit_solib_basename jit-elf-solib +set jit_solib_srcfile ${srcdir}/${subdir}/${jit_solib_basename}.c + +# Compile jit-elf-main.c as a shared library. # -# test running programs +# OPTIONS is passed to gdb_compile when compiling the program. # +# On success, return 0. +# On failure, return -1. +proc compile_jit_elf_main_as_so {options} { + global main_solib_srcfile main_solib_binfile + set options [concat $options debug] + + if { [gdb_compile_shlib ${main_solib_srcfile} ${main_solib_binfile} \ + $options] != "" } { + untested "failed to compile ${main_solib_basename}.c as a shared library" + return -1 + } -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 + return 0 } -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 +# Compile the testcase shared library loader. +# +# OPTIONS is passed to gdb_compile when compiling the binary. +# +# On success, return 0. +# On failure, return -1. +proc compile_jit_dlmain {options} { + global main_loader_srcfile main_loader_binfile + set options [concat $options debug] + + if { [gdb_compile ${main_loader_srcfile} ${main_loader_binfile} \ + executable $options] != "" } { + untested "failed to compile ${main_loader_basename}.c as an executable" + return -1 + } + + return 0 } -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" +# Compile jit-elf-solib.c as a shared library in multiple copies and +# upload them to the target. +# +# On success, return a list of target path to the shared libraries. +# On failure, return -1. +proc compile_and_download_n_jit_so {count} { + global jit_solib_basename jit_solib_srcfile + set binfiles_target {} + + for {set i 1} {$i <= $count} {incr i} { + set binfile [standard_output_file ${jit_solib_basename}.$i.so] + + # Note: compiling without debug info by default: some test + # do symbol renaming by munging on ELF 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 ${jit_solib_srcfile} ${binfile} {}] != "" } { + untested "failed to compile ${jit_solib_basename}.c as a shared library" + return -1 + } -# 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 path [gdb_remote_download target ${binfile}] + lappend binfiles_target $path + } + + return $binfiles_target } -set solib_binfile_target [gdb_remote_download target ${solib_binfile}] +# Run $main_loader_binfile and load $main_solib_binfile in +# GDB. Check jit-related debug output and matches `info function` +# output for a jit loaded function using MATCH_STR. +# +# SOLIB_BINFILES_TARGETS is a list of shared libraries to pass +# as arguments when running $main_loader_binfile. +# MATCH_STR is a regular expression that output of `info function` +# must match. +proc one_jit_test {solib_binfiles_target match_str} { + set count [llength $solib_binfiles_target] -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 + global verbose + global main_loader_binfile main_loader_srcfile + global main_solib_binfile main_solib_srcfile - clean_restart $testfile - gdb_load_shlib $binfile2 + clean_restart $main_loader_binfile + gdb_load_shlib $main_solib_binfile # This is just to help debugging when things fail if {$verbose > 0} { @@ -79,23 +136,32 @@ proc one_jit_test {count match_str} { return } - gdb_breakpoint [gdb_get_line_number "break here before-dlopen" ] + gdb_breakpoint [gdb_get_line_number "break here before-dlopen" \ + $main_loader_srcfile] 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_test_no_output "set var jit_libname = \"$main_solib_binfile\"" \ + "setting library name" - gdb_breakpoint [gdb_get_line_number "break here after-dlopen" ] + gdb_breakpoint [gdb_get_line_number "break here after-dlopen" \ + $main_loader_srcfile] gdb_continue_to_breakpoint "break here after-dlopen" - gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 0} $srcfile2]" + set line [gdb_get_line_number {break here 0} $main_solib_srcfile] + gdb_breakpoint "$main_solib_srcfile:$line" 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" + # 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=[expr $count + 1]" "forging argc" + gdb_test_no_output "set var argv=fake_argv" "forging argv" + for {set i 1} {$i <= $count} {incr i} { + set binfile_target [lindex $solib_binfiles_target [expr $i-1]] + gdb_test_no_output "set var argv\[$i\]=\"${binfile_target}\"" \ + "forging argv\[$i\]" + } - gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 1} $srcfile2]" + set line [gdb_get_line_number {break here 1} $main_solib_srcfile] + gdb_breakpoint "$main_solib_srcfile:$line" gdb_continue_to_breakpoint "break here 1" gdb_test "info function jit_function" "$match_str" @@ -106,8 +172,10 @@ proc one_jit_test {count match_str} { gdb_test "maintenance info break" } - gdb_breakpoint "$srcfile2:[gdb_get_line_number {break here 2} $srcfile2]" + set line [gdb_get_line_number {break here 2} $main_solib_srcfile] + gdb_breakpoint "$main_solib_srcfile:$line" 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\":" \ @@ -115,12 +183,31 @@ proc one_jit_test {count match_str} { } } -one_jit_test 1 "${hex} jit_function_0000" -one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001" +# Compile the main code (which loads the JIT objects) as a shared library. +if { [compile_jit_elf_main_as_so {additional_flags="-DMAIN=jit_dl_main"}] < 0 } { + return +} + +# Compile the "real" main for this test. +if { [compile_jit_dlmain {shlib_load}] < 0 } { + return +} -# 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" +# Compile two shared libraries to use as JIT objects. +set jit_solibs_target [compile_and_download_n_jit_so 2] +if { $jit_solibs_target == -1 } { + return +} + +one_jit_test [lindex $jit_solibs_target 0] "${hex} jit_function_0001" +one_jit_test $jit_solibs_target "${hex} jit_function_0001\[\r\n\]+${hex} jit_function_0002" + +foreach solib $jit_solibs_target { + # We don't intend to load the .so as a JIT debuginfo reader, but we + # need some handy file name for a completion test. + set input [string range $solib 0 [expr { [string length $solib] - 2 }]] + gdb_test \ + "complete jit-reader-load [standard_output_file $input]" \ + "jit-reader-load $solib" \ + "test jit-reader-load filename completion [file tail $solib]" +} diff --git a/gdb/testsuite/gdb.base/jit-elf.exp b/gdb/testsuite/gdb.base/jit-elf.exp index 71d3e37dfb8..98da57bd50f 100644 --- a/gdb/testsuite/gdb.base/jit-elf.exp +++ b/gdb/testsuite/gdb.base/jit-elf.exp @@ -23,48 +23,70 @@ if {[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 - } +# The main code that loads and registers JIT objects. +set main_basename jit-elf-main +set main_srcfile ${srcdir}/${subdir}/${main_basename}.c +set main_binfile [standard_output_file ${main_basename}] - 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 - } +# The shared library that gets loaded as JIT objects. +set jit_solib_basename jit-elf-solib +set jit_solib_srcfile ${srcdir}/${subdir}/${jit_solib_basename}.c - set solib_binfile_target [gdb_remote_download target ${solib_binfile}] +# Compile jit-elf-main.c as an executable. +# +# BINSUFFIX is appended to the binary name. +# OPTIONS is passed to gdb_compile when compiling the program. +# +# On success, return 0. +# On failure, return -1. +proc compile_jit_main {binsuffix options} { + global main_binfile main_srcfile main_basename + + set binfile ${main_binfile}${binsuffix} + set options [concat $options debug] + + if { [gdb_compile ${main_srcfile} ${binfile} \ + executable $options] != "" } { + untested "failed to compile ${main_basename}.c" + return -1 + } return 0 } +# Compile jit-elf-solib.c as a shared library in multiple copies and +# upload them to the target. +# +# On success, return a list of target paths to the shared libraries. +# On failure, return -1. +proc compile_and_download_n_jit_so {count} { + global jit_solib_basename jit_solib_srcfile + set binfiles_target {} + + for {set i 1} {$i <= $count} {incr i} { + set binfile [standard_output_file ${jit_solib_basename}.$i.so] + + # Note: compiling without debug info by default: some test + # do symbol renaming by munging on ELF 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 ${jit_solib_srcfile} ${binfile} {}] != "" } { + untested "failed to compile ${jit_solib_basename}.c as a shared library" + return -1 + } + + set path [gdb_remote_download target ${binfile}] + lappend binfiles_target $path + } + + return $binfiles_target +} + # Detach, restart GDB, and re-attach to the program. proc clean_reattach {} { - global decimal gdb_prompt srcfile testfile + global decimal gdb_prompt + global main_binfile main_srcfile # Get PID of test program. set testpid -1 @@ -79,11 +101,11 @@ proc clean_reattach {} { gdb_test_no_output "set var wait_for_gdb = 1" gdb_test "detach" "Detaching from .*" - clean_restart $testfile + clean_restart ${main_binfile} set test "attach" gdb_test_multiple "attach $testpid" "$test" { - -re "Attaching to program.*.*main.*at .*$srcfile:.*$gdb_prompt $" { + -re "Attaching to program.*.*main.*at .*$main_srcfile:.*$gdb_prompt $" { pass "$test" } } @@ -94,7 +116,9 @@ proc clean_reattach {} { # 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] + global main_srcfile + + gdb_breakpoint [gdb_get_line_number $location $main_srcfile] gdb_continue_to_breakpoint $location if {$reattach} { with_test_prefix "$location" { @@ -103,11 +127,14 @@ proc continue_to_test_location {location reattach} { } } -proc one_jit_test {count match_str reattach} { +proc one_jit_test {jit_solibs_target match_str reattach} { + set count [llength $jit_solibs_target] + with_test_prefix "one_jit_test-$count" { - global verbose testfile solib_binfile_target solib_binfile_test_msg + global verbose + global main_binfile main_srcfile - clean_restart $testfile + clean_restart ${main_binfile} # This is just to help debugging when things fail if {$verbose > 0} { @@ -119,14 +146,20 @@ proc one_jit_test {count match_str reattach} { 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" + incr count + gdb_test_no_output "set var argc=$count" "forging argc" + gdb_test_no_output "set var argv=fake_argv" "forging argv" + for {set i 1} {$i < $count} {incr i} { + set jit_solib_target [lindex $jit_solibs_target [expr $i-1]] + gdb_test_no_output "set var argv\[$i\]=\"${jit_solib_target}\"" \ + "forging argv\[$i\]" + } + + gdb_breakpoint [gdb_get_line_number "break here 0" $main_srcfile] + gdb_continue_to_breakpoint "break here 0" + continue_to_test_location "break here 1" $reattach @@ -146,31 +179,31 @@ proc one_jit_test {count match_str reattach} { } } -if {[compile_jit_test jit.exp "" {}] < 0} { +# Compile two shared libraries to use as JIT objects. +set jit_solibs_target [compile_and_download_n_jit_so 2] +if { $jit_solibs_target == -1 } { 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 + +# Compile the main code (which loads the JIT objects). +if { [compile_jit_main "" {}] == 0 } { + one_jit_test [lindex $jit_solibs_target 0] "${hex} jit_function_0001" 0 + one_jit_test $jit_solibs_target "${hex} jit_function_0001\[\r\n\]+${hex} jit_function_0002" 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 + if { [compile_jit_main "-attach" {additional_flags=-DATTACH=1}] == 0 } { + with_test_prefix attach { + one_jit_test $jit_solibs_target "${hex} jit_function_0001\[\r\n\]+${hex} jit_function_0002" 1 + } } } -with_test_prefix PIE { - if {[compile_jit_test "jit.exp PIE tests" \ - "-pie" {additional_flags=-fPIE ldflags=-pie}] < 0} { - return +if { [compile_jit_main "-pie" {additional_flags=-fPIE ldflags=-pie}] == 0 } { + with_test_prefix PIE { + one_jit_test [lindex $jit_solibs_target 0] "${hex} jit_function_0001" 0 } - - one_jit_test 1 "${hex} jit_function_0000" 0 } -- 2.30.2