blob: 1a33ec302c9062e57d503f39d020132fc0fe19ee [file] [log] [blame]
Joe Damatof0bd98b2010-11-08 15:47:42 -08001#include "config.h"
Juan Cespedesd44c6b81998-09-25 14:48:42 +02002
Juan Cespedesd914a202004-11-10 00:15:33 +01003#include <endian.h>
Juan Cespedes96935a91997-08-09 23:45:39 +02004#include <errno.h>
Juan Cespedesd914a202004-11-10 00:15:33 +01005#include <error.h>
Juan Cespedes96935a91997-08-09 23:45:39 +02006#include <fcntl.h>
Juan Cespedesd914a202004-11-10 00:15:33 +01007#include <gelf.h>
Zachary T Welchbfb26c72010-12-06 23:21:00 -08008#include <inttypes.h>
Juan Cespedesd914a202004-11-10 00:15:33 +01009#include <stdint.h>
10#include <stdlib.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020011#include <string.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +010012#include <unistd.h>
Petr Machatafe1c1712010-10-27 16:57:34 +020013#include <assert.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020014
Juan Cespedesf7281232009-06-25 16:11:21 +020015#include "common.h"
Juan Cespedes96935a91997-08-09 23:45:39 +020016
Joe Damato7a2bdf82010-11-08 15:47:41 -080017void do_init_elf(struct ltelf *lte, const char *filename);
18void do_close_elf(struct ltelf *lte);
19void add_library_symbol(GElf_Addr addr, const char *name,
20 struct library_symbol **library_symbolspp,
21 enum toplt type_of_plt, int is_weak);
22int in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym);
Ian Wienand4bfcedd2006-08-07 04:03:15 +020023static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr);
Juan Cespedes1cd999a2001-07-03 00:46:04 +020024
Joe Damato7a2bdf82010-11-08 15:47:41 -080025struct library_symbol *library_symbols = NULL;
Joe Damatof0bd98b2010-11-08 15:47:42 -080026struct ltelf main_lte;
27
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
Petr Machatafe1c1712010-10-27 16:57:34 +020032#ifndef DT_PPC_GOT
33# define DT_PPC_GOT (DT_LOPROC + 0)
34#endif
35
36#define PPC_PLT_STUB_SIZE 16
37
38static Elf_Data *loaddata(Elf_Scn *scn, GElf_Shdr *shdr)
39{
40 Elf_Data *data = elf_getdata(scn, NULL);
41 if (data == NULL || elf_getdata(scn, data) != NULL
42 || data->d_off || data->d_size != shdr->sh_size)
43 return NULL;
44 return data;
45}
46
47static int inside(GElf_Addr addr, GElf_Shdr *shdr)
48{
49 return addr >= shdr->sh_addr
50 && addr < shdr->sh_addr + shdr->sh_size;
51}
52
53static int maybe_pick_section(GElf_Addr addr,
54 Elf_Scn *in_sec, GElf_Shdr *in_shdr,
55 Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr)
56{
57 if (inside (addr, in_shdr)) {
58 *tgt_sec = in_sec;
59 *tgt_shdr = *in_shdr;
60 return 1;
61 }
62 return 0;
63}
64
65static int get_section_covering(struct ltelf *lte, GElf_Addr addr,
66 Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr)
67{
68 int i;
69 for (i = 1; i < lte->ehdr.e_shnum; ++i) {
70 Elf_Scn *scn;
71 GElf_Shdr shdr;
72
73 scn = elf_getscn(lte->elf, i);
74 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL) {
75 debug(1, "Couldn't read section or header.");
76 return 0;
77 }
78
79 if (maybe_pick_section(addr, scn, &shdr, tgt_sec, tgt_shdr))
80 return 1;
81 }
82
83 return 0;
84}
85
86static GElf_Addr read32be(Elf_Data *data, size_t offset)
87{
88 if (data->d_size < offset + 4) {
89 debug(1, "Not enough data to read 32bit value at offset %zd.",
90 offset);
91 return 0;
92 }
93
94 unsigned char const *buf = data->d_buf + offset;
95 return ((Elf32_Word)buf[0] << 24)
96 | ((Elf32_Word)buf[1] << 16)
97 | ((Elf32_Word)buf[2] << 8)
98 | ((Elf32_Word)buf[3]);
99}
100
101static GElf_Addr get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot,
102 Elf_Data *plt_data)
103{
104 Elf_Scn *ppcgot_sec = NULL;
105 GElf_Shdr ppcgot_shdr;
106 if (ppcgot != 0
107 && !get_section_covering(lte, ppcgot, &ppcgot_sec, &ppcgot_shdr))
108 // xxx should be the log out
109 fprintf(stderr,
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800110 "DT_PPC_GOT=%#" PRIx64 ", but no such section found.\n",
Petr Machatafe1c1712010-10-27 16:57:34 +0200111 ppcgot);
112
113 if (ppcgot_sec != NULL) {
114 Elf_Data *data = loaddata(ppcgot_sec, &ppcgot_shdr);
115 if (data == NULL
116 || data->d_size < 8 )
117 debug(1, "Couldn't read GOT data.");
118 else {
119 // where PPCGOT begins in .got
120 size_t offset = ppcgot - ppcgot_shdr.sh_addr;
121 GElf_Addr glink_vma = read32be(data, offset + 4);
122 if (glink_vma != 0) {
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800123 debug(1, "PPC GOT glink_vma address: %#" PRIx64,
Petr Machatafe1c1712010-10-27 16:57:34 +0200124 glink_vma);
125 return glink_vma;
126 }
127 }
128 }
129
130 if (plt_data != NULL) {
131 GElf_Addr glink_vma = read32be(plt_data, 0);
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800132 debug(1, ".plt glink_vma address: %#" PRIx64, glink_vma);
Petr Machatafe1c1712010-10-27 16:57:34 +0200133 return glink_vma;
134 }
135
136 return 0;
137}
138
Joe Damato7a2bdf82010-11-08 15:47:41 -0800139void
Juan Cespedesf1350522008-12-16 18:19:58 +0100140do_init_elf(struct ltelf *lte, const char *filename) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100141 int i;
142 GElf_Addr relplt_addr = 0;
143 size_t relplt_size = 0;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200144
Juan Cespedescd8976d2009-05-14 13:47:58 +0200145 debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100146 debug(1, "Reading ELF from %s...", filename);
Juan Cespedes1afec691997-08-23 21:31:46 +0200147
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100148 lte->fd = open(filename, O_RDONLY);
149 if (lte->fd == -1)
150 error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
Juan Cespedes96935a91997-08-09 23:45:39 +0200151
Juan Cespedesd914a202004-11-10 00:15:33 +0100152#ifdef HAVE_ELF_C_READ_MMAP
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100153 lte->elf = elf_begin(lte->fd, ELF_C_READ_MMAP, NULL);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200154#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100155 lte->elf = elf_begin(lte->fd, ELF_C_READ, NULL);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200156#endif
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200157
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100158 if (lte->elf == NULL || elf_kind(lte->elf) != ELF_K_ELF)
159 error(EXIT_FAILURE, 0, "Can't open ELF file \"%s\"", filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200160
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100161 if (gelf_getehdr(lte->elf, &lte->ehdr) == NULL)
162 error(EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"",
163 filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200164
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100165 if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN)
166 error(EXIT_FAILURE, 0,
167 "\"%s\" is not an ELF executable nor shared library",
168 filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200169
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100170 if ((lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS
171 || lte->ehdr.e_machine != LT_ELF_MACHINE)
Juan Cespedesd914a202004-11-10 00:15:33 +0100172#ifdef LT_ELF_MACHINE2
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100173 && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS2
174 || lte->ehdr.e_machine != LT_ELF_MACHINE2)
Juan Cespedesd914a202004-11-10 00:15:33 +0100175#endif
176#ifdef LT_ELF_MACHINE3
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100177 && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS3
178 || lte->ehdr.e_machine != LT_ELF_MACHINE3)
Juan Cespedesd914a202004-11-10 00:15:33 +0100179#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100180 )
181 error(EXIT_FAILURE, 0,
182 "\"%s\" is ELF from incompatible architecture", filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100183
Petr Machatafe1c1712010-10-27 16:57:34 +0200184 Elf_Data *plt_data = NULL;
185 GElf_Addr ppcgot = 0;
186
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100187 for (i = 1; i < lte->ehdr.e_shnum; ++i) {
188 Elf_Scn *scn;
189 GElf_Shdr shdr;
190 const char *name;
Juan Cespedesd914a202004-11-10 00:15:33 +0100191
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100192 scn = elf_getscn(lte->elf, i);
193 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
194 error(EXIT_FAILURE, 0,
195 "Couldn't get section header from \"%s\"",
196 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100197
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100198 name = elf_strptr(lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
199 if (name == NULL)
200 error(EXIT_FAILURE, 0,
201 "Couldn't get section header from \"%s\"",
202 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100203
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100204 if (shdr.sh_type == SHT_SYMTAB) {
205 Elf_Data *data;
Juan Cespedesd914a202004-11-10 00:15:33 +0100206
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100207 lte->symtab = elf_getdata(scn, NULL);
208 lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
209 if ((lte->symtab == NULL
210 || elf_getdata(scn, lte->symtab) != NULL)
211 && opt_x != NULL)
212 error(EXIT_FAILURE, 0,
213 "Couldn't get .symtab data from \"%s\"",
214 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100215
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100216 scn = elf_getscn(lte->elf, shdr.sh_link);
217 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
218 error(EXIT_FAILURE, 0,
219 "Couldn't get section header from \"%s\"",
220 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100221
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100222 data = elf_getdata(scn, NULL);
223 if (data == NULL || elf_getdata(scn, data) != NULL
224 || shdr.sh_size != data->d_size || data->d_off)
225 error(EXIT_FAILURE, 0,
226 "Couldn't get .strtab data from \"%s\"",
227 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100228
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100229 lte->strtab = data->d_buf;
230 } else if (shdr.sh_type == SHT_DYNSYM) {
231 Elf_Data *data;
Juan Cespedesd914a202004-11-10 00:15:33 +0100232
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100233 lte->dynsym = elf_getdata(scn, NULL);
234 lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
235 if (lte->dynsym == NULL
236 || elf_getdata(scn, lte->dynsym) != NULL)
237 error(EXIT_FAILURE, 0,
238 "Couldn't get .dynsym data from \"%s\"",
239 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100240
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100241 scn = elf_getscn(lte->elf, shdr.sh_link);
242 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
243 error(EXIT_FAILURE, 0,
244 "Couldn't get section header from \"%s\"",
245 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100246
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100247 data = elf_getdata(scn, NULL);
248 if (data == NULL || elf_getdata(scn, data) != NULL
249 || shdr.sh_size != data->d_size || data->d_off)
250 error(EXIT_FAILURE, 0,
251 "Couldn't get .dynstr data from \"%s\"",
252 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100253
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100254 lte->dynstr = data->d_buf;
255 } else if (shdr.sh_type == SHT_DYNAMIC) {
256 Elf_Data *data;
257 size_t j;
Juan Cespedesd914a202004-11-10 00:15:33 +0100258
Joe Damato87f4f582010-11-08 15:47:36 -0800259 lte->dyn_addr = shdr.sh_addr;
260 lte->dyn_sz = shdr.sh_size;
261
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100262 data = elf_getdata(scn, NULL);
263 if (data == NULL || elf_getdata(scn, data) != NULL)
264 error(EXIT_FAILURE, 0,
265 "Couldn't get .dynamic data from \"%s\"",
266 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100267
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100268 for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
269 GElf_Dyn dyn;
Juan Cespedesd914a202004-11-10 00:15:33 +0100270
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100271 if (gelf_getdyn(data, j, &dyn) == NULL)
272 error(EXIT_FAILURE, 0,
273 "Couldn't get .dynamic data from \"%s\"",
274 filename);
Eric Vaitl1228a912006-12-28 16:16:56 +0100275#ifdef __mips__
276/**
277 MIPS ABI Supplement:
Ian Wienand9a2ad352006-02-20 22:44:45 +0100278
Juan Cespedesf1350522008-12-16 18:19:58 +0100279 DT_PLTGOT This member holds the address of the .got section.
Eric Vaitl1228a912006-12-28 16:16:56 +0100280
281 DT_MIPS_SYMTABNO This member holds the number of entries in the
282 .dynsym section.
283
284 DT_MIPS_LOCAL_GOTNO This member holds the number of local global
285 offset table entries.
286
287 DT_MIPS_GOTSYM This member holds the index of the first dyamic
288 symbol table entry that corresponds to an entry in the gobal offset
289 table.
290
291 */
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200292 if(dyn.d_tag==DT_PLTGOT){
Juan Cespedesf1350522008-12-16 18:19:58 +0100293 lte->pltgot_addr=dyn.d_un.d_ptr;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200294 }
295 if(dyn.d_tag==DT_MIPS_LOCAL_GOTNO){
296 lte->mips_local_gotno=dyn.d_un.d_val;
297 }
298 if(dyn.d_tag==DT_MIPS_GOTSYM){
299 lte->mips_gotsym=dyn.d_un.d_val;
300 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100301#endif // __mips__
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100302 if (dyn.d_tag == DT_JMPREL)
303 relplt_addr = dyn.d_un.d_ptr;
304 else if (dyn.d_tag == DT_PLTRELSZ)
305 relplt_size = dyn.d_un.d_val;
Petr Machatafe1c1712010-10-27 16:57:34 +0200306 else if (dyn.d_tag == DT_PPC_GOT) {
307 ppcgot = dyn.d_un.d_val;
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800308 debug(1, "ppcgot %#" PRIx64, ppcgot);
Petr Machatafe1c1712010-10-27 16:57:34 +0200309 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100310 }
311 } else if (shdr.sh_type == SHT_HASH) {
312 Elf_Data *data;
313 size_t j;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100314
Petr Machata35fe5182006-07-18 12:58:12 +0200315 lte->hash_type = SHT_HASH;
316
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100317 data = elf_getdata(scn, NULL);
318 if (data == NULL || elf_getdata(scn, data) != NULL
319 || data->d_off || data->d_size != shdr.sh_size)
320 error(EXIT_FAILURE, 0,
321 "Couldn't get .hash data from \"%s\"",
322 filename);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100323
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100324 if (shdr.sh_entsize == 4) {
325 /* Standard conforming ELF. */
326 if (data->d_type != ELF_T_WORD)
327 error(EXIT_FAILURE, 0,
328 "Couldn't get .hash data from \"%s\"",
329 filename);
330 lte->hash = (Elf32_Word *) data->d_buf;
331 } else if (shdr.sh_entsize == 8) {
332 /* Alpha or s390x. */
333 Elf32_Word *dst, *src;
334 size_t hash_count = data->d_size / 8;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100335
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100336 lte->hash = (Elf32_Word *)
337 malloc(hash_count * sizeof(Elf32_Word));
338 if (lte->hash == NULL)
339 error(EXIT_FAILURE, 0,
340 "Couldn't convert .hash section from \"%s\"",
341 filename);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200342 lte->lte_flags |= LTE_HASH_MALLOCED;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100343 dst = lte->hash;
344 src = (Elf32_Word *) data->d_buf;
345 if ((data->d_type == ELF_T_WORD
346 && __BYTE_ORDER == __BIG_ENDIAN)
347 || (data->d_type == ELF_T_XWORD
348 && lte->ehdr.e_ident[EI_DATA] ==
349 ELFDATA2MSB))
350 ++src;
351 for (j = 0; j < hash_count; ++j, src += 2)
352 *dst++ = *src;
353 } else
354 error(EXIT_FAILURE, 0,
355 "Unknown .hash sh_entsize in \"%s\"",
356 filename);
Petr Machata35fe5182006-07-18 12:58:12 +0200357 } else if (shdr.sh_type == SHT_GNU_HASH
358 && lte->hash == NULL) {
359 Elf_Data *data;
Petr Machata35fe5182006-07-18 12:58:12 +0200360
361 lte->hash_type = SHT_GNU_HASH;
362
363 if (shdr.sh_entsize != 0
364 && shdr.sh_entsize != 4) {
365 error(EXIT_FAILURE, 0,
Zachary T Welch3ba522f2010-12-14 15:12:47 -0800366 ".gnu.hash sh_entsize in \"%s\" "
367 "should be 4, but is %#" PRIx64,
368 filename, shdr.sh_entsize);
Petr Machata35fe5182006-07-18 12:58:12 +0200369 }
370
Petr Machatafe1c1712010-10-27 16:57:34 +0200371 data = loaddata(scn, &shdr);
372 if (data == NULL)
Petr Machata35fe5182006-07-18 12:58:12 +0200373 error(EXIT_FAILURE, 0,
374 "Couldn't get .gnu.hash data from \"%s\"",
375 filename);
376
377 lte->hash = (Elf32_Word *) data->d_buf;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100378 } else if (shdr.sh_type == SHT_PROGBITS
379 || shdr.sh_type == SHT_NOBITS) {
380 if (strcmp(name, ".plt") == 0) {
381 lte->plt_addr = shdr.sh_addr;
382 lte->plt_size = shdr.sh_size;
Paul Gilliam76c61f12006-06-14 06:55:21 +0200383 if (shdr.sh_flags & SHF_EXECINSTR) {
384 lte->lte_flags |= LTE_PLT_EXECUTABLE;
385 }
Petr Machatafe1c1712010-10-27 16:57:34 +0200386 if (lte->ehdr.e_machine == EM_PPC) {
387 plt_data = loaddata(scn, &shdr);
388 if (plt_data == NULL)
389 fprintf(stderr,
390 "Can't load .plt data\n");
391 }
Petr Machatab3f8fef2006-11-30 14:45:07 +0100392 }
393#ifdef ARCH_SUPPORTS_OPD
394 else if (strcmp(name, ".opd") == 0) {
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200395 lte->opd_addr = (GElf_Addr *) (long) shdr.sh_addr;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100396 lte->opd_size = shdr.sh_size;
397 lte->opd = elf_rawdata(scn, NULL);
398 }
Petr Machatab3f8fef2006-11-30 14:45:07 +0100399#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100400 }
Juan Cespedesd914a202004-11-10 00:15:33 +0100401 }
402
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100403 if (lte->dynsym == NULL || lte->dynstr == NULL)
404 error(EXIT_FAILURE, 0,
405 "Couldn't find .dynsym or .dynstr in \"%s\"", filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100406
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100407 if (!relplt_addr || !lte->plt_addr) {
408 debug(1, "%s has no PLT relocations", filename);
409 lte->relplt = NULL;
410 lte->relplt_count = 0;
Petr Machatafe1c1712010-10-27 16:57:34 +0200411 } else if (relplt_size == 0) {
412 debug(1, "%s has unknown PLT size", filename);
413 lte->relplt = NULL;
414 lte->relplt_count = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100415 } else {
Petr Machatafe1c1712010-10-27 16:57:34 +0200416 if (lte->ehdr.e_machine == EM_PPC) {
417 GElf_Addr glink_vma
418 = get_glink_vma(lte, ppcgot, plt_data);
419
420 assert (relplt_size % 12 == 0);
421 size_t count = relplt_size / 12; // size of RELA entry
422 lte->plt_stub_vma = glink_vma
423 - (GElf_Addr)count * PPC_PLT_STUB_SIZE;
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800424 debug(1, "stub_vma is %#" PRIx64, lte->plt_stub_vma);
Petr Machatafe1c1712010-10-27 16:57:34 +0200425 }
426
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100427 for (i = 1; i < lte->ehdr.e_shnum; ++i) {
428 Elf_Scn *scn;
429 GElf_Shdr shdr;
430
431 scn = elf_getscn(lte->elf, i);
432 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
433 error(EXIT_FAILURE, 0,
434 "Couldn't get section header from \"%s\"",
435 filename);
436 if (shdr.sh_addr == relplt_addr
437 && shdr.sh_size == relplt_size) {
438 lte->relplt = elf_getdata(scn, NULL);
439 lte->relplt_count =
440 shdr.sh_size / shdr.sh_entsize;
441 if (lte->relplt == NULL
442 || elf_getdata(scn, lte->relplt) != NULL)
443 error(EXIT_FAILURE, 0,
444 "Couldn't get .rel*.plt data from \"%s\"",
445 filename);
446 break;
447 }
448 }
449
450 if (i == lte->ehdr.e_shnum)
451 error(EXIT_FAILURE, 0,
452 "Couldn't find .rel*.plt section in \"%s\"",
453 filename);
454
455 debug(1, "%s %zd PLT relocations", filename, lte->relplt_count);
456 }
457}
458
Joe Damato7a2bdf82010-11-08 15:47:41 -0800459void
Juan Cespedesf1350522008-12-16 18:19:58 +0100460do_close_elf(struct ltelf *lte) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200461 debug(DEBUG_FUNCTION, "do_close_elf()");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200462 if (lte->lte_flags & LTE_HASH_MALLOCED)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100463 free((char *)lte->hash);
464 elf_end(lte->elf);
465 close(lte->fd);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200466}
467
Joe Damato7a2bdf82010-11-08 15:47:41 -0800468void
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100469add_library_symbol(GElf_Addr addr, const char *name,
470 struct library_symbol **library_symbolspp,
Juan Cespedesf1350522008-12-16 18:19:58 +0100471 enum toplt type_of_plt, int is_weak) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100472 struct library_symbol *s;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200473
474 debug(DEBUG_FUNCTION, "add_library_symbol()");
475
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100476 s = malloc(sizeof(struct library_symbol) + strlen(name) + 1);
477 if (s == NULL)
478 error(EXIT_FAILURE, errno, "add_library_symbol failed");
479
480 s->needs_init = 1;
481 s->is_weak = is_weak;
Paul Gilliam76c61f12006-06-14 06:55:21 +0200482 s->plt_type = type_of_plt;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100483 s->next = *library_symbolspp;
484 s->enter_addr = (void *)(uintptr_t) addr;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100485 s->name = (char *)(s + 1);
486 strcpy(s->name, name);
487 *library_symbolspp = s;
488
489 debug(2, "addr: %p, symbol: \"%s\"", (void *)(uintptr_t) addr, name);
Juan Cespedesd914a202004-11-10 00:15:33 +0100490}
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200491
Olaf Hering03c087b2006-09-25 02:31:27 +0200492/* stolen from elfutils-0.123 */
Juan Cespedesf1350522008-12-16 18:19:58 +0100493static unsigned long
494private_elf_gnu_hash(const char *name) {
Olaf Hering03c087b2006-09-25 02:31:27 +0200495 unsigned long h = 5381;
496 const unsigned char *string = (const unsigned char *)name;
497 unsigned char c;
498 for (c = *string; c; c = *++string)
499 h = h * 33 + c;
500 return h & 0xffffffff;
501}
502
Juan Cespedesf1350522008-12-16 18:19:58 +0100503static int
Joe Damato3268c5a2010-11-08 15:47:38 -0800504symbol_matches(struct ltelf *lte, size_t lte_i, GElf_Sym *sym,
505 size_t symidx, const char *name)
506{
507 GElf_Sym tmp_sym;
508 GElf_Sym *tmp;
509
510 tmp = (sym) ? (sym) : (&tmp_sym);
511
512 if (gelf_getsym(lte[lte_i].dynsym, symidx, tmp) == NULL)
513 error(EXIT_FAILURE, 0, "Couldn't get symbol from .dynsym");
514 else {
515 tmp->st_value += lte[lte_i].base_addr;
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800516 debug(2, "symbol found: %s, %zd, %#" PRIx64,
Joe Damato3268c5a2010-11-08 15:47:38 -0800517 name, lte_i, tmp->st_value);
518 }
519 return tmp->st_value != 0
520 && tmp->st_shndx != SHN_UNDEF
521 && strcmp(name, lte[lte_i].dynstr + tmp->st_name) == 0;
522}
523
Joe Damato7a2bdf82010-11-08 15:47:41 -0800524int
Joe Damato3268c5a2010-11-08 15:47:38 -0800525in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100526 size_t i;
527 unsigned long hash;
Petr Machata35fe5182006-07-18 12:58:12 +0200528 unsigned long gnu_hash;
Juan Cespedesd914a202004-11-10 00:15:33 +0100529
Joe Damato3268c5a2010-11-08 15:47:38 -0800530 if (!count)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100531 return 1;
Juan Cespedesd914a202004-11-10 00:15:33 +0100532
Zachary T Welch0a43b322010-12-08 18:55:10 -0800533#ifdef ELF_HASH_TAKES_SIGNED_CHAR
534 hash = elf_hash(name);
535#else
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200536 hash = elf_hash((const unsigned char *)name);
Zachary T Welch0a43b322010-12-08 18:55:10 -0800537#endif
Petr Machata07bc4d12006-11-30 14:47:40 +0100538 gnu_hash = private_elf_gnu_hash(name);
Joe Damato3268c5a2010-11-08 15:47:38 -0800539
540 for (i = 0; i < count; ++i) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100541 if (lte[i].hash == NULL)
542 continue;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200543
Petr Machata35fe5182006-07-18 12:58:12 +0200544 if (lte[i].hash_type == SHT_GNU_HASH) {
545 Elf32_Word * hashbase = lte[i].hash;
546 Elf32_Word nbuckets = *hashbase++;
547 Elf32_Word symbias = *hashbase++;
548 Elf32_Word bitmask_nwords = *hashbase++;
Petr Machata35fe5182006-07-18 12:58:12 +0200549 Elf32_Word * buckets;
550 Elf32_Word * chain_zero;
551 Elf32_Word bucket;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200552
Petr Machatab3f8fef2006-11-30 14:45:07 +0100553 // +1 for skipped `shift'
554 hashbase += lte[i].ehdr.e_ident[EI_CLASS] * bitmask_nwords + 1;
Petr Machata35fe5182006-07-18 12:58:12 +0200555 buckets = hashbase;
556 hashbase += nbuckets;
557 chain_zero = hashbase - symbias;
558 bucket = buckets[gnu_hash % nbuckets];
Juan Cespedesd914a202004-11-10 00:15:33 +0100559
Petr Machata35fe5182006-07-18 12:58:12 +0200560 if (bucket != 0) {
561 const Elf32_Word *hasharr = &chain_zero[bucket];
562 do
563 if ((*hasharr & ~1u) == (gnu_hash & ~1u)) {
564 int symidx = hasharr - chain_zero;
Joe Damato3268c5a2010-11-08 15:47:38 -0800565 if (symbol_matches(lte, i,
566 sym, symidx,
567 name))
Petr Machata35fe5182006-07-18 12:58:12 +0200568 return 1;
569 }
570 while ((*hasharr++ & 1u) == 0);
571 }
Olaf Hering03c087b2006-09-25 02:31:27 +0200572 } else {
Petr Machata35fe5182006-07-18 12:58:12 +0200573 Elf32_Word nbuckets, symndx;
574 Elf32_Word *buckets, *chain;
575 nbuckets = lte[i].hash[0];
576 buckets = &lte[i].hash[2];
577 chain = &lte[i].hash[2 + nbuckets];
578
579 for (symndx = buckets[hash % nbuckets];
Joe Damato3268c5a2010-11-08 15:47:38 -0800580 symndx != STN_UNDEF; symndx = chain[symndx])
581 if (symbol_matches(lte, i, sym, symndx, name))
Petr Machata35fe5182006-07-18 12:58:12 +0200582 return 1;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100583 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200584 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100585 return 0;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100586}
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200587
Juan Cespedesf1350522008-12-16 18:19:58 +0100588static GElf_Addr
589opd2addr(struct ltelf *lte, GElf_Addr addr) {
Petr Machatab3f8fef2006-11-30 14:45:07 +0100590#ifdef ARCH_SUPPORTS_OPD
Ian Wienand4bfcedd2006-08-07 04:03:15 +0200591 unsigned long base, offset;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200592
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100593 if (!lte->opd)
Ian Wienand4bfcedd2006-08-07 04:03:15 +0200594 return addr;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100595
Ian Wienand4bfcedd2006-08-07 04:03:15 +0200596 base = (unsigned long)lte->opd->d_buf;
597 offset = (unsigned long)addr - (unsigned long)lte->opd_addr;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100598 if (offset > lte->opd_size)
599 error(EXIT_FAILURE, 0, "static plt not in .opd");
600
Olaf Heringa841f652006-09-15 01:57:49 +0200601 return *(GElf_Addr*)(base + offset);
Petr Machatab3f8fef2006-11-30 14:45:07 +0100602#else //!ARCH_SUPPORTS_OPD
603 return addr;
604#endif
Ian Wienand9a2ad352006-02-20 22:44:45 +0100605}
606
Juan Cespedesf1350522008-12-16 18:19:58 +0100607struct library_symbol *
Juan Cespedesa8909f72009-04-28 20:02:41 +0200608read_elf(Process *proc) {
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200609 struct ltelf lte[MAX_LIBRARIES + 1];
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100610 size_t i;
Paul Gilliam24e643a2006-03-13 18:43:13 +0100611 struct opt_x_t *xptr;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100612 struct library_symbol **lib_tail = NULL;
Paul Gilliam24e643a2006-03-13 18:43:13 +0100613 int exit_out = 0;
Joe Damato3268c5a2010-11-08 15:47:38 -0800614 int count = 0;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100615
Juan Cespedescd8976d2009-05-14 13:47:58 +0200616 debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename);
617
Petr Machatadf8f1ac2011-05-20 10:13:14 +0200618 memset(lte, 0, sizeof(lte));
Joe Damato7a2bdf82010-11-08 15:47:41 -0800619 library_symbols = NULL;
620 library_num = 0;
Joe Damatof0bd98b2010-11-08 15:47:42 -0800621 proc->libdl_hooked = 0;
622
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100623 elf_version(EV_CURRENT);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100624
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100625 do_init_elf(lte, proc->filename);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800626
627 memcpy(&main_lte, lte, sizeof(struct ltelf));
628
629 if (opt_p && opt_p->pid > 0) {
630 linkmap_init(proc, lte);
631 proc->libdl_hooked = 1;
632 }
633
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100634 proc->e_machine = lte->ehdr.e_machine;
Joe Damatof0bd98b2010-11-08 15:47:42 -0800635
636 for (i = 0; i < library_num; ++i) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100637 do_init_elf(&lte[i + 1], library[i]);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800638 }
Joe Damatofa2aefc2010-10-30 19:56:50 -0700639
640 if (!options.no_plt) {
Eric Vaitl1228a912006-12-28 16:16:56 +0100641#ifdef __mips__
Joe Damatofa2aefc2010-10-30 19:56:50 -0700642 // MIPS doesn't use the PLT and the GOT entries get changed
643 // on startup.
644 proc->need_to_reinitialize_breakpoints = 1;
645 for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){
646 GElf_Sym sym;
647 const char *name;
648 GElf_Addr addr = arch_plt_sym_val(lte, i, 0);
649 if (gelf_getsym(lte->dynsym, i, &sym) == NULL){
650 error(EXIT_FAILURE, 0,
651 "Couldn't get relocation from \"%s\"",
652 proc->filename);
653 }
654 name=lte->dynstr+sym.st_name;
Arnaud Patard95623b22010-01-08 08:40:02 -0500655 if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){
656 debug(2,"sym %s not a function",name);
657 continue;
658 }
659 add_library_symbol(addr, name, &library_symbols, 0,
660 ELF64_ST_BIND(sym.st_info) != 0);
661 if (!lib_tail)
662 lib_tail = &(library_symbols->next);
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200663 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100664#else
Joe Damatofa2aefc2010-10-30 19:56:50 -0700665 for (i = 0; i < lte->relplt_count; ++i) {
666 GElf_Rel rel;
667 GElf_Rela rela;
668 GElf_Sym sym;
669 GElf_Addr addr;
670 void *ret;
671 const char *name;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100672
Joe Damatofa2aefc2010-10-30 19:56:50 -0700673 if (lte->relplt->d_type == ELF_T_REL) {
674 ret = gelf_getrel(lte->relplt, i, &rel);
675 rela.r_offset = rel.r_offset;
676 rela.r_info = rel.r_info;
677 rela.r_addend = 0;
678 } else
679 ret = gelf_getrela(lte->relplt, i, &rela);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100680
Joe Damatofa2aefc2010-10-30 19:56:50 -0700681 if (ret == NULL
682 || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
683 || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
684 &sym) == NULL)
685 error(EXIT_FAILURE, 0,
686 "Couldn't get relocation from \"%s\"",
687 proc->filename);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100688
Paul Gilliambe320772006-04-24 22:06:23 +0200689#ifdef PLT_REINITALISATION_BP
Joe Damatofa2aefc2010-10-30 19:56:50 -0700690 if (!sym.st_value && PLTs_initialized_by_here)
691 proc->need_to_reinitialize_breakpoints = 1;
Paul Gilliambe320772006-04-24 22:06:23 +0200692#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100693
Joe Damato3268c5a2010-11-08 15:47:38 -0800694 name = lte->dynstr + sym.st_name;
695 count = library_num ? library_num+1 : 0;
Petr Machatafe1c1712010-10-27 16:57:34 +0200696
Joe Damato3268c5a2010-11-08 15:47:38 -0800697 if (in_load_libraries(name, lte, count, NULL)) {
698 enum toplt pltt;
699 if (sym.st_value == 0 && lte->plt_stub_vma != 0) {
700 pltt = LS_TOPLT_EXEC;
701 addr = lte->plt_stub_vma + PPC_PLT_STUB_SIZE * i;
702 }
703 else {
704 pltt = PLTS_ARE_EXECUTABLE(lte)
705 ? LS_TOPLT_EXEC : LS_TOPLT_POINT;
706 addr = arch_plt_sym_val(lte, i, &rela);
707 }
708
709 add_library_symbol(addr, name, &library_symbols, pltt,
710 ELF64_ST_BIND(sym.st_info) == STB_WEAK);
711 if (!lib_tail)
712 lib_tail = &(library_symbols->next);
Joe Damatofa2aefc2010-10-30 19:56:50 -0700713 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100714 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100715#endif // !__mips__
Paul Gilliambe320772006-04-24 22:06:23 +0200716#ifdef PLT_REINITALISATION_BP
Joe Damatofa2aefc2010-10-30 19:56:50 -0700717 struct opt_x_t *main_cheat;
Ian Wienand4bfcedd2006-08-07 04:03:15 +0200718
Joe Damatofa2aefc2010-10-30 19:56:50 -0700719 if (proc->need_to_reinitialize_breakpoints) {
720 /* Add "PLTs_initialized_by_here" to opt_x list, if not
721 already there. */
722 main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
723 if (main_cheat == NULL)
724 error(EXIT_FAILURE, 0, "Couldn't allocate memory");
725 main_cheat->next = opt_x;
726 main_cheat->found = 0;
727 main_cheat->name = PLTs_initialized_by_here;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100728
Joe Damatofa2aefc2010-10-30 19:56:50 -0700729 for (xptr = opt_x; xptr; xptr = xptr->next)
730 if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
731 && main_cheat) {
732 free(main_cheat);
733 main_cheat = NULL;
734 break;
735 }
736 if (main_cheat)
737 opt_x = main_cheat;
738 }
Paul Gilliambe320772006-04-24 22:06:23 +0200739#endif
Joe Damatofa2aefc2010-10-30 19:56:50 -0700740 } else {
741 lib_tail = &library_symbols;
742 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100743
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100744 for (i = 0; i < lte->symtab_count; ++i) {
745 GElf_Sym sym;
746 GElf_Addr addr;
747 const char *name;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100748
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100749 if (gelf_getsym(lte->symtab, i, &sym) == NULL)
750 error(EXIT_FAILURE, 0,
751 "Couldn't get symbol from \"%s\"",
752 proc->filename);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100753
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100754 name = lte->strtab + sym.st_name;
755 addr = sym.st_value;
756 if (!addr)
757 continue;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100758
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100759 for (xptr = opt_x; xptr; xptr = xptr->next)
760 if (xptr->name && strcmp(xptr->name, name) == 0) {
761 /* FIXME: Should be able to use &library_symbols as above. But
762 when you do, none of the real library symbols cause breaks. */
Ian Wienand4bfcedd2006-08-07 04:03:15 +0200763 add_library_symbol(opd2addr(lte, addr),
Paul Gilliam76c61f12006-06-14 06:55:21 +0200764 name, lib_tail, LS_TOPLT_NONE, 0);
Paul Gilliam24e643a2006-03-13 18:43:13 +0100765 xptr->found = 1;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100766 break;
767 }
768 }
Joe Damatoe2a8f572010-11-08 15:47:40 -0800769
Zachary T Welchba6aca22010-12-08 18:55:09 -0800770 unsigned found_count = 0;
Joe Damatoe2a8f572010-11-08 15:47:40 -0800771
772 for (xptr = opt_x; xptr; xptr = xptr->next) {
773 if (xptr->found)
774 continue;
775
776 GElf_Sym sym;
777 GElf_Addr addr;
778 if (in_load_libraries(xptr->name, lte, library_num+1, &sym)) {
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800779 debug(2, "found symbol %s @ %#" PRIx64 ", adding it.",
780 xptr->name, sym.st_value);
Joe Damatoe2a8f572010-11-08 15:47:40 -0800781 addr = sym.st_value;
782 if (ELF32_ST_TYPE (sym.st_info) == STT_FUNC) {
783 add_library_symbol(addr, xptr->name, lib_tail, LS_TOPLT_NONE, 0);
784 xptr->found = 1;
785 found_count++;
786 }
787 }
788 if (found_count == opt_x_cnt){
789 debug(2, "done, found everything: %d\n", found_count);
790 break;
791 }
792 }
793
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100794 for (xptr = opt_x; xptr; xptr = xptr->next)
Paul Gilliam24e643a2006-03-13 18:43:13 +0100795 if ( ! xptr->found) {
796 char *badthing = "WARNING";
Paul Gilliambe320772006-04-24 22:06:23 +0200797#ifdef PLT_REINITALISATION_BP
798 if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) {
799 if (lte->ehdr.e_entry) {
800 add_library_symbol (
Ian Wienand4bfcedd2006-08-07 04:03:15 +0200801 opd2addr (lte, lte->ehdr.e_entry),
Paul Gilliambe320772006-04-24 22:06:23 +0200802 PLTs_initialized_by_here,
803 lib_tail, 1, 0);
804 fprintf (stderr, "WARNING: Using e_ent"
805 "ry from elf header (%p) for "
806 "address of \"%s\"\n", (void*)
807 (long) lte->ehdr.e_entry,
808 PLTs_initialized_by_here);
809 continue;
810 }
Paul Gilliam24e643a2006-03-13 18:43:13 +0100811 badthing = "ERROR";
812 exit_out = 1;
813 }
Paul Gilliambe320772006-04-24 22:06:23 +0200814#endif
Paul Gilliam24e643a2006-03-13 18:43:13 +0100815 fprintf (stderr,
Joe Damatof0bd98b2010-11-08 15:47:42 -0800816 "%s: Couldn't find symbol \"%s\" in file \"%s\" assuming it will be loaded by libdl!"
817 "\n", badthing, xptr->name, proc->filename);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100818 }
Paul Gilliam24e643a2006-03-13 18:43:13 +0100819 if (exit_out) {
820 exit (1);
821 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100822
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100823 for (i = 0; i < library_num + 1; ++i)
824 do_close_elf(&lte[i]);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100825
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100826 return library_symbols;
Juan Cespedes96935a91997-08-09 23:45:39 +0200827}