ltrace-elf.c revision 747c73d5b7d66d312a1b1a293e67f9ddf2f17d93
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
15static void do_init_elf(struct ltelf *lte, const char *filename);
16static void do_close_elf(struct ltelf *lte);
17static 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);
20static int in_load_libraries(const char *name, struct ltelf *lte);
21static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr);
22
23#ifdef PLT_REINITALISATION_BP
24extern char *PLTs_initialized_by_here;
25#endif
26
27static void
28do_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
317static void
318do_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
326static void
327add_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 */
351static unsigned long
352private_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
361static int
362in_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
435static GElf_Addr
436opd2addr(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
454struct library_symbol *
455read_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
472	if (!options.no_plt) {
473#ifdef __mips__
474		// MIPS doesn't use the PLT and the GOT entries get changed
475		// on startup.
476		proc->need_to_reinitialize_breakpoints = 1;
477		for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){
478			GElf_Sym sym;
479			const char *name;
480			GElf_Addr addr = arch_plt_sym_val(lte, i, 0);
481			if (gelf_getsym(lte->dynsym, i, &sym) == NULL){
482				error(EXIT_FAILURE, 0,
483						"Couldn't get relocation from \"%s\"",
484						proc->filename);
485			}
486			name=lte->dynstr+sym.st_name;
487			if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){
488				debug(2,"sym %s not a function",name);
489				continue;
490			}
491			add_library_symbol(addr, name, &library_symbols, 0,
492					ELF64_ST_BIND(sym.st_info) != 0);
493			if (!lib_tail)
494				lib_tail = &(library_symbols->next);
495		}
496#else
497		for (i = 0; i < lte->relplt_count; ++i) {
498			GElf_Rel rel;
499			GElf_Rela rela;
500			GElf_Sym sym;
501			GElf_Addr addr;
502			void *ret;
503			const char *name;
504
505			if (lte->relplt->d_type == ELF_T_REL) {
506				ret = gelf_getrel(lte->relplt, i, &rel);
507				rela.r_offset = rel.r_offset;
508				rela.r_info = rel.r_info;
509				rela.r_addend = 0;
510			} else
511				ret = gelf_getrela(lte->relplt, i, &rela);
512
513			if (ret == NULL
514					|| ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
515					|| gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
516						&sym) == NULL)
517				error(EXIT_FAILURE, 0,
518						"Couldn't get relocation from \"%s\"",
519						proc->filename);
520
521#ifdef PLT_REINITALISATION_BP
522			if (!sym.st_value && PLTs_initialized_by_here)
523				proc->need_to_reinitialize_breakpoints = 1;
524#endif
525
526		name = lte->dynstr + sym.st_name;
527		if (in_load_libraries(name, lte)) {
528			addr = arch_plt_sym_val(lte, i, &rela);
529			add_library_symbol(addr, name, &library_symbols,
530					   (PLTS_ARE_EXECUTABLE(lte)
531					   ?  LS_TOPLT_EXEC : LS_TOPLT_POINT),
532					   ELF64_ST_BIND(sym.st_info) == STB_WEAK);
533			if (!lib_tail)
534				lib_tail = &(library_symbols->next);
535			}
536		}
537#endif // !__mips__
538#ifdef PLT_REINITALISATION_BP
539		struct opt_x_t *main_cheat;
540
541		if (proc->need_to_reinitialize_breakpoints) {
542			/* Add "PLTs_initialized_by_here" to opt_x list, if not
543				 already there. */
544			main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
545			if (main_cheat == NULL)
546				error(EXIT_FAILURE, 0, "Couldn't allocate memory");
547			main_cheat->next = opt_x;
548			main_cheat->found = 0;
549			main_cheat->name = PLTs_initialized_by_here;
550
551			for (xptr = opt_x; xptr; xptr = xptr->next)
552				if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
553						&& main_cheat) {
554					free(main_cheat);
555					main_cheat = NULL;
556					break;
557				}
558			if (main_cheat)
559				opt_x = main_cheat;
560		}
561#endif
562	} else {
563		lib_tail = &library_symbols;
564	}
565
566	for (i = 0; i < lte->symtab_count; ++i) {
567		GElf_Sym sym;
568		GElf_Addr addr;
569		const char *name;
570
571		if (gelf_getsym(lte->symtab, i, &sym) == NULL)
572			error(EXIT_FAILURE, 0,
573			      "Couldn't get symbol from \"%s\"",
574			      proc->filename);
575
576		name = lte->strtab + sym.st_name;
577		addr = sym.st_value;
578		if (!addr)
579			continue;
580
581		for (xptr = opt_x; xptr; xptr = xptr->next)
582			if (xptr->name && strcmp(xptr->name, name) == 0) {
583				/* FIXME: Should be able to use &library_symbols as above.  But
584				   when you do, none of the real library symbols cause breaks. */
585				add_library_symbol(opd2addr(lte, addr),
586						   name, lib_tail, LS_TOPLT_NONE, 0);
587				xptr->found = 1;
588				break;
589			}
590	}
591	for (xptr = opt_x; xptr; xptr = xptr->next)
592		if ( ! xptr->found) {
593			char *badthing = "WARNING";
594#ifdef PLT_REINITALISATION_BP
595			if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) {
596				if (lte->ehdr.e_entry) {
597					add_library_symbol (
598						opd2addr (lte, lte->ehdr.e_entry),
599						PLTs_initialized_by_here,
600						lib_tail, 1, 0);
601					fprintf (stderr, "WARNING: Using e_ent"
602						 "ry from elf header (%p) for "
603						 "address of \"%s\"\n", (void*)
604						 (long) lte->ehdr.e_entry,
605						 PLTs_initialized_by_here);
606					continue;
607				}
608				badthing = "ERROR";
609				exit_out = 1;
610			}
611#endif
612			fprintf (stderr,
613				 "%s: Couldn't find symbol \"%s\" in file \"%s"
614			         "\"\n", badthing, xptr->name, proc->filename);
615		}
616	if (exit_out) {
617		exit (1);
618	}
619
620	for (i = 0; i < library_num + 1; ++i)
621		do_close_elf(&lte[i]);
622
623	return library_symbols;
624}
625