1 /* This test program is part of GDB, the GNU debugger. 2 3 Copyright 2020 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 /* Simulates loading of JIT code by memory mapping a compiled 19 shared library binary and doing minimal post-processing. */ 20 21 #include <elf.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <link.h> 25 #include <stdint.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <sys/mman.h> 30 #include <sys/stat.h> 31 #include <unistd.h> 32 33 /* ElfW is coming from linux. On other platforms it does not exist. 34 Let us define it here. */ 35 #ifndef ElfW 36 #if (defined(_LP64) || defined(__LP64__)) 37 #define WORDSIZE 64 38 #else 39 #define WORDSIZE 32 40 #endif /* _LP64 || __LP64__ */ 41 #define ElfW(type) _ElfW (Elf, WORDSIZE, type) 42 #define _ElfW(e, w, t) _ElfW_1 (e, w, _##t) 43 #define _ElfW_1(e, w, t) e##w##t 44 #endif /* !ElfW */ 45 46 /* Find symbol with the name `sym_name`. */ 47 static void * 48 load_symbol (void *addr, const char *sym_name) 49 { 50 const ElfW (Ehdr) *const ehdr = (ElfW (Ehdr) *) addr; 51 ElfW (Shdr) *const shdr = (ElfW (Shdr) *) ((char *) addr + ehdr->e_shoff); 52 53 ElfW (Addr) sym_old_addr = 0; 54 ElfW (Addr) sym_new_addr = 0; 55 56 /* Find `func_name` in symbol_table and return its address. */ 57 58 for (int i = 0; i < ehdr->e_shnum; ++i) 59 { 60 if (shdr[i].sh_type == SHT_SYMTAB) 61 { 62 ElfW (Sym) *symtab = (ElfW (Sym) *) (addr + shdr[i].sh_offset); 63 ElfW (Sym) *symtab_end 64 = (ElfW (Sym) *) (addr + shdr[i].sh_offset + shdr[i].sh_size); 65 char *const strtab 66 = (char *) (addr + shdr[shdr[i].sh_link].sh_offset); 67 68 for (ElfW (Sym) *p = symtab; p < symtab_end; ++p) 69 { 70 const char *s = strtab + p->st_name; 71 if (strcmp (s, sym_name) == 0) 72 return (void *) p->st_value; 73 } 74 } 75 } 76 77 fprintf (stderr, "symbol '%s' not found\n", sym_name); 78 exit (1); 79 return 0; 80 } 81 82 /* Open an elf binary file and memory map it with execution flag enabled. */ 83 static void * 84 load_elf (const char *libname, size_t *size, void *load_addr) 85 { 86 int fd; 87 struct stat st; 88 89 if ((fd = open (libname, O_RDONLY)) == -1) 90 { 91 fprintf (stderr, "open (\"%s\", O_RDONLY): %s\n", libname, 92 strerror (errno)); 93 exit (1); 94 } 95 96 if (fstat (fd, &st) != 0) 97 { 98 fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno)); 99 exit (1); 100 } 101 102 void *addr = mmap (load_addr, st.st_size, 103 PROT_READ | PROT_WRITE | PROT_EXEC, 104 load_addr != NULL ? MAP_PRIVATE | MAP_FIXED : MAP_PRIVATE, 105 fd, 0); 106 close (fd); 107 108 if (addr == MAP_FAILED) 109 { 110 fprintf (stderr, "mmap: %s\n", strerror (errno)); 111 exit (1); 112 } 113 114 if (size != NULL) 115 *size = st.st_size; 116 117 return addr; 118 } 119