This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Add tests for JIT debugging interface


Greetings,

Currently there are no tests which verify that JIT debugging actually works.

Here is a patch to perform some minimal checks (ELF only).

Thanks,

--
Paul Pluzhnikov

testsuite/ChangeLog:

2011-01-11  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.



Index: testsuite/gdb.base/jit-main.c
===================================================================
RCS file: testsuite/gdb.base/jit-main.c
diff -N testsuite/gdb.base/jit-main.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/jit-main.c	11 Jan 2011 23:17:54 -0000
@@ -0,0 +1,186 @@
+/* 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[])
+{
+  if (argc < 2)
+    usage(argv[0]);
+  else
+    {
+      const char *const libname = argv[1];
+      int i, fd, count = 1;
+      struct stat st;
+
+      if (argc > 2)
+        count = atoi (argv[2]);
+
+      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  */
+}
Index: testsuite/gdb.base/jit-solib.c
===================================================================
RCS file: testsuite/gdb.base/jit-solib.c
diff -N testsuite/gdb.base/jit-solib.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/jit-solib.c	11 Jan 2011 23:17:54 -0000
@@ -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; }
Index: testsuite/gdb.base/jit.exp
===================================================================
RCS file: testsuite/gdb.base/jit.exp
diff -N testsuite/gdb.base/jit.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/jit.exp	11 Jan 2011 23:17:54 -0000
@@ -0,0 +1,83 @@
+# 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
+}
+
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load $binfile
+
+proc one_test {count match_str} {
+    global solib_binfile gdb_prompt
+
+    gdb_test_no_output "set args $solib_binfile $count" "set args"
+    if ![runto_main] then {
+	fail "Can't run to main"
+	return 0
+    }
+
+    gdb_breakpoint [gdb_get_line_number "break here 1"]
+    gdb_continue_to_breakpoint "break here 1"
+    gdb_test "info function jit_function" "$match_str"
+    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\":"
+}
+
+one_test 1 "${hex}  jit_function_0000"
+one_test 2 "${hex}  jit_function_0000\[\r\n\]+${hex}  jit_function_0001"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]