2011-01-31 Paul Pluzhnikov <ppluzhnikov@google.com>

* gdb.base/jit.exp: New file.
	* gdb.base/jit-main.c: New file.
	* gdb.base/jit-solib.c: New file.
This commit is contained in:
Paul Pluzhnikov 2011-01-31 21:44:52 +00:00
parent c52b559d66
commit d3f0f85341
4 changed files with 333 additions and 0 deletions

View File

@ -1,3 +1,9 @@
2011-01-31 Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.base/jit.exp: New file.
* gdb.base/jit-main.c: New file.
* gdb.base/jit-solib.c: New file.
2011-01-31 Ulrich Weigand <uweigand@de.ibm.com>
* gdb.opencl/convs_casts.exp: Use tbreak instead of break to

View File

@ -0,0 +1,203 @@
/* This test program is part of GDB, the GNU debugger.
Copyright 2011 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Simulate loading of JIT code. */
#include <elf.h>
#include <link.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
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;
}
}
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;
count = count; /* gdb break here 0 */
if (argc < 2)
usage (argv[0]);
else
{
int i, fd;
struct stat st;
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 ();
}
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);
}
}
return 0; /* gdb break here 2 */
}

View File

@ -0,0 +1,22 @@
/* This test program is part of GDB, the GNU debugger.
Copyright 2011 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This simulates a JIT library. The function is "renamed" after being
loaded into memory. */
int jit_function_XXXX() { return 42; }

View File

@ -0,0 +1,102 @@
# Copyright 2011 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
if $tracelevel {
strace $tracelevel
}
if {[skip_shlib_tests]} {
untested jit.exp
return -1
}
if {[get_compiler_info not-used]} {
warning "Could not get compiler info"
untested jit.exp
return 1
}
#
# test running programs
#
set testfile jit-main
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
untested jit.exp
return -1
}
set solib_testfile "jit-solib"
set solib_srcfile "${srcdir}/${subdir}/${solib_testfile}.c"
set solib_binfile "${objdir}/${subdir}/${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} {-fPIC}] != "" } {
untested jit.exp
return -1
}
proc one_jit_test {count match_str} {
global verbose testfile solib_binfile pf_prefix
set old_pf_prefix $pf_prefix
set pf_prefix "one_jit_test-$count"
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 "set var argc = 2"
gdb_test "set var libname = \"$solib_binfile\""
gdb_test "set var count = $count"
gdb_breakpoint [gdb_get_line_number "break here 1"]
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 [gdb_get_line_number "break here 2"]
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\":" \
set pf_prefix $old_pf_prefix
}
one_jit_test 1 "${hex} jit_function_0000"
one_jit_test 2 "${hex} jit_function_0000\[\r\n\]+${hex} jit_function_0001"