blob: c7ef400a224098252e5b2633ade9563fce4ce153 [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 Wienand9a2ad352006-02-20 22:44:45 +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
Ian Wienand9a2ad352006-02-20 22:44:45 +010028
29extern char * PLTs_initialized_by_here;
30
31static void
32do_init_elf (struct ltelf *lte, const char *filename)
Juan Cespedesd914a202004-11-10 00:15:33 +010033{
Ian Wienand9a2ad352006-02-20 22:44:45 +010034 int i;
35 GElf_Addr relplt_addr = 0;
36 size_t relplt_size = 0;
Juan Cespedes1cd999a2001-07-03 00:46:04 +020037
Ian Wienand9a2ad352006-02-20 22:44:45 +010038 debug (1, "Reading ELF from %s...", filename);
Juan Cespedes1afec691997-08-23 21:31:46 +020039
Ian Wienand9a2ad352006-02-20 22:44:45 +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 Wienand9a2ad352006-02-20 22:44:45 +010046 lte->elf = elf_begin (lte->fd, ELF_C_READ_MMAP, NULL);
Juan Cespedes5c3fe062004-06-14 18:08:37 +020047#else
Ian Wienand9a2ad352006-02-20 22:44:45 +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 Wienand9a2ad352006-02-20 22:44:45 +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 Wienand9a2ad352006-02-20 22:44:45 +010054 if (gelf_getehdr (lte->elf, &lte->ehdr) == NULL)
55 error (EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"", filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +020056
Ian Wienand9a2ad352006-02-20 22:44:45 +010057 if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN)
58 error (EXIT_FAILURE, 0, "\"%s\" is not an ELF executable nor shared library",
59 filename);
Juan Cespedes1cd999a2001-07-03 00:46:04 +020060
Ian Wienand9a2ad352006-02-20 22:44:45 +010061 if ((lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS
62 || lte->ehdr.e_machine != LT_ELF_MACHINE)
Juan Cespedesd914a202004-11-10 00:15:33 +010063#ifdef LT_ELF_MACHINE2
Ian Wienand9a2ad352006-02-20 22:44:45 +010064 && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS2
65 || lte->ehdr.e_machine != LT_ELF_MACHINE2)
Juan Cespedesd914a202004-11-10 00:15:33 +010066#endif
67#ifdef LT_ELF_MACHINE3
Ian Wienand9a2ad352006-02-20 22:44:45 +010068 && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS3
69 || lte->ehdr.e_machine != LT_ELF_MACHINE3)
Juan Cespedesd914a202004-11-10 00:15:33 +010070#endif
Ian Wienand9a2ad352006-02-20 22:44:45 +010071 )
72 error (EXIT_FAILURE, 0, "\"%s\" is ELF from incompatible architecture",
73 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +010074
Ian Wienand9a2ad352006-02-20 22:44:45 +010075 for (i = 1; i < lte->ehdr.e_shnum; ++i)
76 {
77 Elf_Scn *scn;
78 GElf_Shdr shdr;
79 const char *name;
Juan Cespedesd914a202004-11-10 00:15:33 +010080
Ian Wienand9a2ad352006-02-20 22:44:45 +010081 scn = elf_getscn (lte->elf, i);
82 if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
83 error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
84 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +010085
Ian Wienand9a2ad352006-02-20 22:44:45 +010086 name = elf_strptr (lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
87 if (name == NULL)
88 error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
89 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +010090
Ian Wienand9a2ad352006-02-20 22:44:45 +010091 if (shdr.sh_type == SHT_SYMTAB)
92 {
93 Elf_Data *data;
Juan Cespedesd914a202004-11-10 00:15:33 +010094
Ian Wienand9a2ad352006-02-20 22:44:45 +010095 lte->symtab = elf_getdata (scn,NULL);
96 lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
97 if ((lte->symtab == NULL || elf_getdata(scn, lte->symtab) != NULL)
98 && opt_x != NULL)
99 error (EXIT_FAILURE, 0, "Couldn't get .symtab data from \"%s\"",
100 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100101
Ian Wienand9a2ad352006-02-20 22:44:45 +0100102 scn = elf_getscn (lte->elf, shdr.sh_link);
103 if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
104 error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
105 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100106
Ian Wienand9a2ad352006-02-20 22:44:45 +0100107 data = elf_getdata (scn, NULL);
108 if (data == NULL || elf_getdata (scn, data) != NULL
109 || shdr.sh_size != data->d_size || data->d_off)
110 error (EXIT_FAILURE, 0, "Couldn't get .strtab data from \"%s\"",
111 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100112
Ian Wienand9a2ad352006-02-20 22:44:45 +0100113 lte->strtab = data->d_buf;
114 }
115 else if (shdr.sh_type == SHT_DYNSYM)
116 {
117 Elf_Data *data;
Juan Cespedesd914a202004-11-10 00:15:33 +0100118
Ian Wienand9a2ad352006-02-20 22:44:45 +0100119 lte->dynsym = elf_getdata (scn, NULL);
120 lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
121 if (lte->dynsym == NULL || elf_getdata (scn, lte->dynsym) != NULL)
122 error (EXIT_FAILURE, 0, "Couldn't get .dynsym data from \"%s\"",
123 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100124
Ian Wienand9a2ad352006-02-20 22:44:45 +0100125 scn = elf_getscn (lte->elf, shdr.sh_link);
126 if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
127 error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
128 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100129
Ian Wienand9a2ad352006-02-20 22:44:45 +0100130 data = elf_getdata (scn, NULL);
131 if (data == NULL || elf_getdata (scn, data) != NULL
132 || shdr.sh_size != data->d_size || data->d_off)
133 error (EXIT_FAILURE, 0, "Couldn't get .dynstr data from \"%s\"",
134 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100135
Ian Wienand9a2ad352006-02-20 22:44:45 +0100136 lte->dynstr = data->d_buf;
137 }
138 else if (shdr.sh_type == SHT_DYNAMIC)
139 {
140 Elf_Data *data;
141 size_t j;
Juan Cespedesd914a202004-11-10 00:15:33 +0100142
Ian Wienand9a2ad352006-02-20 22:44:45 +0100143 data = elf_getdata (scn, NULL);
144 if (data == NULL || elf_getdata (scn, data) != NULL)
145 error (EXIT_FAILURE, 0, "Couldn't get .dynamic data from \"%s\"",
146 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100147
Ian Wienand9a2ad352006-02-20 22:44:45 +0100148 for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j)
149 {
150 GElf_Dyn dyn;
Juan Cespedesd914a202004-11-10 00:15:33 +0100151
Ian Wienand9a2ad352006-02-20 22:44:45 +0100152 if (gelf_getdyn (data, j, &dyn) == NULL)
153 error (EXIT_FAILURE, 0, "Couldn't get .dynamic data from \"%s\"",
154 filename);
155
156 if (dyn.d_tag == DT_JMPREL)
157 relplt_addr = dyn.d_un.d_ptr;
158 else if (dyn.d_tag == DT_PLTRELSZ)
159 relplt_size = dyn.d_un.d_val;
160 }
161 }
162 else if (shdr.sh_type == SHT_HASH)
163 {
164 Elf_Data *data;
165 size_t j;
166
167 data = elf_getdata (scn, NULL);
168 if (data == NULL || elf_getdata (scn, data) != NULL
169 || data->d_off || data->d_size != shdr.sh_size)
170 error (EXIT_FAILURE, 0, "Couldn't get .hash data from \"%s\"",
171 filename);
172
173 if (shdr.sh_entsize == 4)
174 {
175 /* Standard conforming ELF. */
176 if (data->d_type != ELF_T_WORD)
177 error (EXIT_FAILURE, 0, "Couldn't get .hash data from \"%s\"",
178 filename);
179 lte->hash = (Elf32_Word *) data->d_buf;
180 }
181 else if (shdr.sh_entsize == 8)
182 {
183 /* Alpha or s390x. */
184 Elf32_Word *dst, *src;
185 size_t hash_count = data->d_size / 8;
186
187 lte->hash = (Elf32_Word *)
188 malloc (hash_count * sizeof (Elf32_Word));
189 if (lte->hash == NULL)
190 error (EXIT_FAILURE, 0, "Couldn't convert .hash section from \"%s\"",
191 filename);
192 lte->hash_malloced = 1;
193 dst = lte->hash;
194 src = (Elf32_Word *) data->d_buf;
195 if ((data->d_type == ELF_T_WORD && __BYTE_ORDER == __BIG_ENDIAN)
196 || (data->d_type == ELF_T_XWORD
197 && lte->ehdr.e_ident[EI_DATA] == ELFDATA2MSB))
198 ++src;
199 for (j = 0; j < hash_count; ++j, src += 2)
200 *dst++ = *src;
201 }
202 else
203 error (EXIT_FAILURE, 0, "Unknown .hash sh_entsize in \"%s\"",
204 filename);
205 }
206 else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS)
207 {
208 if (strcmp (name, ".plt") == 0)
209 {
210 lte->plt_addr = shdr.sh_addr;
211 lte->plt_size = shdr.sh_size;
212 }
213 else if (strcmp (name, ".opd") == 0)
214 {
215 lte->opd_addr = (GElf_Addr *)shdr.sh_addr;
216 lte->opd_size = shdr.sh_size;
217 lte->opd = elf_rawdata (scn, NULL);
218 }
219 }
220 }
221
222 if (lte->dynsym == NULL || lte->dynstr == NULL)
223 error (EXIT_FAILURE, 0, "Couldn't find .dynsym or .dynstr in \"%s\"",
224 filename);
225
226 if (!relplt_addr || !lte->plt_addr)
227 {
228 debug (1, "%s has no PLT relocations", filename);
229 lte->relplt = NULL;
230 lte->relplt_count = 0;
231 }
232 else
233 {
234 for (i = 1; i < lte->ehdr.e_shnum; ++i)
235 {
236 Elf_Scn *scn;
237 GElf_Shdr shdr;
238
239 scn = elf_getscn (lte->elf, i);
240 if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
241 error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
242 filename);
243 if (shdr.sh_addr == relplt_addr && shdr.sh_size == relplt_size)
244 {
245 lte->relplt = elf_getdata (scn, NULL);
246 lte->relplt_count = shdr.sh_size / shdr.sh_entsize;
247 if (lte->relplt == NULL
248 || elf_getdata (scn, lte->relplt) != NULL)
249 error (EXIT_FAILURE, 0, "Couldn't get .rel*.plt data from \"%s\"",
250 filename);
251 break;
252 }
Juan Cespedesd914a202004-11-10 00:15:33 +0100253 }
254
Ian Wienand9a2ad352006-02-20 22:44:45 +0100255 if (i == lte->ehdr.e_shnum)
256 error (EXIT_FAILURE, 0, "Couldn't find .rel*.plt section in \"%s\"",
257 filename);
Juan Cespedesd914a202004-11-10 00:15:33 +0100258
Ian Wienand9a2ad352006-02-20 22:44:45 +0100259 debug (1, "%s %zd PLT relocations", filename, lte->relplt_count);
260 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200261}
262
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100263static void
Ian Wienand9a2ad352006-02-20 22:44:45 +0100264do_close_elf (struct ltelf *lte)
Juan Cespedesd914a202004-11-10 00:15:33 +0100265{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100266 if (lte->hash_malloced)
267 free ((char *) lte->hash);
268 elf_end (lte->elf);
269 close (lte->fd);
Juan Cespedesd914a202004-11-10 00:15:33 +0100270}
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200271
Ian Wienand9a2ad352006-02-20 22:44:45 +0100272static void
273add_library_symbol (GElf_Addr addr, const char *name,
274 struct library_symbol **library_symbolspp,
275 int use_elf_plt2addr, int is_weak)
Juan Cespedesd914a202004-11-10 00:15:33 +0100276{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100277 struct library_symbol *s;
278 s = malloc (sizeof (struct library_symbol) + strlen (name) + 1);
279 if (s == NULL)
280 error (EXIT_FAILURE, errno, "add_library_symbol failed");
Juan Cespedesd914a202004-11-10 00:15:33 +0100281
Ian Wienand9a2ad352006-02-20 22:44:45 +0100282 s->needs_init = 1;
283 s->is_weak = is_weak;
284 s->static_plt2addr = use_elf_plt2addr;
285 s->next = *library_symbolspp;
286 s->enter_addr = (void *) (uintptr_t) addr;
287 s->brkpnt = NULL;
288 s->name = (char *) (s + 1);
289 strcpy (s->name, name);
290 *library_symbolspp = s;
Juan Cespedesd914a202004-11-10 00:15:33 +0100291
Ian Wienand9a2ad352006-02-20 22:44:45 +0100292 debug (2, "addr: %p, symbol: \"%s\"", (void *) (uintptr_t) addr, name);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200293}
294
Ian Wienand9a2ad352006-02-20 22:44:45 +0100295static int
296in_load_libraries (const char *name, struct ltelf *lte)
Juan Cespedesd914a202004-11-10 00:15:33 +0100297{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100298 size_t i;
299 unsigned long hash;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200300
Ian Wienand9a2ad352006-02-20 22:44:45 +0100301 if (!library_num)
302 return 1;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200303
Ian Wienand9a2ad352006-02-20 22:44:45 +0100304 hash = elf_hash (name);
305 for (i = 1; i <= library_num; ++i)
306 {
307 Elf32_Word nbuckets, symndx;
308 Elf32_Word *buckets, *chain;
Juan Cespedesd914a202004-11-10 00:15:33 +0100309
Ian Wienand9a2ad352006-02-20 22:44:45 +0100310 if (lte[i].hash == NULL)
311 continue;
Juan Cespedesd914a202004-11-10 00:15:33 +0100312
Ian Wienand9a2ad352006-02-20 22:44:45 +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;
318 symndx = chain[symndx])
319 {
320 GElf_Sym sym;
Juan Cespedesd914a202004-11-10 00:15:33 +0100321
Ian Wienand9a2ad352006-02-20 22:44:45 +0100322 if (gelf_getsym (lte[i].dynsym, symndx, &sym) == NULL)
323 error (EXIT_FAILURE, 0, "Couldn't get symbol from .dynsym");
Juan Cespedesd914a202004-11-10 00:15:33 +0100324
Ian Wienand9a2ad352006-02-20 22:44:45 +0100325 if (sym.st_value != 0
326 && sym.st_shndx != SHN_UNDEF
327 && strcmp (name, lte[i].dynstr + sym.st_name) == 0)
328 return 1;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200329 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100330 }
331 return 0;
332}
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200333
Ian Wienand9a2ad352006-02-20 22:44:45 +0100334static GElf_Addr
335elf_plt2addr (struct ltelf *lte, void *addr)
336{
337 long base;
338 long offset;
339 GElf_Addr ret_val;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200340
Ian Wienand9a2ad352006-02-20 22:44:45 +0100341 if (!lte->opd)
342 return (GElf_Addr)addr;
343
344 base = (long)lte->opd->d_buf;
345 offset = (long)addr - (long)lte->opd_addr;
346 if (offset > lte->opd_size)
347 error (EXIT_FAILURE, 0, "static plt not in .opd");
348
349 ret_val = (GElf_Addr) *(long*)(base + offset);
350 return ret_val;
351}
352
353struct library_symbol *
354read_elf (struct process * proc)
355{
356 struct library_symbol *library_symbols = NULL;
357 struct ltelf lte[MAX_LIBRARY + 1];
358 size_t i;
359 struct opt_e_t * xptr;
360 struct library_symbol **lib_tail = NULL;
361 struct opt_e_t *main_cheat;
362
363 elf_version (EV_CURRENT);
364
365 do_init_elf (lte, proc->filename);
366 proc->e_machine = lte->ehdr.e_machine;
367 for (i = 0; i < library_num; ++i)
368 do_init_elf (&lte[i + 1], library[i]);
369
370 for (i = 0; i < lte->relplt_count; ++i)
371 {
372 GElf_Rel rel;
373 GElf_Rela rela;
374 GElf_Sym sym;
375 GElf_Addr addr;
376 void *ret;
377 const char *name;
378
379 if (lte->relplt->d_type == ELF_T_REL)
380 {
381 ret = gelf_getrel (lte->relplt, i, &rel);
382 rela.r_offset = rel.r_offset;
383 rela.r_info = rel.r_info;
384 rela.r_addend = 0;
385 }
386 else
387 ret = gelf_getrela (lte->relplt, i, &rela);
388
389 if (ret == NULL
390 || ELF64_R_SYM (rela.r_info) >= lte->dynsym_count
391 || gelf_getsym (lte->dynsym, ELF64_R_SYM (rela.r_info), &sym) == NULL)
392 error (EXIT_FAILURE, 0, "Couldn't get relocation from \"%s\"",
393 proc->filename);
394
395 if ( ! sym.st_value && PLTs_initialized_by_here)
396 proc->need_to_reinitialize_breakpoints = 1;
397
398 name = lte->dynstr + sym.st_name;
399 if (in_load_libraries (name, lte))
400 {
401 addr = arch_plt_sym_val (lte, i, &rela);
402 add_library_symbol (addr, name, &library_symbols, 0,
403 ELF64_ST_BIND (sym.st_info) != 0);
404 if (!lib_tail)
405 lib_tail = &(library_symbols->next);
406 }
407 }
408
409 if (proc->need_to_reinitialize_breakpoints)
410 {
411 /* Add "PLTs_initialized_by_here" to opt_x list, if not already there. */
412 main_cheat = (struct opt_e_t *)malloc(sizeof(struct opt_e_t));
413 if (main_cheat == NULL)
414 error (EXIT_FAILURE, 0, "Couldn allocate memory");
415 main_cheat->next = opt_x;
416 main_cheat->name = PLTs_initialized_by_here;
417
418 for (xptr=opt_x; xptr; xptr=xptr->next)
419 if (strcmp(xptr->name, PLTs_initialized_by_here) == 0 && main_cheat)
420 {
421 free(main_cheat);
422 main_cheat = NULL;
423 break;
424 }
425 if (main_cheat)
426 opt_x = main_cheat;
427 }
428
429 for (i = 0; i < lte->symtab_count; ++i)
430 {
431 GElf_Sym sym;
432 GElf_Addr addr;
433 const char *name;
434
435 if (gelf_getsym (lte->symtab, i, &sym) == NULL)
436 error (EXIT_FAILURE, 0, "Couldn't get symbol from \"%s\"", proc->filename);
437
438 name = lte->strtab + sym.st_name;
439 addr = sym.st_value;
440 if ( ! addr)
441 continue;
442
443 for (xptr=opt_x; xptr; xptr=xptr->next)
444 if (xptr->name && strcmp (xptr->name, name) == 0)
445 {
446 /* FIXME: Should be able to use &library_symbols as above. But
447 when you do, none of the real library symbols cause breaks. */
448 add_library_symbol (elf_plt2addr(lte, (void *)addr), name,
449 lib_tail, 1, 0);
450 break;
451 }
452 }
453 for (xptr=opt_x; xptr; xptr=xptr->next)
454 if (xptr->name)
455 {
456 if (strcmp(xptr->name, E_ENTRY_NAME) == 0)
457 add_library_symbol (elf_plt2addr(lte, (void*)lte->ehdr.e_entry),
458 "_start", lib_tail, 1, 0);
459 else
460 fprintf (stderr, "Warning: Couldn't get symbol \"%s\" "
461 "from \"%s\" or it's a duplicate",
462 xptr->name, proc->filename);
463 }
464
465 for (i = 0; i < library_num + 1; ++i)
466 do_close_elf (&lte[i]);
467
468 return library_symbols;
Juan Cespedes96935a91997-08-09 23:45:39 +0200469}