aboutsummaryrefslogtreecommitdiff
path: root/elf.c
blob: deb82f82b7f6d4161ea4da43c51a7acf2b3d1db5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#if HAVE_CONFIG_H
#include "config.h"
#endif

/*
 * This file contains functions specific to ELF binaries
 */

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <elf.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

#include "ltrace.h"
#include "elf.h"
#include "options.h"
#include "output.h"

struct library_symbol * read_elf(const char *filename)
{
	struct library_symbol * library_symbols = NULL;
	struct stat sbuf;
	int fd;
	void * addr;
	Elf32_Ehdr * hdr;
	Elf32_Shdr * shdr;
	Elf32_Sym * symtab = NULL;
	int i;
	char * strtab = NULL;
	u_long symtab_len = 0;

	if (opt_d>0) {
		output_line(0, "Reading symbol table from %s...", filename);
	}

	fd = open(filename, O_RDONLY);
	if (fd==-1) {
		fprintf(stderr, "Can't open \"%s\": %s\n", filename, strerror(errno));
		exit(1);
	}
	if (fstat(fd, &sbuf)==-1) {
		fprintf(stderr, "Can't stat \"%s\": %s\n", filename, strerror(errno));
		exit(1);
	}
	if (sbuf.st_size < sizeof(Elf32_Ehdr)) {
		fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
		exit(1);
	}
	addr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
	if (addr==(void*)-1) {
		fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, strerror(errno));
		exit(1);
	}
	hdr = addr;
	if (strncmp(hdr->e_ident, ELFMAG, SELFMAG)) {
		fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
		exit(1);
	}
	for(i=0; i<hdr->e_shnum; i++) {
		shdr = addr + hdr->e_shoff + i*hdr->e_shentsize;
		if (shdr->sh_type == SHT_DYNSYM) {
			if (!symtab) {
#if 0
				symtab = (Elf32_Sym *)shdr->sh_addr;
#else
				symtab = (Elf32_Sym *)(addr + shdr->sh_offset);
#endif
				symtab_len = shdr->sh_size;
			}
		}
		if (shdr->sh_type == SHT_STRTAB) {
			if (!strtab) {
				strtab = (char *)(addr + shdr->sh_offset);
			}
		}
	}
	if (opt_d>1) {
		output_line(0, "symtab: 0x%08x", (unsigned)symtab);
		output_line(0, "symtab_len: %lu", symtab_len);
		output_line(0, "strtab: 0x%08x", (unsigned)strtab);
	}
	if (!symtab) {
		close(fd);
		return NULL;
	}
	for(i=0; i<symtab_len/sizeof(Elf32_Sym); i++) {
		if (!((symtab+i)->st_shndx) && (symtab+i)->st_value) {
			struct library_symbol * tmp = library_symbols;

			library_symbols = malloc(sizeof(struct library_symbol));
			if (!library_symbols) {
				perror("ltrace: malloc");
				exit(1);
			}
			library_symbols->brk.addr = (void *)((symtab+i)->st_value);
			library_symbols->brk.enabled = 0;
			library_symbols->name = strtab+(symtab+i)->st_name;
			library_symbols->next = tmp;
			if (opt_d>1) {
				output_line(0, "addr: 0x%08x, symbol: \"%s\"",
					(unsigned)((symtab+i)->st_value),
					(strtab+(symtab+i)->st_name));
			}
		}
	}
	close(fd);
	return library_symbols;
}