1 /* This test program is part of GDB, the GNU debugger. 2 3 Copyright 2020-2024 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 int i; 58 for (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 ElfW (Sym) *p; 69 for (p = symtab; p < symtab_end; ++p) 70 { 71 const char *s = strtab + p->st_name; 72 if (strcmp (s, sym_name) == 0) 73 return (void *) p->st_value; 74 } 75 } 76 } 77 78 fprintf (stderr, "symbol '%s' not found\n", sym_name); 79 exit (1); 80 return 0; 81 } 82 83 /* Open an elf binary file and memory map it with execution flag enabled. */ 84 static void * 85 load_elf (const char *libname, size_t *size, void *load_addr) 86 { 87 int fd; 88 struct stat st; 89 90 if ((fd = open (libname, O_RDONLY)) == -1) 91 { 92 fprintf (stderr, "open (\"%s\", O_RDONLY): %s\n", libname, 93 strerror (errno)); 94 exit (1); 95 } 96 97 if (fstat (fd, &st) != 0) 98 { 99 fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno)); 100 exit (1); 101 } 102 103 void *addr = mmap (load_addr, st.st_size, 104 PROT_READ | PROT_WRITE | PROT_EXEC, 105 load_addr != NULL ? MAP_PRIVATE | MAP_FIXED : MAP_PRIVATE, 106 fd, 0); 107 close (fd); 108 109 if (addr == MAP_FAILED) 110 { 111 fprintf (stderr, "mmap: %s\n", strerror (errno)); 112 exit (1); 113 } 114 115 if (size != NULL) 116 *size = st.st_size; 117 118 return addr; 119 } 120