tizen 2.0
[external/ltrace.git] / elf.c
1 # include "config.h"
2
3 #include <endian.h>
4 #include <errno.h>
5 #include <error.h>
6 #include <fcntl.h>
7 #include <gelf.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #include "common.h"
14
15 static void do_init_elf(struct ltelf *lte, const char *filename);
16 static void do_close_elf(struct ltelf *lte);
17 static void add_library_symbol(GElf_Addr addr, const char *name,
18                                struct library_symbol **library_symbolspp,
19                                enum toplt type_of_plt, int is_weak);
20 static int in_load_libraries(const char *name, struct ltelf *lte);
21 static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr);
22
23 #ifdef PLT_REINITALISATION_BP
24 extern char *PLTs_initialized_by_here;
25 #endif
26
27 static void
28 do_init_elf(struct ltelf *lte, const char *filename) {
29         int i;
30         GElf_Addr relplt_addr = 0;
31         size_t relplt_size = 0;
32
33         debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
34         debug(1, "Reading ELF from %s...", filename);
35
36         memset(lte, 0, sizeof(*lte));
37         lte->fd = open(filename, O_RDONLY);
38         if (lte->fd == -1)
39                 error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
40
41 #ifdef HAVE_ELF_C_READ_MMAP
42         lte->elf = elf_begin(lte->fd, ELF_C_READ_MMAP, NULL);
43 #else
44         lte->elf = elf_begin(lte->fd, ELF_C_READ, NULL);
45 #endif
46
47         if (lte->elf == NULL || elf_kind(lte->elf) != ELF_K_ELF)
48                 error(EXIT_FAILURE, 0, "Can't open ELF file \"%s\"", filename);
49
50         if (gelf_getehdr(lte->elf, &lte->ehdr) == NULL)
51                 error(EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"",
52                       filename);
53
54         if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN)
55                 error(EXIT_FAILURE, 0,
56                       "\"%s\" is not an ELF executable nor shared library",
57                       filename);
58
59         if ((lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS
60              || lte->ehdr.e_machine != LT_ELF_MACHINE)
61 #ifdef LT_ELF_MACHINE2
62             && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS2
63                 || lte->ehdr.e_machine != LT_ELF_MACHINE2)
64 #endif
65 #ifdef LT_ELF_MACHINE3
66             && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS3
67                 || lte->ehdr.e_machine != LT_ELF_MACHINE3)
68 #endif
69             )
70                 error(EXIT_FAILURE, 0,
71                       "\"%s\" is ELF from incompatible architecture", filename);
72
73         for (i = 1; i < lte->ehdr.e_shnum; ++i) {
74                 Elf_Scn *scn;
75                 GElf_Shdr shdr;
76                 const char *name;
77
78                 scn = elf_getscn(lte->elf, i);
79                 if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
80                         error(EXIT_FAILURE, 0,
81                               "Couldn't get section header from \"%s\"",
82                               filename);
83
84                 name = elf_strptr(lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
85                 if (name == NULL)
86                         error(EXIT_FAILURE, 0,
87                               "Couldn't get section header from \"%s\"",
88                               filename);
89
90                 if (shdr.sh_type == SHT_SYMTAB) {
91                         Elf_Data *data;
92
93                         lte->symtab = elf_getdata(scn, NULL);
94                         lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
95                         if ((lte->symtab == NULL
96                              || elf_getdata(scn, lte->symtab) != NULL)
97                             && opt_x != NULL)
98                                 error(EXIT_FAILURE, 0,
99                                       "Couldn't get .symtab data from \"%s\"",
100                                       filename);
101
102                         scn = elf_getscn(lte->elf, shdr.sh_link);
103                         if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
104                                 error(EXIT_FAILURE, 0,
105                                       "Couldn't get section header from \"%s\"",
106                                       filename);
107
108                         data = elf_getdata(scn, NULL);
109                         if (data == NULL || elf_getdata(scn, data) != NULL
110                             || shdr.sh_size != data->d_size || data->d_off)
111                                 error(EXIT_FAILURE, 0,
112                                       "Couldn't get .strtab data from \"%s\"",
113                                       filename);
114
115                         lte->strtab = data->d_buf;
116                 } else if (shdr.sh_type == SHT_DYNSYM) {
117                         Elf_Data *data;
118
119                         lte->dynsym = elf_getdata(scn, NULL);
120                         lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
121                         if (lte->dynsym == NULL
122                             || elf_getdata(scn, lte->dynsym) != NULL)
123                                 error(EXIT_FAILURE, 0,
124                                       "Couldn't get .dynsym data from \"%s\"",
125                                       filename);
126
127                         scn = elf_getscn(lte->elf, shdr.sh_link);
128                         if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
129                                 error(EXIT_FAILURE, 0,
130                                       "Couldn't get section header from \"%s\"",
131                                       filename);
132
133                         data = elf_getdata(scn, NULL);
134                         if (data == NULL || elf_getdata(scn, data) != NULL
135                             || shdr.sh_size != data->d_size || data->d_off)
136                                 error(EXIT_FAILURE, 0,
137                                       "Couldn't get .dynstr data from \"%s\"",
138                                       filename);
139
140                         lte->dynstr = data->d_buf;
141                 } else if (shdr.sh_type == SHT_DYNAMIC) {
142                         Elf_Data *data;
143                         size_t j;
144
145                         data = elf_getdata(scn, NULL);
146                         if (data == NULL || elf_getdata(scn, data) != NULL)
147                                 error(EXIT_FAILURE, 0,
148                                       "Couldn't get .dynamic data from \"%s\"",
149                                       filename);
150
151                         for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
152                                 GElf_Dyn dyn;
153
154                                 if (gelf_getdyn(data, j, &dyn) == NULL)
155                                         error(EXIT_FAILURE, 0,
156                                               "Couldn't get .dynamic data from \"%s\"",
157                                               filename);
158 #ifdef __mips__
159 /**
160   MIPS ABI Supplement:
161
162   DT_PLTGOT This member holds the address of the .got section.
163
164   DT_MIPS_SYMTABNO This member holds the number of entries in the
165   .dynsym section.
166
167   DT_MIPS_LOCAL_GOTNO This member holds the number of local global
168   offset table entries.
169
170   DT_MIPS_GOTSYM This member holds the index of the first dyamic
171   symbol table entry that corresponds to an entry in the gobal offset
172   table.
173
174  */
175                                 if(dyn.d_tag==DT_PLTGOT){
176                                         lte->pltgot_addr=dyn.d_un.d_ptr;
177                                 }
178                                 if(dyn.d_tag==DT_MIPS_LOCAL_GOTNO){
179                                         lte->mips_local_gotno=dyn.d_un.d_val;
180                                 }
181                                 if(dyn.d_tag==DT_MIPS_GOTSYM){
182                                         lte->mips_gotsym=dyn.d_un.d_val;
183                                 }
184 #endif // __mips__
185                                 if (dyn.d_tag == DT_JMPREL)
186                                         relplt_addr = dyn.d_un.d_ptr;
187                                 else if (dyn.d_tag == DT_PLTRELSZ)
188                                         relplt_size = dyn.d_un.d_val;
189                         }
190                 } else if (shdr.sh_type == SHT_HASH) {
191                         Elf_Data *data;
192                         size_t j;
193
194                         lte->hash_type = SHT_HASH;
195
196                         data = elf_getdata(scn, NULL);
197                         if (data == NULL || elf_getdata(scn, data) != NULL
198                             || data->d_off || data->d_size != shdr.sh_size)
199                                 error(EXIT_FAILURE, 0,
200                                       "Couldn't get .hash data from \"%s\"",
201                                       filename);
202
203                         if (shdr.sh_entsize == 4) {
204                                 /* Standard conforming ELF.  */
205                                 if (data->d_type != ELF_T_WORD)
206                                         error(EXIT_FAILURE, 0,
207                                               "Couldn't get .hash data from \"%s\"",
208                                               filename);
209                                 lte->hash = (Elf32_Word *) data->d_buf;
210                         } else if (shdr.sh_entsize == 8) {
211                                 /* Alpha or s390x.  */
212                                 Elf32_Word *dst, *src;
213                                 size_t hash_count = data->d_size / 8;
214
215                                 lte->hash = (Elf32_Word *)
216                                     malloc(hash_count * sizeof(Elf32_Word));
217                                 if (lte->hash == NULL)
218                                         error(EXIT_FAILURE, 0,
219                                               "Couldn't convert .hash section from \"%s\"",
220                                               filename);
221                                 lte->lte_flags |= LTE_HASH_MALLOCED;
222                                 dst = lte->hash;
223                                 src = (Elf32_Word *) data->d_buf;
224                                 if ((data->d_type == ELF_T_WORD
225                                      && __BYTE_ORDER == __BIG_ENDIAN)
226                                     || (data->d_type == ELF_T_XWORD
227                                         && lte->ehdr.e_ident[EI_DATA] ==
228                                         ELFDATA2MSB))
229                                         ++src;
230                                 for (j = 0; j < hash_count; ++j, src += 2)
231                                         *dst++ = *src;
232                         } else
233                                 error(EXIT_FAILURE, 0,
234                                       "Unknown .hash sh_entsize in \"%s\"",
235                                       filename);
236                 } else if (shdr.sh_type == SHT_GNU_HASH
237                            && lte->hash == NULL) {
238                         Elf_Data *data;
239
240                         lte->hash_type = SHT_GNU_HASH;
241
242                         if (shdr.sh_entsize != 0
243                             && shdr.sh_entsize != 4) {
244                                 error(EXIT_FAILURE, 0,
245                                       ".gnu.hash sh_entsize in \"%s\" should be 4, but is %llu",
246                                       filename, shdr.sh_entsize);
247                         }
248
249                         data = elf_getdata(scn, NULL);
250                         if (data == NULL || elf_getdata(scn, data) != NULL
251                             || data->d_off || data->d_size != shdr.sh_size)
252                                 error(EXIT_FAILURE, 0,
253                                       "Couldn't get .gnu.hash data from \"%s\"",
254                                       filename);
255
256                         lte->hash = (Elf32_Word *) data->d_buf;
257                 } else if (shdr.sh_type == SHT_PROGBITS
258                            || shdr.sh_type == SHT_NOBITS) {
259                         if (strcmp(name, ".plt") == 0) {
260                                 lte->plt_addr = shdr.sh_addr;
261                                 lte->plt_size = shdr.sh_size;
262                                 if (shdr.sh_flags & SHF_EXECINSTR) {
263                                         lte->lte_flags |= LTE_PLT_EXECUTABLE;
264                                 }
265                         }
266 #ifdef ARCH_SUPPORTS_OPD
267                         else if (strcmp(name, ".opd") == 0) {
268                                 lte->opd_addr = (GElf_Addr *) (long) shdr.sh_addr;
269                                 lte->opd_size = shdr.sh_size;
270                                 lte->opd = elf_rawdata(scn, NULL);
271                         }
272 #endif
273                 }
274         }
275
276         if (lte->dynsym == NULL || lte->dynstr == NULL)
277                 error(EXIT_FAILURE, 0,
278                       "Couldn't find .dynsym or .dynstr in \"%s\"", filename);
279
280         if (!relplt_addr || !lte->plt_addr) {
281                 debug(1, "%s has no PLT relocations", filename);
282                 lte->relplt = NULL;
283                 lte->relplt_count = 0;
284         } else {
285                 for (i = 1; i < lte->ehdr.e_shnum; ++i) {
286                         Elf_Scn *scn;
287                         GElf_Shdr shdr;
288
289                         scn = elf_getscn(lte->elf, i);
290                         if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
291                                 error(EXIT_FAILURE, 0,
292                                       "Couldn't get section header from \"%s\"",
293                                       filename);
294                         if (shdr.sh_addr == relplt_addr
295                             && shdr.sh_size == relplt_size) {
296                                 lte->relplt = elf_getdata(scn, NULL);
297                                 lte->relplt_count =
298                                     shdr.sh_size / shdr.sh_entsize;
299                                 if (lte->relplt == NULL
300                                     || elf_getdata(scn, lte->relplt) != NULL)
301                                         error(EXIT_FAILURE, 0,
302                                               "Couldn't get .rel*.plt data from \"%s\"",
303                                               filename);
304                                 break;
305                         }
306                 }
307
308                 if (i == lte->ehdr.e_shnum)
309                         error(EXIT_FAILURE, 0,
310                               "Couldn't find .rel*.plt section in \"%s\"",
311                               filename);
312
313                 debug(1, "%s %zd PLT relocations", filename, lte->relplt_count);
314         }
315 }
316
317 static void
318 do_close_elf(struct ltelf *lte) {
319         debug(DEBUG_FUNCTION, "do_close_elf()");
320         if (lte->lte_flags & LTE_HASH_MALLOCED)
321                 free((char *)lte->hash);
322         elf_end(lte->elf);
323         close(lte->fd);
324 }
325
326 static void
327 add_library_symbol(GElf_Addr addr, const char *name,
328                    struct library_symbol **library_symbolspp,
329                    enum toplt type_of_plt, int is_weak) {
330         struct library_symbol *s;
331
332         debug(DEBUG_FUNCTION, "add_library_symbol()");
333
334         s = malloc(sizeof(struct library_symbol) + strlen(name) + 1);
335         if (s == NULL)
336                 error(EXIT_FAILURE, errno, "add_library_symbol failed");
337
338         s->needs_init = 1;
339         s->is_weak = is_weak;
340         s->plt_type = type_of_plt;
341         s->next = *library_symbolspp;
342         s->enter_addr = (void *)(uintptr_t) addr;
343         s->name = (char *)(s + 1);
344         strcpy(s->name, name);
345         *library_symbolspp = s;
346
347         debug(2, "addr: %p, symbol: \"%s\"", (void *)(uintptr_t) addr, name);
348 }
349
350 /* stolen from elfutils-0.123 */
351 static unsigned long
352 private_elf_gnu_hash(const char *name) {
353         unsigned long h = 5381;
354         const unsigned char *string = (const unsigned char *)name;
355         unsigned char c;
356         for (c = *string; c; c = *++string)
357                 h = h * 33 + c;
358         return h & 0xffffffff;
359 }
360
361 static int
362 in_load_libraries(const char *name, struct ltelf *lte) {
363         size_t i;
364         unsigned long hash;
365         unsigned long gnu_hash;
366
367         if (!library_num)
368                 return 1;
369
370         hash = elf_hash((const unsigned char *)name);
371         gnu_hash = private_elf_gnu_hash(name);
372         for (i = 1; i <= library_num; ++i) {
373                 if (lte[i].hash == NULL)
374                         continue;
375
376                 if (lte[i].hash_type == SHT_GNU_HASH) {
377                         Elf32_Word * hashbase = lte[i].hash;
378                         Elf32_Word nbuckets = *hashbase++;
379                         Elf32_Word symbias = *hashbase++;
380                         Elf32_Word bitmask_nwords = *hashbase++;
381                         Elf32_Word * buckets;
382                         Elf32_Word * chain_zero;
383                         Elf32_Word bucket;
384
385                         // +1 for skipped `shift'
386                         hashbase += lte[i].ehdr.e_ident[EI_CLASS] * bitmask_nwords + 1;
387                         buckets = hashbase;
388                         hashbase += nbuckets;
389                         chain_zero = hashbase - symbias;
390                         bucket = buckets[gnu_hash % nbuckets];
391
392                         if (bucket != 0) {
393                                 const Elf32_Word *hasharr = &chain_zero[bucket];
394                                 do
395                                         if ((*hasharr & ~1u) == (gnu_hash & ~1u)) {
396                                                 int symidx = hasharr - chain_zero;
397                                                 GElf_Sym sym;
398
399                                                 if (gelf_getsym(lte[i].dynsym, symidx, &sym) == NULL)
400                                                         error(EXIT_FAILURE, 0,
401                                                               "Couldn't get symbol from .dynsym");
402
403                                                 if (sym.st_value != 0
404                                                     && sym.st_shndx != SHN_UNDEF
405                                                     && strcmp(name, lte[i].dynstr + sym.st_name) == 0)
406                                                         return 1;
407                                         }
408                                 while ((*hasharr++ & 1u) == 0);
409                         }
410                 } else {
411                         Elf32_Word nbuckets, symndx;
412                         Elf32_Word *buckets, *chain;
413                         nbuckets = lte[i].hash[0];
414                         buckets = &lte[i].hash[2];
415                         chain = &lte[i].hash[2 + nbuckets];
416
417                         for (symndx = buckets[hash % nbuckets];
418                              symndx != STN_UNDEF; symndx = chain[symndx]) {
419                                 GElf_Sym sym;
420
421                                 if (gelf_getsym(lte[i].dynsym, symndx, &sym) == NULL)
422                                         error(EXIT_FAILURE, 0,
423                                               "Couldn't get symbol from .dynsym");
424
425                                 if (sym.st_value != 0
426                                     && sym.st_shndx != SHN_UNDEF
427                                     && strcmp(name, lte[i].dynstr + sym.st_name) == 0)
428                                         return 1;
429                         }
430                 }
431         }
432         return 0;
433 }
434
435 static GElf_Addr
436 opd2addr(struct ltelf *lte, GElf_Addr addr) {
437 #ifdef ARCH_SUPPORTS_OPD
438         unsigned long base, offset;
439
440         if (!lte->opd)
441                 return addr;
442
443         base = (unsigned long)lte->opd->d_buf;
444         offset = (unsigned long)addr - (unsigned long)lte->opd_addr;
445         if (offset > lte->opd_size)
446                 error(EXIT_FAILURE, 0, "static plt not in .opd");
447
448         return *(GElf_Addr*)(base + offset);
449 #else //!ARCH_SUPPORTS_OPD
450         return addr;
451 #endif
452 }
453
454 struct library_symbol *
455 read_elf(Process *proc) {
456         struct library_symbol *library_symbols = NULL;
457         struct ltelf lte[MAX_LIBRARIES + 1];
458         size_t i;
459         struct opt_x_t *xptr;
460         struct library_symbol **lib_tail = NULL;
461         int exit_out = 0;
462
463         debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename);
464
465         elf_version(EV_CURRENT);
466
467         do_init_elf(lte, proc->filename);
468         proc->e_machine = lte->ehdr.e_machine;
469         for (i = 0; i < library_num; ++i)
470                 do_init_elf(&lte[i + 1], library[i]);
471 #ifdef __mips__
472         // MIPS doesn't use the PLT and the GOT entries get changed
473         // on startup.
474         proc->need_to_reinitialize_breakpoints = 1;
475         for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){
476                 GElf_Sym sym;
477                 const char *name;
478                 GElf_Addr addr = arch_plt_sym_val(lte, i, 0);
479                 if (gelf_getsym(lte->dynsym, i, &sym) == NULL){
480                         error(EXIT_FAILURE, 0,
481                                         "Couldn't get relocation from \"%s\"",
482                                         proc->filename);
483                 }
484                 name=lte->dynstr+sym.st_name;
485                 if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){
486                         debug(2,"sym %s not a function",name);
487                         continue;
488                 }
489                 add_library_symbol(addr, name, &library_symbols, 0,
490                                 ELF64_ST_BIND(sym.st_info) != 0);
491                 if (!lib_tail)
492                         lib_tail = &(library_symbols->next);
493         }
494 #else
495         for (i = 0; i < lte->relplt_count; ++i) {
496                 GElf_Rel rel;
497                 GElf_Rela rela;
498                 GElf_Sym sym;
499                 GElf_Addr addr;
500                 void *ret;
501                 const char *name;
502
503                 if (lte->relplt->d_type == ELF_T_REL) {
504                         ret = gelf_getrel(lte->relplt, i, &rel);
505                         rela.r_offset = rel.r_offset;
506                         rela.r_info = rel.r_info;
507                         rela.r_addend = 0;
508                 } else
509                         ret = gelf_getrela(lte->relplt, i, &rela);
510
511                 if (ret == NULL
512                     || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
513                     || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
514                                    &sym) == NULL)
515                         error(EXIT_FAILURE, 0,
516                               "Couldn't get relocation from \"%s\"",
517                               proc->filename);
518
519 #ifdef PLT_REINITALISATION_BP
520                 if (!sym.st_value && PLTs_initialized_by_here)
521                         proc->need_to_reinitialize_breakpoints = 1;
522 #endif
523
524                 name = lte->dynstr + sym.st_name;
525                 if (in_load_libraries(name, lte)) {
526                         addr = arch_plt_sym_val(lte, i, &rela);
527                         add_library_symbol(addr, name, &library_symbols,
528                                            (PLTS_ARE_EXECUTABLE(lte)
529                                            ?  LS_TOPLT_EXEC : LS_TOPLT_POINT),
530                                            ELF64_ST_BIND(sym.st_info) == STB_WEAK);
531                         if (!lib_tail)
532                                 lib_tail = &(library_symbols->next);
533                 }
534         }
535 #endif // !__mips__
536 #ifdef PLT_REINITALISATION_BP
537         struct opt_x_t *main_cheat;
538
539         if (proc->need_to_reinitialize_breakpoints) {
540                 /* Add "PLTs_initialized_by_here" to opt_x list, if not
541                    already there. */
542                 main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
543                 if (main_cheat == NULL)
544                         error(EXIT_FAILURE, 0, "Couldn't allocate memory");
545                 main_cheat->next = opt_x;
546                 main_cheat->found = 0;
547                 main_cheat->name = PLTs_initialized_by_here;
548
549                 for (xptr = opt_x; xptr; xptr = xptr->next)
550                         if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
551                             && main_cheat) {
552                                 free(main_cheat);
553                                 main_cheat = NULL;
554                                 break;
555                         }
556                 if (main_cheat)
557                         opt_x = main_cheat;
558         }
559 #endif
560
561         for (i = 0; i < lte->symtab_count; ++i) {
562                 GElf_Sym sym;
563                 GElf_Addr addr;
564                 const char *name;
565
566                 if (gelf_getsym(lte->symtab, i, &sym) == NULL)
567                         error(EXIT_FAILURE, 0,
568                               "Couldn't get symbol from \"%s\"",
569                               proc->filename);
570
571                 name = lte->strtab + sym.st_name;
572                 addr = sym.st_value;
573                 if (!addr)
574                         continue;
575
576                 for (xptr = opt_x; xptr; xptr = xptr->next)
577                         if (xptr->name && strcmp(xptr->name, name) == 0) {
578                                 /* FIXME: Should be able to use &library_symbols as above.  But
579                                    when you do, none of the real library symbols cause breaks. */
580                                 add_library_symbol(opd2addr(lte, addr),
581                                                    name, lib_tail, LS_TOPLT_NONE, 0);
582                                 xptr->found = 1;
583                                 break;
584                         }
585         }
586         for (xptr = opt_x; xptr; xptr = xptr->next)
587                 if ( ! xptr->found) {
588                         char *badthing = "WARNING";
589 #ifdef PLT_REINITALISATION_BP
590                         if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) {
591                                 if (lte->ehdr.e_entry) {
592                                         add_library_symbol (
593                                                 opd2addr (lte, lte->ehdr.e_entry),
594                                                 PLTs_initialized_by_here,
595                                                 lib_tail, 1, 0);
596                                         fprintf (stderr, "WARNING: Using e_ent"
597                                                  "ry from elf header (%p) for "
598                                                  "address of \"%s\"\n", (void*)
599                                                  (long) lte->ehdr.e_entry,
600                                                  PLTs_initialized_by_here);
601                                         continue;
602                                 }
603                                 badthing = "ERROR";
604                                 exit_out = 1;
605                         }
606 #endif
607                         fprintf (stderr,
608                                  "%s: Couldn't find symbol \"%s\" in file \"%s"
609                                  "\"\n", badthing, xptr->name, proc->filename);
610                 }
611         if (exit_out) {
612                 exit (1);
613         }
614
615         for (i = 0; i < library_num + 1; ++i)
616                 do_close_elf(&lte[i]);
617
618         return library_symbols;
619 }