[v4,5/5,gdb/testsuite] add jit-elf-util.h and run jit function

Message ID 20200421133123.21284-6-mihails.strasuns@intel.com
State Superseded
Headers show
Series
  • jit testsuite refactoring
Related show

Commit Message

Simon Marchi via Gdb-patches April 21, 2020, 1:31 p.m.
Splits ELF related symbols into a separate jit-elf-util.h header and
enhances it with a few more.

Intention is to make adding new JIT tests possible without repeating
most of the common boilerplate.

As a test enhancement, jit-elf-main.c now calls the renamed function
after registering the jit object and ensures it returns an expected
result.

gdb/testsuite/ChangeLog:

2020-02-18  Mihails Strasuns  <mihails.strasuns@intel.com>

	* gdb.base/jit-elf-util.h: New header file.
	* gdb.base/jit-elf-main.c: Use jit-elf-util.h, add a call to
	  the renamed JIT function to verify its result.
---
 gdb/testsuite/gdb.base/jit-elf-main.c |  56 ++++--------
 gdb/testsuite/gdb.base/jit-elf-util.h | 117 ++++++++++++++++++++++++++
 2 files changed, 133 insertions(+), 40 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/jit-elf-util.h

-- 
2.26.1

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

Comments

Simon Marchi April 22, 2020, 2:25 a.m. | #1
On 2020-04-21 9:31 a.m., Mihails Strasuns via Gdb-patches wrote:
> Splits ELF related symbols into a separate jit-elf-util.h header and

> enhances it with a few more.

> 

> Intention is to make adding new JIT tests possible without repeating

> most of the common boilerplate.

> 

> As a test enhancement, jit-elf-main.c now calls the renamed function

> after registering the jit object and ensures it returns an expected

> result.

> 

> gdb/testsuite/ChangeLog:

> 

> 2020-02-18  Mihails Strasuns  <mihails.strasuns@intel.com>

> 

> 	* gdb.base/jit-elf-util.h: New header file.

> 	* gdb.base/jit-elf-main.c: Use jit-elf-util.h, add a call to

> 	  the renamed JIT function to verify its result.

> ---

>  gdb/testsuite/gdb.base/jit-elf-main.c |  56 ++++--------

>  gdb/testsuite/gdb.base/jit-elf-util.h | 117 ++++++++++++++++++++++++++

>  2 files changed, 133 insertions(+), 40 deletions(-)

>  create mode 100644 gdb/testsuite/gdb.base/jit-elf-util.h

> 

> diff --git a/gdb/testsuite/gdb.base/jit-elf-main.c b/gdb/testsuite/gdb.base/jit-elf-main.c

> index b74212dbf5..b812cb91e5 100644

> --- a/gdb/testsuite/gdb.base/jit-elf-main.c

> +++ b/gdb/testsuite/gdb.base/jit-elf-main.c

> @@ -30,19 +30,7 @@

>  #include <unistd.h>

>  

>  #include "jit-protocol.h"

> -

> -/* ElfW is coming from linux. On other platforms it does not exist.

> -   Let us define it here. */

> -#ifndef ElfW

> -# if (defined  (_LP64) || defined (__LP64__)) 

> -#   define WORDSIZE 64

> -# else

> -#   define WORDSIZE 32

> -# endif /* _LP64 || __LP64__  */

> -#define ElfW(type)      _ElfW (Elf, WORDSIZE, type)

> -#define _ElfW(e,w,t)    _ElfW_1 (e, w, _##t)

> -#define _ElfW_1(e,w,t)  e##w##t

> -#endif /* !ElfW  */

> +#include "jit-elf-util.h"

>  

>  static void

>  usage (void)

> @@ -95,37 +83,19 @@ MAIN (int argc, char *argv[])

>  

>    for (i = 1; i < argc; ++i)

>      {

> -      struct stat st;

> -      int fd;

> -

> -      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);

> -	}

> +      size_t obj_size;

> +      ElfW (Addr) load_addr = LOAD_ADDRESS + (i-1) * LOAD_INCREMENT;


(i - 1)

I think load_addr should just be a `void *`, and the `(void *)` casts should be removed.

> +      printf("Loading %s as JIT at %p\n", argv[i], (void*) load_addr);


(void *)

> +      ElfW (Addr) addr = load_elf (argv[i], &obj_size, load_addr);

>  

> -      if (fstat (fd, &st) != 0)

> -	{

> -	  fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno));

> -	  exit (1);

> -	}

> -

> -      void* load_addr = (void*) (size_t) (LOAD_ADDRESS + (i - 1) * LOAD_INCREMENT);




> -      const void *const addr = mmap (load_addr, st.st_size, PROT_READ|PROT_WRITE,

> -				     MAP_PRIVATE | MAP_FIXED, 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);

> -	}

> +      char name[32];

> +      sprintf (name, "jit_function_%04d", i);

> +      int (*jit_function) () = (int (*) ()) load_symbol (addr, name);


Use (void) instead of ().

>  

>        /* Link entry at the end of the list.  */

> +      struct jit_code_entry *const entry = calloc (1, sizeof (*entry));

>        entry->symfile_addr = (const char *)addr;

> -      entry->symfile_size = st.st_size;

> +      entry->symfile_size = obj_size;

>        entry->prev_entry = __jit_debug_descriptor.relevant_entry;

>        __jit_debug_descriptor.relevant_entry = entry;

>  

> @@ -137,6 +107,12 @@ MAIN (int argc, char *argv[])

>        /* Notify GDB.  */

>        __jit_debug_descriptor.action_flag = JIT_REGISTER;

>        __jit_debug_register_code ();

> +

> +      if (jit_function () != 42)

> +	{

> +	  fprintf (stderr, "unexpected return value\n");

> +	  exit (1);

> +	}

>      }

>  

>    WAIT_FOR_GDB; i = 0;  /* gdb break here 1 */

> diff --git a/gdb/testsuite/gdb.base/jit-elf-util.h b/gdb/testsuite/gdb.base/jit-elf-util.h

> new file mode 100644

> index 0000000000..e48d99f098

> --- /dev/null

> +++ b/gdb/testsuite/gdb.base/jit-elf-util.h

> @@ -0,0 +1,117 @@

> +/* This test program is part of GDB, the GNU debugger.

> +

> +   Copyright 2020 Free Software Foundation, Inc.

> +

> +   This program is free software; you can redistribute it and/or modify

> +   it under the terms of the GNU General Public License as published by

> +   the Free Software Foundation; either version 3 of the License, or

> +   (at your option) any later version.

> +

> +   This program is distributed in the hope that it will be useful,

> +   but WITHOUT ANY WARRANTY; without even the implied warranty of

> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

> +   GNU General Public License for more details.

> +

> +   You should have received a copy of the GNU General Public License

> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

> +

> +/* Simulates loading of JIT code by memory mapping a compiled

> +   shared library binary and doing minimal post-processing.  */

> +

> +#include <elf.h>

> +#include <errno.h>

> +#include <fcntl.h>

> +#include <link.h>

> +#include <stdint.h>

> +#include <stdio.h>

> +#include <stdlib.h>

> +#include <string.h>

> +#include <sys/mman.h>

> +#include <sys/stat.h>

> +#include <unistd.h>

> +

> +/* ElfW is coming from linux. On other platforms it does not exist.

> +   Let us define it here. */

> +#ifndef ElfW

> +#if (defined(_LP64) || defined(__LP64__))

> +#define WORDSIZE 64

> +#else

> +#define WORDSIZE 32

> +#endif /* _LP64 || __LP64__  */

> +#define ElfW(type) _ElfW (Elf, WORDSIZE, type)

> +#define _ElfW(e, w, t) _ElfW_1 (e, w, _##t)

> +#define _ElfW_1(e, w, t) e##w##t

> +#endif /* !ElfW  */

> +

> +/* Find symbol with the name `sym_name`.  */

> +static ElfW (Addr)

> +load_symbol (ElfW (Addr) addr, const char *sym_name)

> +{

> +  const ElfW (Ehdr) *const ehdr = (ElfW (Ehdr) *) addr;

> +  ElfW (Shdr) *const shdr = (ElfW (Shdr) *) ((char *) addr + ehdr->e_shoff);

> +

> +  ElfW (Addr) sym_old_addr = 0;

> +  ElfW (Addr) sym_new_addr = 0;

> +

> +  /* Find `func_name` in symbol_table and adjust it from the addr.  */


I'm wondering, is the "and adjust it from the addr" part of the comment still relevant?

> +

> +  for (int i = 0; i < ehdr->e_shnum; ++i)

> +    {

> +      if (shdr[i].sh_type == SHT_SYMTAB)

> +	{

> +	  ElfW (Sym) *symtab = (ElfW (Sym) *) (addr + shdr[i].sh_offset);

> +	  ElfW (Sym) *symtab_end

> +	      = (ElfW (Sym) *) (addr + shdr[i].sh_offset + shdr[i].sh_size);

> +	  char *const strtab

> +	      = (char *) (addr + shdr[shdr[i].sh_link].sh_offset);

> +

> +	  for (ElfW (Sym) *p = symtab; p < symtab_end; ++p)

> +	    {

> +	      const char *s = strtab + p->st_name;

> +	      if (strcmp (s, sym_name) == 0)

> +	        return p->st_value;

> +	    }

> +	}

> +    }

> +

> +  fprintf (stderr, "symbol '%s' not found\n", sym_name);

> +  exit (1);

> +  return 0;

> +}

> +

> +/* Open an elf binary file and memory map it with execution flag enabled.  */

> +static ElfW (Addr)

> +load_elf (const char *libname, size_t *size, ElfW (Addr) load_addr)


I think load_addr should be a `void *` directly.

> +{

> +  int fd;

> +  struct stat st;

> +

> +  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);

> +    }

> +

> +  void *addr = mmap ((void *) load_addr, st.st_size,

> +		     PROT_READ | PROT_WRITE | PROT_EXEC,

> +		     load_addr ? MAP_PRIVATE | MAP_FIXED : MAP_PRIVATE, fd, 0);


Assuming load_addr becomes a `void *`, the condition should be `load_addr != NULL`.

Simon

Patch

diff --git a/gdb/testsuite/gdb.base/jit-elf-main.c b/gdb/testsuite/gdb.base/jit-elf-main.c
index b74212dbf5..b812cb91e5 100644
--- a/gdb/testsuite/gdb.base/jit-elf-main.c
+++ b/gdb/testsuite/gdb.base/jit-elf-main.c
@@ -30,19 +30,7 @@ 
 #include <unistd.h>
 
 #include "jit-protocol.h"
-
-/* ElfW is coming from linux. On other platforms it does not exist.
-   Let us define it here. */
-#ifndef ElfW
-# if (defined  (_LP64) || defined (__LP64__)) 
-#   define WORDSIZE 64
-# else
-#   define WORDSIZE 32
-# endif /* _LP64 || __LP64__  */
-#define ElfW(type)      _ElfW (Elf, WORDSIZE, type)
-#define _ElfW(e,w,t)    _ElfW_1 (e, w, _##t)
-#define _ElfW_1(e,w,t)  e##w##t
-#endif /* !ElfW  */
+#include "jit-elf-util.h"
 
 static void
 usage (void)
@@ -95,37 +83,19 @@  MAIN (int argc, char *argv[])
 
   for (i = 1; i < argc; ++i)
     {
-      struct stat st;
-      int fd;
-
-      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);
-	}
+      size_t obj_size;
+      ElfW (Addr) load_addr = LOAD_ADDRESS + (i-1) * LOAD_INCREMENT;
+      printf("Loading %s as JIT at %p\n", argv[i], (void*) load_addr);
+      ElfW (Addr) addr = load_elf (argv[i], &obj_size, load_addr);
 
-      if (fstat (fd, &st) != 0)
-	{
-	  fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno));
-	  exit (1);
-	}
-
-      void* load_addr = (void*) (size_t) (LOAD_ADDRESS + (i - 1) * LOAD_INCREMENT);
-      const void *const addr = mmap (load_addr, st.st_size, PROT_READ|PROT_WRITE,
-				     MAP_PRIVATE | MAP_FIXED, 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);
-	}
+      char name[32];
+      sprintf (name, "jit_function_%04d", i);
+      int (*jit_function) () = (int (*) ()) load_symbol (addr, name);
 
       /* Link entry at the end of the list.  */
+      struct jit_code_entry *const entry = calloc (1, sizeof (*entry));
       entry->symfile_addr = (const char *)addr;
-      entry->symfile_size = st.st_size;
+      entry->symfile_size = obj_size;
       entry->prev_entry = __jit_debug_descriptor.relevant_entry;
       __jit_debug_descriptor.relevant_entry = entry;
 
@@ -137,6 +107,12 @@  MAIN (int argc, char *argv[])
       /* Notify GDB.  */
       __jit_debug_descriptor.action_flag = JIT_REGISTER;
       __jit_debug_register_code ();
+
+      if (jit_function () != 42)
+	{
+	  fprintf (stderr, "unexpected return value\n");
+	  exit (1);
+	}
     }
 
   WAIT_FOR_GDB; i = 0;  /* gdb break here 1 */
diff --git a/gdb/testsuite/gdb.base/jit-elf-util.h b/gdb/testsuite/gdb.base/jit-elf-util.h
new file mode 100644
index 0000000000..e48d99f098
--- /dev/null
+++ b/gdb/testsuite/gdb.base/jit-elf-util.h
@@ -0,0 +1,117 @@ 
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Simulates loading of JIT code by memory mapping a compiled
+   shared library binary and doing minimal post-processing.  */
+
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <link.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* ElfW is coming from linux. On other platforms it does not exist.
+   Let us define it here. */
+#ifndef ElfW
+#if (defined(_LP64) || defined(__LP64__))
+#define WORDSIZE 64
+#else
+#define WORDSIZE 32
+#endif /* _LP64 || __LP64__  */
+#define ElfW(type) _ElfW (Elf, WORDSIZE, type)
+#define _ElfW(e, w, t) _ElfW_1 (e, w, _##t)
+#define _ElfW_1(e, w, t) e##w##t
+#endif /* !ElfW  */
+
+/* Find symbol with the name `sym_name`.  */
+static ElfW (Addr)
+load_symbol (ElfW (Addr) addr, const char *sym_name)
+{
+  const ElfW (Ehdr) *const ehdr = (ElfW (Ehdr) *) addr;
+  ElfW (Shdr) *const shdr = (ElfW (Shdr) *) ((char *) addr + ehdr->e_shoff);
+
+  ElfW (Addr) sym_old_addr = 0;
+  ElfW (Addr) sym_new_addr = 0;
+
+  /* Find `func_name` in symbol_table and adjust it from the addr.  */
+
+  for (int i = 0; i < ehdr->e_shnum; ++i)
+    {
+      if (shdr[i].sh_type == SHT_SYMTAB)
+	{
+	  ElfW (Sym) *symtab = (ElfW (Sym) *) (addr + shdr[i].sh_offset);
+	  ElfW (Sym) *symtab_end
+	      = (ElfW (Sym) *) (addr + shdr[i].sh_offset + shdr[i].sh_size);
+	  char *const strtab
+	      = (char *) (addr + shdr[shdr[i].sh_link].sh_offset);
+
+	  for (ElfW (Sym) *p = symtab; p < symtab_end; ++p)
+	    {
+	      const char *s = strtab + p->st_name;
+	      if (strcmp (s, sym_name) == 0)
+	        return p->st_value;
+	    }
+	}
+    }
+
+  fprintf (stderr, "symbol '%s' not found\n", sym_name);
+  exit (1);
+  return 0;
+}
+
+/* Open an elf binary file and memory map it with execution flag enabled.  */
+static ElfW (Addr)
+load_elf (const char *libname, size_t *size, ElfW (Addr) load_addr)
+{
+  int fd;
+  struct stat st;
+
+  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);
+    }
+
+  void *addr = mmap ((void *) load_addr, st.st_size,
+		     PROT_READ | PROT_WRITE | PROT_EXEC,
+		     load_addr ? MAP_PRIVATE | MAP_FIXED : MAP_PRIVATE, fd, 0);
+  close (fd);
+
+  if (addr == MAP_FAILED)
+    {
+      fprintf (stderr, "mmap: %s\n", strerror (errno));
+      exit (1);
+    }
+
+  if (size != NULL)
+    *size = st.st_size;
+
+  return (ElfW (Addr)) addr;
+}