ltrace-elf.c revision 7a2bdf8e5bf49d2fbb700981efd1d0a8728340ed
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#include <assert.h>
13
14#include "common.h"
15
16void do_init_elf(struct ltelf *lte, const char *filename);
17void do_close_elf(struct ltelf *lte);
18void add_library_symbol(GElf_Addr addr, const char *name,
19		struct library_symbol **library_symbolspp,
20		enum toplt type_of_plt, int is_weak);
21int in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym);
22static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr);
23
24struct library_symbol *library_symbols = NULL;
25#ifdef PLT_REINITALISATION_BP
26extern char *PLTs_initialized_by_here;
27#endif
28
29#ifndef DT_PPC_GOT
30# define DT_PPC_GOT		(DT_LOPROC + 0)
31#endif
32
33#define PPC_PLT_STUB_SIZE 16
34
35static Elf_Data *loaddata(Elf_Scn *scn, GElf_Shdr *shdr)
36{
37	Elf_Data *data = elf_getdata(scn, NULL);
38	if (data == NULL || elf_getdata(scn, data) != NULL
39	    || data->d_off || data->d_size != shdr->sh_size)
40		return NULL;
41	return data;
42}
43
44static int inside(GElf_Addr addr, GElf_Shdr *shdr)
45{
46	return addr >= shdr->sh_addr
47		&& addr < shdr->sh_addr + shdr->sh_size;
48}
49
50static int maybe_pick_section(GElf_Addr addr,
51			      Elf_Scn *in_sec, GElf_Shdr *in_shdr,
52			      Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr)
53{
54	if (inside (addr, in_shdr)) {
55		*tgt_sec = in_sec;
56		*tgt_shdr = *in_shdr;
57		return 1;
58	}
59	return 0;
60}
61
62static int get_section_covering(struct ltelf *lte, GElf_Addr addr,
63				Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr)
64{
65	int i;
66	for (i = 1; i < lte->ehdr.e_shnum; ++i) {
67		Elf_Scn *scn;
68		GElf_Shdr shdr;
69
70		scn = elf_getscn(lte->elf, i);
71		if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL) {
72			debug(1, "Couldn't read section or header.");
73			return 0;
74		}
75
76		if (maybe_pick_section(addr, scn, &shdr, tgt_sec, tgt_shdr))
77			return 1;
78	}
79
80	return 0;
81}
82
83static GElf_Addr read32be(Elf_Data *data, size_t offset)
84{
85	if (data->d_size < offset + 4) {
86		debug(1, "Not enough data to read 32bit value at offset %zd.",
87		      offset);
88		return 0;
89	}
90
91	unsigned char const *buf = data->d_buf + offset;
92	return ((Elf32_Word)buf[0] << 24)
93		| ((Elf32_Word)buf[1] << 16)
94		| ((Elf32_Word)buf[2] << 8)
95		| ((Elf32_Word)buf[3]);
96}
97
98static GElf_Addr get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot,
99			       Elf_Data *plt_data)
100{
101	Elf_Scn *ppcgot_sec = NULL;
102	GElf_Shdr ppcgot_shdr;
103	if (ppcgot != 0
104	    && !get_section_covering(lte, ppcgot, &ppcgot_sec, &ppcgot_shdr))
105		// xxx should be the log out
106		fprintf(stderr,
107			"DT_PPC_GOT=%#lx, but no such section found.\n",
108			ppcgot);
109
110	if (ppcgot_sec != NULL) {
111		Elf_Data *data = loaddata(ppcgot_sec, &ppcgot_shdr);
112		if (data == NULL
113		    || data->d_size < 8 )
114			debug(1, "Couldn't read GOT data.");
115		else {
116			// where PPCGOT begins in .got
117			size_t offset = ppcgot - ppcgot_shdr.sh_addr;
118			GElf_Addr glink_vma = read32be(data, offset + 4);
119			if (glink_vma != 0) {
120				debug(1, "PPC GOT glink_vma address: %#lx",
121				      glink_vma);
122				return glink_vma;
123			}
124		}
125	}
126
127	if (plt_data != NULL) {
128		GElf_Addr glink_vma = read32be(plt_data, 0);
129		debug(1, ".plt glink_vma address: %#lx", glink_vma);
130		return glink_vma;
131	}
132
133	return 0;
134}
135
136void
137do_init_elf(struct ltelf *lte, const char *filename) {
138	int i;
139	GElf_Addr relplt_addr = 0;
140	size_t relplt_size = 0;
141
142	debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
143	debug(1, "Reading ELF from %s...", filename);
144
145	memset(lte, 0, sizeof(*lte));
146	lte->fd = open(filename, O_RDONLY);
147	if (lte->fd == -1)
148		error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
149
150#ifdef HAVE_ELF_C_READ_MMAP
151	lte->elf = elf_begin(lte->fd, ELF_C_READ_MMAP, NULL);
152#else
153	lte->elf = elf_begin(lte->fd, ELF_C_READ, NULL);
154#endif
155
156	if (lte->elf == NULL || elf_kind(lte->elf) != ELF_K_ELF)
157		error(EXIT_FAILURE, 0, "Can't open ELF file \"%s\"", filename);
158
159	if (gelf_getehdr(lte->elf, &lte->ehdr) == NULL)
160		error(EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"",
161		      filename);
162
163	if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN)
164		error(EXIT_FAILURE, 0,
165		      "\"%s\" is not an ELF executable nor shared library",
166		      filename);
167
168	if ((lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS
169	     || lte->ehdr.e_machine != LT_ELF_MACHINE)
170#ifdef LT_ELF_MACHINE2
171	    && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS2
172		|| lte->ehdr.e_machine != LT_ELF_MACHINE2)
173#endif
174#ifdef LT_ELF_MACHINE3
175	    && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS3
176		|| lte->ehdr.e_machine != LT_ELF_MACHINE3)
177#endif
178	    )
179		error(EXIT_FAILURE, 0,
180		      "\"%s\" is ELF from incompatible architecture", filename);
181
182	Elf_Data *plt_data = NULL;
183	GElf_Addr ppcgot = 0;
184
185	for (i = 1; i < lte->ehdr.e_shnum; ++i) {
186		Elf_Scn *scn;
187		GElf_Shdr shdr;
188		const char *name;
189
190		scn = elf_getscn(lte->elf, i);
191		if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
192			error(EXIT_FAILURE, 0,
193			      "Couldn't get section header from \"%s\"",
194			      filename);
195
196		name = elf_strptr(lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
197		if (name == NULL)
198			error(EXIT_FAILURE, 0,
199			      "Couldn't get section header from \"%s\"",
200			      filename);
201
202		if (shdr.sh_type == SHT_SYMTAB) {
203			Elf_Data *data;
204
205			lte->symtab = elf_getdata(scn, NULL);
206			lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
207			if ((lte->symtab == NULL
208			     || elf_getdata(scn, lte->symtab) != NULL)
209			    && opt_x != NULL)
210				error(EXIT_FAILURE, 0,
211				      "Couldn't get .symtab data from \"%s\"",
212				      filename);
213
214			scn = elf_getscn(lte->elf, shdr.sh_link);
215			if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
216				error(EXIT_FAILURE, 0,
217				      "Couldn't get section header from \"%s\"",
218				      filename);
219
220			data = elf_getdata(scn, NULL);
221			if (data == NULL || elf_getdata(scn, data) != NULL
222			    || shdr.sh_size != data->d_size || data->d_off)
223				error(EXIT_FAILURE, 0,
224				      "Couldn't get .strtab data from \"%s\"",
225				      filename);
226
227			lte->strtab = data->d_buf;
228		} else if (shdr.sh_type == SHT_DYNSYM) {
229			Elf_Data *data;
230
231			lte->dynsym = elf_getdata(scn, NULL);
232			lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
233			if (lte->dynsym == NULL
234			    || elf_getdata(scn, lte->dynsym) != NULL)
235				error(EXIT_FAILURE, 0,
236				      "Couldn't get .dynsym data from \"%s\"",
237				      filename);
238
239			scn = elf_getscn(lte->elf, shdr.sh_link);
240			if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
241				error(EXIT_FAILURE, 0,
242				      "Couldn't get section header from \"%s\"",
243				      filename);
244
245			data = elf_getdata(scn, NULL);
246			if (data == NULL || elf_getdata(scn, data) != NULL
247			    || shdr.sh_size != data->d_size || data->d_off)
248				error(EXIT_FAILURE, 0,
249				      "Couldn't get .dynstr data from \"%s\"",
250				      filename);
251
252			lte->dynstr = data->d_buf;
253		} else if (shdr.sh_type == SHT_DYNAMIC) {
254			Elf_Data *data;
255			size_t j;
256
257			lte->dyn_addr = shdr.sh_addr;
258			lte->dyn_sz = shdr.sh_size;
259
260			data = elf_getdata(scn, NULL);
261			if (data == NULL || elf_getdata(scn, data) != NULL)
262				error(EXIT_FAILURE, 0,
263				      "Couldn't get .dynamic data from \"%s\"",
264				      filename);
265
266			for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
267				GElf_Dyn dyn;
268
269				if (gelf_getdyn(data, j, &dyn) == NULL)
270					error(EXIT_FAILURE, 0,
271					      "Couldn't get .dynamic data from \"%s\"",
272					      filename);
273#ifdef __mips__
274/**
275  MIPS ABI Supplement:
276
277  DT_PLTGOT This member holds the address of the .got section.
278
279  DT_MIPS_SYMTABNO This member holds the number of entries in the
280  .dynsym section.
281
282  DT_MIPS_LOCAL_GOTNO This member holds the number of local global
283  offset table entries.
284
285  DT_MIPS_GOTSYM This member holds the index of the first dyamic
286  symbol table entry that corresponds to an entry in the gobal offset
287  table.
288
289 */
290				if(dyn.d_tag==DT_PLTGOT){
291					lte->pltgot_addr=dyn.d_un.d_ptr;
292				}
293				if(dyn.d_tag==DT_MIPS_LOCAL_GOTNO){
294					lte->mips_local_gotno=dyn.d_un.d_val;
295				}
296				if(dyn.d_tag==DT_MIPS_GOTSYM){
297					lte->mips_gotsym=dyn.d_un.d_val;
298				}
299#endif // __mips__
300				if (dyn.d_tag == DT_JMPREL)
301					relplt_addr = dyn.d_un.d_ptr;
302				else if (dyn.d_tag == DT_PLTRELSZ)
303					relplt_size = dyn.d_un.d_val;
304				else if (dyn.d_tag == DT_PPC_GOT) {
305					ppcgot = dyn.d_un.d_val;
306					debug(1, "ppcgot %#lx", ppcgot);
307				}
308			}
309		} else if (shdr.sh_type == SHT_HASH) {
310			Elf_Data *data;
311			size_t j;
312
313			lte->hash_type = SHT_HASH;
314
315			data = elf_getdata(scn, NULL);
316			if (data == NULL || elf_getdata(scn, data) != NULL
317			    || data->d_off || data->d_size != shdr.sh_size)
318				error(EXIT_FAILURE, 0,
319				      "Couldn't get .hash data from \"%s\"",
320				      filename);
321
322			if (shdr.sh_entsize == 4) {
323				/* Standard conforming ELF.  */
324				if (data->d_type != ELF_T_WORD)
325					error(EXIT_FAILURE, 0,
326					      "Couldn't get .hash data from \"%s\"",
327					      filename);
328				lte->hash = (Elf32_Word *) data->d_buf;
329			} else if (shdr.sh_entsize == 8) {
330				/* Alpha or s390x.  */
331				Elf32_Word *dst, *src;
332				size_t hash_count = data->d_size / 8;
333
334				lte->hash = (Elf32_Word *)
335				    malloc(hash_count * sizeof(Elf32_Word));
336				if (lte->hash == NULL)
337					error(EXIT_FAILURE, 0,
338					      "Couldn't convert .hash section from \"%s\"",
339					      filename);
340				lte->lte_flags |= LTE_HASH_MALLOCED;
341				dst = lte->hash;
342				src = (Elf32_Word *) data->d_buf;
343				if ((data->d_type == ELF_T_WORD
344				     && __BYTE_ORDER == __BIG_ENDIAN)
345				    || (data->d_type == ELF_T_XWORD
346					&& lte->ehdr.e_ident[EI_DATA] ==
347					ELFDATA2MSB))
348					++src;
349				for (j = 0; j < hash_count; ++j, src += 2)
350					*dst++ = *src;
351			} else
352				error(EXIT_FAILURE, 0,
353				      "Unknown .hash sh_entsize in \"%s\"",
354				      filename);
355		} else if (shdr.sh_type == SHT_GNU_HASH
356			   && lte->hash == NULL) {
357			Elf_Data *data;
358
359			lte->hash_type = SHT_GNU_HASH;
360
361			if (shdr.sh_entsize != 0
362			    && shdr.sh_entsize != 4) {
363				error(EXIT_FAILURE, 0,
364				      ".gnu.hash sh_entsize in \"%s\" should be 4, but is %llu",
365				      filename, shdr.sh_entsize);
366			}
367
368			data = loaddata(scn, &shdr);
369			if (data == NULL)
370				error(EXIT_FAILURE, 0,
371				      "Couldn't get .gnu.hash data from \"%s\"",
372				      filename);
373
374			lte->hash = (Elf32_Word *) data->d_buf;
375		} else if (shdr.sh_type == SHT_PROGBITS
376			   || shdr.sh_type == SHT_NOBITS) {
377			if (strcmp(name, ".plt") == 0) {
378				lte->plt_addr = shdr.sh_addr;
379				lte->plt_size = shdr.sh_size;
380				if (shdr.sh_flags & SHF_EXECINSTR) {
381					lte->lte_flags |= LTE_PLT_EXECUTABLE;
382				}
383				if (lte->ehdr.e_machine == EM_PPC) {
384					plt_data = loaddata(scn, &shdr);
385					if (plt_data == NULL)
386						fprintf(stderr,
387							"Can't load .plt data\n");
388				}
389			}
390#ifdef ARCH_SUPPORTS_OPD
391			else if (strcmp(name, ".opd") == 0) {
392				lte->opd_addr = (GElf_Addr *) (long) shdr.sh_addr;
393				lte->opd_size = shdr.sh_size;
394				lte->opd = elf_rawdata(scn, NULL);
395			}
396#endif
397		}
398	}
399
400	if (lte->dynsym == NULL || lte->dynstr == NULL)
401		error(EXIT_FAILURE, 0,
402		      "Couldn't find .dynsym or .dynstr in \"%s\"", filename);
403
404	if (!relplt_addr || !lte->plt_addr) {
405		debug(1, "%s has no PLT relocations", filename);
406		lte->relplt = NULL;
407		lte->relplt_count = 0;
408	} else if (relplt_size == 0) {
409		debug(1, "%s has unknown PLT size", filename);
410		lte->relplt = NULL;
411		lte->relplt_count = 0;
412	} else {
413		if (lte->ehdr.e_machine == EM_PPC) {
414			GElf_Addr glink_vma
415				= get_glink_vma(lte, ppcgot, plt_data);
416
417			assert (relplt_size % 12 == 0);
418			size_t count = relplt_size / 12; // size of RELA entry
419			lte->plt_stub_vma = glink_vma
420				- (GElf_Addr)count * PPC_PLT_STUB_SIZE;
421			debug(1, "stub_vma is %#lx", lte->plt_stub_vma);
422		}
423
424		for (i = 1; i < lte->ehdr.e_shnum; ++i) {
425			Elf_Scn *scn;
426			GElf_Shdr shdr;
427
428			scn = elf_getscn(lte->elf, i);
429			if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
430				error(EXIT_FAILURE, 0,
431				      "Couldn't get section header from \"%s\"",
432				      filename);
433			if (shdr.sh_addr == relplt_addr
434			    && shdr.sh_size == relplt_size) {
435				lte->relplt = elf_getdata(scn, NULL);
436				lte->relplt_count =
437				    shdr.sh_size / shdr.sh_entsize;
438				if (lte->relplt == NULL
439				    || elf_getdata(scn, lte->relplt) != NULL)
440					error(EXIT_FAILURE, 0,
441					      "Couldn't get .rel*.plt data from \"%s\"",
442					      filename);
443				break;
444			}
445		}
446
447		if (i == lte->ehdr.e_shnum)
448			error(EXIT_FAILURE, 0,
449			      "Couldn't find .rel*.plt section in \"%s\"",
450			      filename);
451
452		debug(1, "%s %zd PLT relocations", filename, lte->relplt_count);
453	}
454}
455
456void
457do_close_elf(struct ltelf *lte) {
458	debug(DEBUG_FUNCTION, "do_close_elf()");
459	if (lte->lte_flags & LTE_HASH_MALLOCED)
460		free((char *)lte->hash);
461	elf_end(lte->elf);
462	close(lte->fd);
463}
464
465void
466add_library_symbol(GElf_Addr addr, const char *name,
467		   struct library_symbol **library_symbolspp,
468		   enum toplt type_of_plt, int is_weak) {
469	struct library_symbol *s;
470
471	debug(DEBUG_FUNCTION, "add_library_symbol()");
472
473	s = malloc(sizeof(struct library_symbol) + strlen(name) + 1);
474	if (s == NULL)
475		error(EXIT_FAILURE, errno, "add_library_symbol failed");
476
477	s->needs_init = 1;
478	s->is_weak = is_weak;
479	s->plt_type = type_of_plt;
480	s->next = *library_symbolspp;
481	s->enter_addr = (void *)(uintptr_t) addr;
482	s->name = (char *)(s + 1);
483	strcpy(s->name, name);
484	*library_symbolspp = s;
485
486	debug(2, "addr: %p, symbol: \"%s\"", (void *)(uintptr_t) addr, name);
487}
488
489/* stolen from elfutils-0.123 */
490static unsigned long
491private_elf_gnu_hash(const char *name) {
492	unsigned long h = 5381;
493	const unsigned char *string = (const unsigned char *)name;
494	unsigned char c;
495	for (c = *string; c; c = *++string)
496		h = h * 33 + c;
497	return h & 0xffffffff;
498}
499
500static int
501symbol_matches(struct ltelf *lte, size_t lte_i, GElf_Sym *sym,
502	       size_t symidx, const char *name)
503{
504	GElf_Sym tmp_sym;
505	GElf_Sym *tmp;
506
507	tmp = (sym) ? (sym) : (&tmp_sym);
508
509	if (gelf_getsym(lte[lte_i].dynsym, symidx, tmp) == NULL)
510		error(EXIT_FAILURE, 0, "Couldn't get symbol from .dynsym");
511	else {
512		tmp->st_value += lte[lte_i].base_addr;
513		debug(2, "symbol found: %s, %zd, %lx",
514		      name, lte_i, tmp->st_value);
515	}
516	return tmp->st_value != 0
517		&& tmp->st_shndx != SHN_UNDEF
518		&& strcmp(name, lte[lte_i].dynstr + tmp->st_name) == 0;
519}
520
521int
522in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym) {
523	size_t i;
524	unsigned long hash;
525	unsigned long gnu_hash;
526
527	if (!count)
528		return 1;
529
530	hash = elf_hash((const unsigned char *)name);
531	gnu_hash = private_elf_gnu_hash(name);
532
533	for (i = 0; i < count; ++i) {
534		if (lte[i].hash == NULL)
535			continue;
536
537		if (lte[i].hash_type == SHT_GNU_HASH) {
538			Elf32_Word * hashbase = lte[i].hash;
539			Elf32_Word nbuckets = *hashbase++;
540			Elf32_Word symbias = *hashbase++;
541			Elf32_Word bitmask_nwords = *hashbase++;
542			Elf32_Word * buckets;
543			Elf32_Word * chain_zero;
544			Elf32_Word bucket;
545
546			// +1 for skipped `shift'
547			hashbase += lte[i].ehdr.e_ident[EI_CLASS] * bitmask_nwords + 1;
548			buckets = hashbase;
549			hashbase += nbuckets;
550			chain_zero = hashbase - symbias;
551			bucket = buckets[gnu_hash % nbuckets];
552
553			if (bucket != 0) {
554				const Elf32_Word *hasharr = &chain_zero[bucket];
555				do
556					if ((*hasharr & ~1u) == (gnu_hash & ~1u)) {
557						int symidx = hasharr - chain_zero;
558						if (symbol_matches(lte, i,
559								   sym, symidx,
560								   name))
561							return 1;
562					}
563				while ((*hasharr++ & 1u) == 0);
564			}
565		} else {
566			Elf32_Word nbuckets, symndx;
567			Elf32_Word *buckets, *chain;
568			nbuckets = lte[i].hash[0];
569			buckets = &lte[i].hash[2];
570			chain = &lte[i].hash[2 + nbuckets];
571
572			for (symndx = buckets[hash % nbuckets];
573			     symndx != STN_UNDEF; symndx = chain[symndx])
574				if (symbol_matches(lte, i, sym, symndx, name))
575					return 1;
576		}
577	}
578	return 0;
579}
580
581static GElf_Addr
582opd2addr(struct ltelf *lte, GElf_Addr addr) {
583#ifdef ARCH_SUPPORTS_OPD
584	unsigned long base, offset;
585
586	if (!lte->opd)
587		return addr;
588
589	base = (unsigned long)lte->opd->d_buf;
590	offset = (unsigned long)addr - (unsigned long)lte->opd_addr;
591	if (offset > lte->opd_size)
592		error(EXIT_FAILURE, 0, "static plt not in .opd");
593
594	return *(GElf_Addr*)(base + offset);
595#else //!ARCH_SUPPORTS_OPD
596	return addr;
597#endif
598}
599
600struct library_symbol *
601read_elf(Process *proc) {
602	struct ltelf lte[MAX_LIBRARIES + 1];
603	size_t i;
604	struct opt_x_t *xptr;
605	struct library_symbol **lib_tail = NULL;
606	int exit_out = 0;
607	int count = 0;
608
609	debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename);
610
611	library_symbols = NULL;
612	library_num = 0;
613	elf_version(EV_CURRENT);
614
615	do_init_elf(lte, proc->filename);
616	proc->e_machine = lte->ehdr.e_machine;
617	for (i = 0; i < library_num; ++i)
618		do_init_elf(&lte[i + 1], library[i]);
619
620	if (!options.no_plt) {
621#ifdef __mips__
622		// MIPS doesn't use the PLT and the GOT entries get changed
623		// on startup.
624		proc->need_to_reinitialize_breakpoints = 1;
625		for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){
626			GElf_Sym sym;
627			const char *name;
628			GElf_Addr addr = arch_plt_sym_val(lte, i, 0);
629			if (gelf_getsym(lte->dynsym, i, &sym) == NULL){
630				error(EXIT_FAILURE, 0,
631						"Couldn't get relocation from \"%s\"",
632						proc->filename);
633			}
634			name=lte->dynstr+sym.st_name;
635			if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){
636				debug(2,"sym %s not a function",name);
637				continue;
638			}
639			add_library_symbol(addr, name, &library_symbols, 0,
640					ELF64_ST_BIND(sym.st_info) != 0);
641			if (!lib_tail)
642				lib_tail = &(library_symbols->next);
643		}
644#else
645		for (i = 0; i < lte->relplt_count; ++i) {
646			GElf_Rel rel;
647			GElf_Rela rela;
648			GElf_Sym sym;
649			GElf_Addr addr;
650			void *ret;
651			const char *name;
652
653			if (lte->relplt->d_type == ELF_T_REL) {
654				ret = gelf_getrel(lte->relplt, i, &rel);
655				rela.r_offset = rel.r_offset;
656				rela.r_info = rel.r_info;
657				rela.r_addend = 0;
658			} else
659				ret = gelf_getrela(lte->relplt, i, &rela);
660
661			if (ret == NULL
662					|| ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
663					|| gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
664						&sym) == NULL)
665				error(EXIT_FAILURE, 0,
666						"Couldn't get relocation from \"%s\"",
667						proc->filename);
668
669#ifdef PLT_REINITALISATION_BP
670			if (!sym.st_value && PLTs_initialized_by_here)
671				proc->need_to_reinitialize_breakpoints = 1;
672#endif
673
674			name = lte->dynstr + sym.st_name;
675			count = library_num ? library_num+1 : 0;
676
677			if (in_load_libraries(name, lte, count, NULL)) {
678				enum toplt pltt;
679				if (sym.st_value == 0 && lte->plt_stub_vma != 0) {
680					pltt = LS_TOPLT_EXEC;
681					addr = lte->plt_stub_vma + PPC_PLT_STUB_SIZE * i;
682				}
683				else {
684					pltt = PLTS_ARE_EXECUTABLE(lte)
685						?  LS_TOPLT_EXEC : LS_TOPLT_POINT;
686					addr = arch_plt_sym_val(lte, i, &rela);
687				}
688
689				add_library_symbol(addr, name, &library_symbols, pltt,
690						ELF64_ST_BIND(sym.st_info) == STB_WEAK);
691				if (!lib_tail)
692					lib_tail = &(library_symbols->next);
693			}
694		}
695#endif // !__mips__
696#ifdef PLT_REINITALISATION_BP
697		struct opt_x_t *main_cheat;
698
699		if (proc->need_to_reinitialize_breakpoints) {
700			/* Add "PLTs_initialized_by_here" to opt_x list, if not
701				 already there. */
702			main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
703			if (main_cheat == NULL)
704				error(EXIT_FAILURE, 0, "Couldn't allocate memory");
705			main_cheat->next = opt_x;
706			main_cheat->found = 0;
707			main_cheat->name = PLTs_initialized_by_here;
708
709			for (xptr = opt_x; xptr; xptr = xptr->next)
710				if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
711						&& main_cheat) {
712					free(main_cheat);
713					main_cheat = NULL;
714					break;
715				}
716			if (main_cheat)
717				opt_x = main_cheat;
718		}
719#endif
720	} else {
721		lib_tail = &library_symbols;
722	}
723
724	for (i = 0; i < lte->symtab_count; ++i) {
725		GElf_Sym sym;
726		GElf_Addr addr;
727		const char *name;
728
729		if (gelf_getsym(lte->symtab, i, &sym) == NULL)
730			error(EXIT_FAILURE, 0,
731			      "Couldn't get symbol from \"%s\"",
732			      proc->filename);
733
734		name = lte->strtab + sym.st_name;
735		addr = sym.st_value;
736		if (!addr)
737			continue;
738
739		for (xptr = opt_x; xptr; xptr = xptr->next)
740			if (xptr->name && strcmp(xptr->name, name) == 0) {
741				/* FIXME: Should be able to use &library_symbols as above.  But
742				   when you do, none of the real library symbols cause breaks. */
743				add_library_symbol(opd2addr(lte, addr),
744						   name, lib_tail, LS_TOPLT_NONE, 0);
745				xptr->found = 1;
746				break;
747			}
748	}
749
750	int found_count = 0;
751
752	for (xptr = opt_x; xptr; xptr = xptr->next) {
753		if (xptr->found)
754			continue;
755
756		GElf_Sym sym;
757		GElf_Addr addr;
758		if (in_load_libraries(xptr->name, lte, library_num+1, &sym)) {
759			debug(2, "found symbol %s @ %lx, adding it.", xptr->name, sym.st_value);
760			addr = sym.st_value;
761			if (ELF32_ST_TYPE (sym.st_info) == STT_FUNC) {
762				add_library_symbol(addr, xptr->name, lib_tail, LS_TOPLT_NONE, 0);
763				xptr->found = 1;
764				found_count++;
765			}
766		}
767		if (found_count == opt_x_cnt){
768			debug(2, "done, found everything: %d\n", found_count);
769			break;
770		}
771	}
772
773	for (xptr = opt_x; xptr; xptr = xptr->next)
774		if ( ! xptr->found) {
775			char *badthing = "WARNING";
776#ifdef PLT_REINITALISATION_BP
777			if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) {
778				if (lte->ehdr.e_entry) {
779					add_library_symbol (
780						opd2addr (lte, lte->ehdr.e_entry),
781						PLTs_initialized_by_here,
782						lib_tail, 1, 0);
783					fprintf (stderr, "WARNING: Using e_ent"
784						 "ry from elf header (%p) for "
785						 "address of \"%s\"\n", (void*)
786						 (long) lte->ehdr.e_entry,
787						 PLTs_initialized_by_here);
788					continue;
789				}
790				badthing = "ERROR";
791				exit_out = 1;
792			}
793#endif
794			fprintf (stderr,
795				 "%s: Couldn't find symbol \"%s\" in file \"%s"
796			         "\"\n", badthing, xptr->name, proc->filename);
797		}
798	if (exit_out) {
799		exit (1);
800	}
801
802	for (i = 0; i < library_num + 1; ++i)
803		do_close_elf(&lte[i]);
804
805	return library_symbols;
806}
807