blob: d791bfe16373e156b434c00628a1546f146ab71a [file] [log] [blame]
Juan Cespedesd44c6b81998-09-25 14:48:42 +02001#if HAVE_CONFIG_H
Juan Cespedesd914a202004-11-10 00:15:33 +01002# include "config.h"
Juan Cespedesd44c6b81998-09-25 14:48:42 +02003#endif
4
Juan Cespedesd914a202004-11-10 00:15:33 +01005#include <endian.h>
Juan Cespedes96935a91997-08-09 23:45:39 +02006#include <errno.h>
Juan Cespedesd914a202004-11-10 00:15:33 +01007#include <error.h>
Juan Cespedes96935a91997-08-09 23:45:39 +02008#include <fcntl.h>
Juan Cespedesd914a202004-11-10 00:15:33 +01009#include <gelf.h>
10#include <stdint.h>
11#include <stdlib.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020012#include <string.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +010013#include <unistd.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020014
Juan Cespedes96935a91997-08-09 23:45:39 +020015#include "ltrace.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010016#include "elf.h"
Juan Cespedescac15c32003-01-31 18:58:58 +010017#include "debug.h"
Ian Wienand9a2ad352006-02-20 22:44:45 +010018#include "options.h"
Juan Cespedes96935a91997-08-09 23:45:39 +020019
Ian Wienand2d45b1a2006-02-20 22:48:07 +010020static void do_init_elf(struct ltelf *lte, const char *filename);
21static void do_close_elf(struct ltelf *lte);
22static void add_library_symbol(GElf_Addr addr, const char *name,
23 struct library_symbol **library_symbolspp,
24 int use_elf_plt2addr, int is_weak);
25static int in_load_libraries(const char *name, struct ltelf *lte);
26static GElf_Addr elf_plt2addr(struct ltelf *ltc, void *addr);
Juan Cespedes1cd999a2001-07-03 00:46:04 +020027
Paul Gilliambe320772006-04-24 22:06:23 +020028#ifdef PLT_REINITALISATION_BP
Ian Wienand2d45b1a2006-02-20 22:48:07 +010029extern char *PLTs_initialized_by_here;
Paul Gilliambe320772006-04-24 22:06:23 +020030#endif
Ian Wienand9a2ad352006-02-20 22:44:45 +010031
Ian Wienand2d45b1a2006-02-20 22:48:07 +010032static void do_init_elf(struct ltelf *lte, const char *filename)
Juan Cespedesd914a202004-11-10 00:15:33 +010033{
Ian Wienand2d45b1a2006-02-20 22:48:07 +010034 int i;
35 GElf_Addr relplt_addr = 0;
36 size_t relplt_size = 0;
Juan Cespedes1cd999a2001-07-03 00:46:04 +020037
Ian Wienand2d45b1a2006-02-20 22:48:07 +010038 debug(1, "Reading ELF from %s...", filename);
Juan Cespedes1afec691997-08-23 21:31:46 +020039
Ian Wienand2d45b1a2006-02-20 22:48:07 +010040 memset(lte, 0, sizeof(*lte));
41 lte->fd = open(filename, O_RDONLY);
42 if (lte->fd == -1)
43 error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
Juan Cespedes96935a91997-08-09 23:45:39 +020044
Juan Cespedesd914a202004-11-10 00:15:33 +010045#ifdef HAVE_ELF_C_READ_MMAP
Ian Wienand2d45b1a2006-02-20 22:48:07 +010046 lte->elf = elf_begin(lte->fd, ELF_C_READ_MMAP, NULL);
Juan Cespedes5c3fe062004-06-14 18:08:37 +020047#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010048 lte->elf = elf_begin(lte->fd, ELF_C_READ, NULL);
Juan Cespedes5c3fe062004-06-14 18:08:37 +020049#endif
Juan Cespedes1cd999a2001-07-03 00:46:04 +020050
Ian Wienand2d45b1a2006-02-20 22:48:07 +010051 if (lte->elf == NULL || elf_kind(lte->elf) != ELF_K_ELF)
52 error(EXIT_FAILURE, 0, "Can't open ELF file \"%s\"", filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +020053
Ian Wienand2d45b1a2006-02-20 22:48:07 +010054 if (gelf_getehdr(lte->elf, &lte->ehdr) == NULL)
55 error(EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"",
56 filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +020057
Ian Wienand2d45b1a2006-02-20 22:48:07 +010058 if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN)
59 error(EXIT_FAILURE, 0,
60 "\"%s\" is not an ELF executable nor shared library",
61 filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +020062
Ian Wienand2d45b1a2006-02-20 22:48:07 +010063 if ((lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS
64 || lte->ehdr.e_machine != LT_ELF_MACHINE)
Juan Cespedesd914a202004-11-10 00:15:33 +010065#ifdef LT_ELF_MACHINE2
Ian Wienand2d45b1a2006-02-20 22:48:07 +010066 && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS2
67 || lte->ehdr.e_machine != LT_ELF_MACHINE2)
Juan Cespedesd914a202004-11-10 00:15:33 +010068#endif
69#ifdef LT_ELF_MACHINE3
Ian Wienand2d45b1a2006-02-20 22:48:07 +010070 && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS3
71 || lte->ehdr.e_machine != LT_ELF_MACHINE3)
Juan Cespedesd914a202004-11-10 00:15:33 +010072#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +010073 )
74 error(EXIT_FAILURE, 0,
75 "\"%s\" is ELF from incompatible architecture", filename);
Juan Cespedesd914a202004-11-10 00:15:33 +010076
Ian Wienand2d45b1a2006-02-20 22:48:07 +010077 for (i = 1; i < lte->ehdr.e_shnum; ++i) {
78 Elf_Scn *scn;
79 GElf_Shdr shdr;
80 const char *name;
Juan Cespedesd914a202004-11-10 00:15:33 +010081
Ian Wienand2d45b1a2006-02-20 22:48:07 +010082 scn = elf_getscn(lte->elf, i);
83 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
84 error(EXIT_FAILURE, 0,
85 "Couldn't get section header from \"%s\"",
86 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +010087
Ian Wienand2d45b1a2006-02-20 22:48:07 +010088 name = elf_strptr(lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
89 if (name == NULL)
90 error(EXIT_FAILURE, 0,
91 "Couldn't get section header from \"%s\"",
92 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +010093
Ian Wienand2d45b1a2006-02-20 22:48:07 +010094 if (shdr.sh_type == SHT_SYMTAB) {
95 Elf_Data *data;
Juan Cespedesd914a202004-11-10 00:15:33 +010096
Ian Wienand2d45b1a2006-02-20 22:48:07 +010097 lte->symtab = elf_getdata(scn, NULL);
98 lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
99 if ((lte->symtab == NULL
100 || elf_getdata(scn, lte->symtab) != NULL)
101 && opt_x != NULL)
102 error(EXIT_FAILURE, 0,
103 "Couldn't get .symtab data from \"%s\"",
104 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100105
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100106 scn = elf_getscn(lte->elf, shdr.sh_link);
107 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
108 error(EXIT_FAILURE, 0,
109 "Couldn't get section header from \"%s\"",
110 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100111
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100112 data = elf_getdata(scn, NULL);
113 if (data == NULL || elf_getdata(scn, data) != NULL
114 || shdr.sh_size != data->d_size || data->d_off)
115 error(EXIT_FAILURE, 0,
116 "Couldn't get .strtab data from \"%s\"",
117 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100118
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100119 lte->strtab = data->d_buf;
120 } else if (shdr.sh_type == SHT_DYNSYM) {
121 Elf_Data *data;
Juan Cespedesd914a202004-11-10 00:15:33 +0100122
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100123 lte->dynsym = elf_getdata(scn, NULL);
124 lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
125 if (lte->dynsym == NULL
126 || elf_getdata(scn, lte->dynsym) != NULL)
127 error(EXIT_FAILURE, 0,
128 "Couldn't get .dynsym data from \"%s\"",
129 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100130
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100131 scn = elf_getscn(lte->elf, shdr.sh_link);
132 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
133 error(EXIT_FAILURE, 0,
134 "Couldn't get section header from \"%s\"",
135 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100136
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100137 data = elf_getdata(scn, NULL);
138 if (data == NULL || elf_getdata(scn, data) != NULL
139 || shdr.sh_size != data->d_size || data->d_off)
140 error(EXIT_FAILURE, 0,
141 "Couldn't get .dynstr data from \"%s\"",
142 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100143
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100144 lte->dynstr = data->d_buf;
145 } else if (shdr.sh_type == SHT_DYNAMIC) {
146 Elf_Data *data;
147 size_t j;
Juan Cespedesd914a202004-11-10 00:15:33 +0100148
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100149 data = elf_getdata(scn, NULL);
150 if (data == NULL || elf_getdata(scn, data) != NULL)
151 error(EXIT_FAILURE, 0,
152 "Couldn't get .dynamic data from \"%s\"",
153 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100154
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100155 for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
156 GElf_Dyn dyn;
Juan Cespedesd914a202004-11-10 00:15:33 +0100157
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100158 if (gelf_getdyn(data, j, &dyn) == NULL)
159 error(EXIT_FAILURE, 0,
160 "Couldn't get .dynamic data from \"%s\"",
161 filename);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100162
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100163 if (dyn.d_tag == DT_JMPREL)
164 relplt_addr = dyn.d_un.d_ptr;
165 else if (dyn.d_tag == DT_PLTRELSZ)
166 relplt_size = dyn.d_un.d_val;
167 }
168 } else if (shdr.sh_type == SHT_HASH) {
169 Elf_Data *data;
170 size_t j;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100171
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100172 data = elf_getdata(scn, NULL);
173 if (data == NULL || elf_getdata(scn, data) != NULL
174 || data->d_off || data->d_size != shdr.sh_size)
175 error(EXIT_FAILURE, 0,
176 "Couldn't get .hash data from \"%s\"",
177 filename);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100178
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100179 if (shdr.sh_entsize == 4) {
180 /* Standard conforming ELF. */
181 if (data->d_type != ELF_T_WORD)
182 error(EXIT_FAILURE, 0,
183 "Couldn't get .hash data from \"%s\"",
184 filename);
185 lte->hash = (Elf32_Word *) data->d_buf;
186 } else if (shdr.sh_entsize == 8) {
187 /* Alpha or s390x. */
188 Elf32_Word *dst, *src;
189 size_t hash_count = data->d_size / 8;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100190
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100191 lte->hash = (Elf32_Word *)
192 malloc(hash_count * sizeof(Elf32_Word));
193 if (lte->hash == NULL)
194 error(EXIT_FAILURE, 0,
195 "Couldn't convert .hash section from \"%s\"",
196 filename);
197 lte->hash_malloced = 1;
198 dst = lte->hash;
199 src = (Elf32_Word *) data->d_buf;
200 if ((data->d_type == ELF_T_WORD
201 && __BYTE_ORDER == __BIG_ENDIAN)
202 || (data->d_type == ELF_T_XWORD
203 && lte->ehdr.e_ident[EI_DATA] ==
204 ELFDATA2MSB))
205 ++src;
206 for (j = 0; j < hash_count; ++j, src += 2)
207 *dst++ = *src;
208 } else
209 error(EXIT_FAILURE, 0,
210 "Unknown .hash sh_entsize in \"%s\"",
211 filename);
212 } else if (shdr.sh_type == SHT_PROGBITS
213 || shdr.sh_type == SHT_NOBITS) {
214 if (strcmp(name, ".plt") == 0) {
215 lte->plt_addr = shdr.sh_addr;
216 lte->plt_size = shdr.sh_size;
217 } else if (strcmp(name, ".opd") == 0) {
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200218 lte->opd_addr = (GElf_Addr *) (long) shdr.sh_addr;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100219 lte->opd_size = shdr.sh_size;
220 lte->opd = elf_rawdata(scn, NULL);
221 }
222 }
Juan Cespedesd914a202004-11-10 00:15:33 +0100223 }
224
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100225 if (lte->dynsym == NULL || lte->dynstr == NULL)
226 error(EXIT_FAILURE, 0,
227 "Couldn't find .dynsym or .dynstr in \"%s\"", filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100228
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100229 if (!relplt_addr || !lte->plt_addr) {
230 debug(1, "%s has no PLT relocations", filename);
231 lte->relplt = NULL;
232 lte->relplt_count = 0;
233 } else {
234 for (i = 1; i < lte->ehdr.e_shnum; ++i) {
235 Elf_Scn *scn;
236 GElf_Shdr shdr;
237
238 scn = elf_getscn(lte->elf, i);
239 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
240 error(EXIT_FAILURE, 0,
241 "Couldn't get section header from \"%s\"",
242 filename);
243 if (shdr.sh_addr == relplt_addr
244 && shdr.sh_size == relplt_size) {
245 lte->relplt = elf_getdata(scn, NULL);
246 lte->relplt_count =
247 shdr.sh_size / shdr.sh_entsize;
248 if (lte->relplt == NULL
249 || elf_getdata(scn, lte->relplt) != NULL)
250 error(EXIT_FAILURE, 0,
251 "Couldn't get .rel*.plt data from \"%s\"",
252 filename);
253 break;
254 }
255 }
256
257 if (i == lte->ehdr.e_shnum)
258 error(EXIT_FAILURE, 0,
259 "Couldn't find .rel*.plt section in \"%s\"",
260 filename);
261
262 debug(1, "%s %zd PLT relocations", filename, lte->relplt_count);
263 }
264}
265
266static void do_close_elf(struct ltelf *lte)
267{
268 if (lte->hash_malloced)
269 free((char *)lte->hash);
270 elf_end(lte->elf);
271 close(lte->fd);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200272}
273
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100274static void
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100275add_library_symbol(GElf_Addr addr, const char *name,
276 struct library_symbol **library_symbolspp,
277 int use_elf_plt2addr, int is_weak)
Juan Cespedesd914a202004-11-10 00:15:33 +0100278{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100279 struct library_symbol *s;
280 s = malloc(sizeof(struct library_symbol) + strlen(name) + 1);
281 if (s == NULL)
282 error(EXIT_FAILURE, errno, "add_library_symbol failed");
283
284 s->needs_init = 1;
285 s->is_weak = is_weak;
286 s->static_plt2addr = use_elf_plt2addr;
287 s->next = *library_symbolspp;
288 s->enter_addr = (void *)(uintptr_t) addr;
289 s->brkpnt = NULL;
290 s->name = (char *)(s + 1);
291 strcpy(s->name, name);
292 *library_symbolspp = s;
293
294 debug(2, "addr: %p, symbol: \"%s\"", (void *)(uintptr_t) addr, name);
Juan Cespedesd914a202004-11-10 00:15:33 +0100295}
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200296
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100297static int in_load_libraries(const char *name, struct ltelf *lte)
Juan Cespedesd914a202004-11-10 00:15:33 +0100298{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100299 size_t i;
300 unsigned long hash;
Juan Cespedesd914a202004-11-10 00:15:33 +0100301
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100302 if (!library_num)
303 return 1;
Juan Cespedesd914a202004-11-10 00:15:33 +0100304
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200305 hash = elf_hash((const unsigned char *)name);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100306 for (i = 1; i <= library_num; ++i) {
307 Elf32_Word nbuckets, symndx;
308 Elf32_Word *buckets, *chain;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200309
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100310 if (lte[i].hash == NULL)
311 continue;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200312
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100313 nbuckets = lte[i].hash[0];
314 buckets = &lte[i].hash[2];
315 chain = &lte[i].hash[2 + nbuckets];
316 for (symndx = buckets[hash % nbuckets];
317 symndx != STN_UNDEF; symndx = chain[symndx]) {
318 GElf_Sym sym;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200319
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100320 if (gelf_getsym(lte[i].dynsym, symndx, &sym) == NULL)
321 error(EXIT_FAILURE, 0,
322 "Couldn't get symbol from .dynsym");
Juan Cespedesd914a202004-11-10 00:15:33 +0100323
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100324 if (sym.st_value != 0
325 && sym.st_shndx != SHN_UNDEF
326 && strcmp(name, lte[i].dynstr + sym.st_name) == 0)
327 return 1;
328 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200329 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100330 return 0;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100331}
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200332
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100333static GElf_Addr elf_plt2addr(struct ltelf *lte, void *addr)
Ian Wienand9a2ad352006-02-20 22:44:45 +0100334{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100335 long base;
336 long offset;
337 GElf_Addr ret_val;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200338
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100339 if (!lte->opd)
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200340 return (GElf_Addr) (long) addr;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100341
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100342 base = (long)lte->opd->d_buf;
343 offset = (long)addr - (long)lte->opd_addr;
344 if (offset > lte->opd_size)
345 error(EXIT_FAILURE, 0, "static plt not in .opd");
346
347 ret_val = (GElf_Addr) * (long *)(base + offset);
348 return ret_val;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100349}
350
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100351struct library_symbol *read_elf(struct process *proc)
Ian Wienand9a2ad352006-02-20 22:44:45 +0100352{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100353 struct library_symbol *library_symbols = NULL;
354 struct ltelf lte[MAX_LIBRARY + 1];
355 size_t i;
Paul Gilliam24e643a2006-03-13 18:43:13 +0100356 struct opt_x_t *xptr;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100357 struct library_symbol **lib_tail = NULL;
Paul Gilliam24e643a2006-03-13 18:43:13 +0100358 struct opt_x_t *main_cheat;
359 int exit_out = 0;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100360
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100361 elf_version(EV_CURRENT);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100362
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100363 do_init_elf(lte, proc->filename);
364 proc->e_machine = lte->ehdr.e_machine;
365 for (i = 0; i < library_num; ++i)
366 do_init_elf(&lte[i + 1], library[i]);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100367
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100368 for (i = 0; i < lte->relplt_count; ++i) {
369 GElf_Rel rel;
370 GElf_Rela rela;
371 GElf_Sym sym;
372 GElf_Addr addr;
373 void *ret;
374 const char *name;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100375
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100376 if (lte->relplt->d_type == ELF_T_REL) {
377 ret = gelf_getrel(lte->relplt, i, &rel);
378 rela.r_offset = rel.r_offset;
379 rela.r_info = rel.r_info;
380 rela.r_addend = 0;
381 } else
382 ret = gelf_getrela(lte->relplt, i, &rela);
383
384 if (ret == NULL
385 || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
386 || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
387 &sym) == NULL)
388 error(EXIT_FAILURE, 0,
389 "Couldn't get relocation from \"%s\"",
390 proc->filename);
391
Paul Gilliambe320772006-04-24 22:06:23 +0200392#ifdef PLT_REINITALISATION_BP
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100393 if (!sym.st_value && PLTs_initialized_by_here)
394 proc->need_to_reinitialize_breakpoints = 1;
Paul Gilliambe320772006-04-24 22:06:23 +0200395#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100396
397 name = lte->dynstr + sym.st_name;
398 if (in_load_libraries(name, lte)) {
399 addr = arch_plt_sym_val(lte, i, &rela);
400 add_library_symbol(addr, name, &library_symbols, 0,
401 ELF64_ST_BIND(sym.st_info) != 0);
402 if (!lib_tail)
403 lib_tail = &(library_symbols->next);
404 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100405 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100406
Paul Gilliambe320772006-04-24 22:06:23 +0200407#ifdef PLT_REINITALISATION_BP
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100408 if (proc->need_to_reinitialize_breakpoints) {
Paul Gilliambe320772006-04-24 22:06:23 +0200409 /* Add "PLTs_initialized_by_here" to opt_x list, if not
410 already there. */
Paul Gilliam2b2507a2006-04-07 18:32:07 +0200411 main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100412 if (main_cheat == NULL)
413 error(EXIT_FAILURE, 0, "Couldn allocate memory");
414 main_cheat->next = opt_x;
Paul Gilliambe320772006-04-24 22:06:23 +0200415 main_cheat->found = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100416 main_cheat->name = PLTs_initialized_by_here;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100417
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100418 for (xptr = opt_x; xptr; xptr = xptr->next)
419 if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
420 && main_cheat) {
421 free(main_cheat);
422 main_cheat = NULL;
423 break;
424 }
425 if (main_cheat)
426 opt_x = main_cheat;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100427 }
Paul Gilliambe320772006-04-24 22:06:23 +0200428#endif
Ian Wienand9a2ad352006-02-20 22:44:45 +0100429
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100430 for (i = 0; i < lte->symtab_count; ++i) {
431 GElf_Sym sym;
432 GElf_Addr addr;
433 const char *name;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100434
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100435 if (gelf_getsym(lte->symtab, i, &sym) == NULL)
436 error(EXIT_FAILURE, 0,
437 "Couldn't get symbol from \"%s\"",
438 proc->filename);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100439
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100440 name = lte->strtab + sym.st_name;
441 addr = sym.st_value;
442 if (!addr)
443 continue;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100444
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100445 for (xptr = opt_x; xptr; xptr = xptr->next)
446 if (xptr->name && strcmp(xptr->name, name) == 0) {
447 /* FIXME: Should be able to use &library_symbols as above. But
448 when you do, none of the real library symbols cause breaks. */
449 add_library_symbol(elf_plt2addr
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200450 (lte, (void *) (long) addr),
451 name, lib_tail, 1, 0);
Paul Gilliam24e643a2006-03-13 18:43:13 +0100452 xptr->found = 1;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100453 break;
454 }
455 }
456 for (xptr = opt_x; xptr; xptr = xptr->next)
Paul Gilliam24e643a2006-03-13 18:43:13 +0100457 if ( ! xptr->found) {
458 char *badthing = "WARNING";
Paul Gilliambe320772006-04-24 22:06:23 +0200459#ifdef PLT_REINITALISATION_BP
460 if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) {
461 if (lte->ehdr.e_entry) {
462 add_library_symbol (
463 elf_plt2addr (lte, (void*)(long)
464 lte->ehdr.e_entry),
465 PLTs_initialized_by_here,
466 lib_tail, 1, 0);
467 fprintf (stderr, "WARNING: Using e_ent"
468 "ry from elf header (%p) for "
469 "address of \"%s\"\n", (void*)
470 (long) lte->ehdr.e_entry,
471 PLTs_initialized_by_here);
472 continue;
473 }
Paul Gilliam24e643a2006-03-13 18:43:13 +0100474 badthing = "ERROR";
475 exit_out = 1;
476 }
Paul Gilliambe320772006-04-24 22:06:23 +0200477#endif
Paul Gilliam24e643a2006-03-13 18:43:13 +0100478 fprintf (stderr,
Paul Gilliambe320772006-04-24 22:06:23 +0200479 "%s: Couldn't find symbol \"%s\" in file \"%s"
480 "\"\n", badthing, xptr->name, proc->filename);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100481 }
Paul Gilliam24e643a2006-03-13 18:43:13 +0100482 if (exit_out) {
483 exit (1);
484 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100485
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100486 for (i = 0; i < library_num + 1; ++i)
487 do_close_elf(&lte[i]);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100488
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100489 return library_symbols;
Juan Cespedes96935a91997-08-09 23:45:39 +0200490}