1/* This test program is part of GDB, the GNU debugger. 2 3 Copyright 2011 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 19/* Simulate loading of JIT code. */ 20 21#include <elf.h> 22#include <link.h> 23#include <errno.h> 24#include <fcntl.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 32/* ElfW is coming from linux. On other platforms it does not exist. 33 Let us define it here. */ 34#ifndef ElfW 35# if (defined (_LP64) || defined (__LP64__)) 36# define WORDSIZE 64 37# else 38# define WORDSIZE 32 39# endif /* _LP64 || __LP64__ */ 40#define ElfW(type) _ElfW (Elf, WORDSIZE, type) 41#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t) 42#define _ElfW_1(e,w,t) e##w##t 43#endif /* !ElfW */ 44 45typedef enum 46{ 47 JIT_NOACTION = 0, 48 JIT_REGISTER_FN, 49 JIT_UNREGISTER_FN 50} jit_actions_t; 51 52struct jit_code_entry 53{ 54 struct jit_code_entry *next_entry; 55 struct jit_code_entry *prev_entry; 56 const char *symfile_addr; 57 uint64_t symfile_size; 58}; 59 60struct jit_descriptor 61{ 62 uint32_t version; 63 /* This type should be jit_actions_t, but we use uint32_t 64 to be explicit about the bitwidth. */ 65 uint32_t action_flag; 66 struct jit_code_entry *relevant_entry; 67 struct jit_code_entry *first_entry; 68}; 69 70/* GDB puts a breakpoint in this function. */ 71void __attribute__((noinline)) __jit_debug_register_code () { } 72 73/* Make sure to specify the version statically, because the 74 debugger may check the version before we can set it. */ 75struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 76 77static void 78usage (const char *const argv0) 79{ 80 fprintf (stderr, "Usage: %s library [count]\n", argv0); 81 exit (1); 82} 83 84/* Update .p_vaddr and .sh_addr as if the code was JITted to ADDR. */ 85 86static void 87update_locations (const void *const addr, int idx) 88{ 89 const ElfW (Ehdr) *const ehdr = (ElfW (Ehdr) *)addr; 90 ElfW (Shdr) *const shdr = (ElfW (Shdr) *)((char *)addr + ehdr->e_shoff); 91 ElfW (Phdr) *const phdr = (ElfW (Phdr) *)((char *)addr + ehdr->e_phoff); 92 int i; 93 94 for (i = 0; i < ehdr->e_phnum; ++i) 95 if (phdr[i].p_type == PT_LOAD) 96 phdr[i].p_vaddr += (ElfW (Addr))addr; 97 98 for (i = 0; i < ehdr->e_shnum; ++i) 99 { 100 if (shdr[i].sh_type == SHT_STRTAB) 101 { 102 /* Note: we update both .strtab and .dynstr. The latter would 103 not be correct if this were a regular shared library (.hash 104 would be wrong), but this is a simulation -- the library is 105 never exposed to the dynamic loader, so it all ends up ok. */ 106 char *const strtab = (char *)((ElfW (Addr))addr + shdr[i].sh_offset); 107 char *const strtab_end = strtab + shdr[i].sh_size; 108 char *p; 109 110 for (p = strtab; p < strtab_end; p += strlen (p) + 1) 111 if (strcmp (p, "jit_function_XXXX") == 0) 112 sprintf (p, "jit_function_%04d", idx); 113 } 114 115 if (shdr[i].sh_flags & SHF_ALLOC) 116 shdr[i].sh_addr += (ElfW (Addr))addr; 117 } 118} 119 120#ifndef MAIN 121#define MAIN main 122#endif 123 124int 125MAIN (int argc, char *argv[]) 126{ 127 /* These variables are here so they can easily be set from jit.exp. */ 128 const char *libname = NULL; 129 int count = 0; 130 131 count = count; /* gdb break here 0 */ 132 133 if (argc < 2) 134 usage (argv[0]); 135 else 136 { 137 int i, fd; 138 struct stat st; 139 140 if (libname == NULL) 141 /* Only set if not already set from GDB. */ 142 libname = argv[1]; 143 144 if (argc > 2 && count == 0) 145 /* Only set if not already set from GDB. */ 146 count = atoi (argv[2]); 147 148 printf ("%s:%d: libname = %s, count = %d\n", __FILE__, __LINE__, 149 libname, count); 150 151 if ((fd = open (libname, O_RDONLY)) == -1) 152 { 153 fprintf (stderr, "open (\"%s\", O_RDONLY): %s\n", libname, 154 strerror (errno)); 155 exit (1); 156 } 157 158 if (fstat (fd, &st) != 0) 159 { 160 fprintf (stderr, "fstat (\"%d\"): %s\n", fd, strerror (errno)); 161 exit (1); 162 } 163 164 for (i = 0; i < count; ++i) 165 { 166 const void *const addr = mmap (0, st.st_size, PROT_READ|PROT_WRITE, 167 MAP_PRIVATE, fd, 0); 168 struct jit_code_entry *const entry = calloc (1, sizeof (*entry)); 169 170 if (addr == MAP_FAILED) 171 { 172 fprintf (stderr, "mmap: %s\n", strerror (errno)); 173 exit (1); 174 } 175 176 update_locations (addr, i); 177 178 /* Link entry at the end of the list. */ 179 entry->symfile_addr = (const char *)addr; 180 entry->symfile_size = st.st_size; 181 entry->prev_entry = __jit_debug_descriptor.relevant_entry; 182 __jit_debug_descriptor.relevant_entry = entry; 183 184 if (entry->prev_entry != NULL) 185 entry->prev_entry->next_entry = entry; 186 else 187 __jit_debug_descriptor.first_entry = entry; 188 189 /* Notify GDB. */ 190 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 191 __jit_debug_register_code (); 192 } 193 194 i = 0; /* gdb break here 1 */ 195 196 /* Now unregister them all in reverse order. */ 197 while (__jit_debug_descriptor.relevant_entry != NULL) 198 { 199 struct jit_code_entry *const entry = 200 __jit_debug_descriptor.relevant_entry; 201 struct jit_code_entry *const prev_entry = entry->prev_entry; 202 203 if (prev_entry != NULL) 204 { 205 prev_entry->next_entry = NULL; 206 entry->prev_entry = NULL; 207 } 208 else 209 __jit_debug_descriptor.first_entry = NULL; 210 211 /* Notify GDB. */ 212 __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; 213 __jit_debug_register_code (); 214 215 __jit_debug_descriptor.relevant_entry = prev_entry; 216 free (entry); 217 } 218 } 219 return 0; /* gdb break here 2 */ 220} 221