blob: b3f7a12d0c4c030ce3bc3c80f3b1c0e9bd78122e [file] [log] [blame]
Juan Cespedesd44c6b81998-09-25 14:48:42 +02001#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
Juan Cespedesc9a48b91997-08-17 02:45:40 +02005/*
6 * This file contains functions specific to ELF binaries
Juan Cespedes1cd999a2001-07-03 00:46:04 +02007 *
8 * Silvio Cesare <silvio@big.net.au>
9 *
Juan Cespedesc9a48b91997-08-17 02:45:40 +020010 */
11
Juan Cespedes96935a91997-08-09 23:45:39 +020012#include <stdio.h>
13#include <errno.h>
14#include <stdlib.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020015#include <sys/types.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020016#include <sys/stat.h>
17#include <fcntl.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020018#include <sys/mman.h>
19#include <string.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +010020#include <unistd.h>
Juan Cespedes96935a91997-08-09 23:45:39 +020021
Juan Cespedes96935a91997-08-09 23:45:39 +020022#include "ltrace.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010023#include "elf.h"
24#include "options.h"
Juan Cespedes3268a161997-08-25 16:45:22 +020025#include "output.h"
Juan Cespedes96935a91997-08-09 23:45:39 +020026
Juan Cespedes1cd999a2001-07-03 00:46:04 +020027static void do_init_elf(struct ltelf *lte, const char *filename);
28static void do_close_elf(struct ltelf *lte);
29static void do_load_elf_symtab(struct ltelf *lte);
30static void do_init_load_libraries(void);
31static void do_close_load_libraries(void);
32static int in_load_libraries(const char *func);
33static void add_library_symbol(
34 struct ltelf *lte,
35 int i,
36 struct library_symbol **library_symbolspp
37);
Juan Cespedes96935a91997-08-09 23:45:39 +020038
Juan Cespedes1cd999a2001-07-03 00:46:04 +020039static struct ltelf library_lte[MAX_LIBRARY];
40
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010041static void
42do_init_elf(struct ltelf *lte, const char *filename) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +020043 struct stat sbuf;
44
45 if (opt_d > 0) {
46 output_line(0, "Reading ELF from %s...", filename);
Juan Cespedes1afec691997-08-23 21:31:46 +020047 }
48
Juan Cespedes1cd999a2001-07-03 00:46:04 +020049 lte->fd = open(filename, O_RDONLY);
50 if (lte->fd == -1) {
51 fprintf(
52 stderr,
53 "Can't open \"%s\": %s\n",
54 filename,
55 strerror(errno)
56 );
Juan Cespedes96935a91997-08-09 23:45:39 +020057 exit(1);
58 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +020059 if (fstat(lte->fd, &sbuf) == -1) {
60 fprintf(
61 stderr,
62 "Can't stat \"%s\": %s\n",
63 filename,
64 strerror(errno)
65 );
Juan Cespedes96935a91997-08-09 23:45:39 +020066 exit(1);
67 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010068 if (sbuf.st_size < sizeof(Elf32_Ehdr)) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +020069 fprintf(
70 stderr,
71 "\"%s\" is not an ELF binary object\n",
72 filename
73 );
Juan Cespedes96935a91997-08-09 23:45:39 +020074 exit(1);
75 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +020076 lte->maddr = mmap(
77 NULL, sbuf.st_size, PROT_READ, MAP_SHARED, lte->fd, 0
78 );
79 if (lte->maddr == (void*)-1) {
80 fprintf(
81 stderr,
82 "Can't mmap \"%s\": %s\n",
83 filename,
84 strerror(errno)
85 );
Juan Cespedes96935a91997-08-09 23:45:39 +020086 exit(1);
87 }
Juan Cespedes96935a91997-08-09 23:45:39 +020088
Juan Cespedes1cd999a2001-07-03 00:46:04 +020089 lte->ehdr = lte->maddr;
90
91 if (strncmp(lte->ehdr->e_ident, ELFMAG, SELFMAG)) {
92 fprintf(
93 stderr,
94 "\"%s\" is not an ELF binary object\n",
95 filename
96 );
97 exit(1);
98 }
99
100/*
101 more ELF checks should go here - the e_arch/e_machine fields in the
102 ELF header are specific to each architecture. perhaps move some code
103 into sysdeps (have check_ehdr_arch) - silvio
104*/
105
106 lte->strtab = NULL;
107
108 lte->symtab = NULL;
109 lte->symtab_len = 0;
110}
111
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100112static void
113do_close_elf(struct ltelf *lte) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200114 close(lte->fd);
115}
116
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100117static void
118do_load_elf_symtab(struct ltelf *lte) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200119 void *maddr = lte->maddr;
120 Elf32_Ehdr *ehdr = lte->ehdr;
121 Elf32_Shdr *shdr = (Elf32_Shdr *)(maddr + ehdr->e_shoff);
122 int i;
123
124/*
125 an ELF object should only ever one dynamic symbol section (DYNSYM), but
126 can have multiple string tables. the sh_link entry from DYNSYM points
127 to the correct STRTAB section - silvio
128*/
129
130 for(i = 0; i < ehdr->e_shnum; i++) {
131 if (shdr[i].sh_type == SHT_DYNSYM) {
132 lte->symtab = (Elf32_Sym *)(maddr + shdr[i].sh_offset);
133 lte->symtab_len = shdr[i].sh_size;
134 lte->strtab = (char *)(
135 maddr + shdr[shdr[i].sh_link].sh_offset
136 );
137 }
138 }
139
140 if (opt_d > 1) {
141 output_line(0, "symtab: 0x%08x", (unsigned)lte->symtab);
142 output_line(0, "symtab_len: %lu", lte->symtab_len);
143 output_line(0, "strtab: 0x%08x", (unsigned)lte->strtab);
144 }
145}
146
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100147static void
148add_library_symbol(
149 struct ltelf *lte,
150 int i,
151 struct library_symbol **library_symbolspp) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200152 struct library_symbol *tmp = *library_symbolspp;
153 struct library_symbol *library_symbols;
154
155 *library_symbolspp = (struct library_symbol *)malloc(
156 sizeof(struct library_symbol)
157 );
158 library_symbols = *library_symbolspp;
159 if (library_symbols == NULL) {
160 perror("ltrace: malloc");
161 exit(1);
162 }
163
164 library_symbols->enter_addr = (void *)lte->symtab[i].st_value;
165 library_symbols->name = &lte->strtab[lte->symtab[i].st_name];
166 library_symbols->next = tmp;
167
168 if (opt_d > 1) {
169 output_line(
170 0,
171 "addr: 0x%08x, symbol: \"%s\"",
172 (unsigned)lte->symtab[i].st_value,
173 &lte->strtab[lte->symtab[i].st_name]
174 );
175 }
176}
177
178/*
179 this is all pretty slow. perhaps using .hash would be faster, or
180 even just a custum built hash table. its all initialization though,
181 so its not that bad - silvio
182*/
183
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100184static void
185do_init_load_libraries(void) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200186 int i;
187
188 for (i = 0; i < library_num; i++) {
189 do_init_elf(&library_lte[i], library[i]);
190 do_load_elf_symtab(&library_lte[i]);
191 }
192}
193
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100194static void
195do_close_load_libraries(void) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200196 int i;
197
198 for (i = 0; i < library_num; i++) {
199 do_close_elf(&library_lte[i]);
200 }
201}
202
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100203static int
204in_load_libraries(const char *func) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200205 int i, j;
206/*
207 if no libraries are specified, assume we want all
208*/
209 if (library_num == 0) return 1;
210
211 for (i = 0; i < library_num; i++) {
212 Elf32_Sym *symtab = library_lte[i].symtab;
213 char *strtab = library_lte[i].strtab;
214
215 for(
216 j = 0;
217 j < library_lte[i].symtab_len / sizeof(Elf32_Sym);
218 j++
219 ) {
220 if (
221 symtab[j].st_value &&
222 !strcmp(func, &strtab[symtab[j].st_name])
223 ) return 1;
224 }
225 }
226 return 0;
227}
228
229/*
230 this is the main function
231*/
232
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100233struct library_symbol *
234read_elf(const char *filename) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200235 struct library_symbol *library_symbols = NULL;
236 struct ltelf lte;
237 int i;
238
239 do_init_elf(&lte, filename);
240 do_load_elf_symtab(&lte);
241 do_init_load_libraries();
242
243 for(i = 0; i < lte.symtab_len / sizeof(Elf32_Sym); i++) {
244 Elf32_Sym *symtab = lte.symtab;
245 char *strtab = lte.strtab;
246
247 if (!symtab[i].st_shndx && symtab[i].st_value) {
248 if (in_load_libraries(&strtab[symtab[i].st_name])) {
249 add_library_symbol(&lte, i, &library_symbols);
Juan Cespedes96935a91997-08-09 23:45:39 +0200250 }
251 }
252 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200253
254 do_close_load_libraries();
255 do_close_elf(&lte);
256
Juan Cespedes5e01f651998-03-08 22:31:44 +0100257 return library_symbols;
Juan Cespedes96935a91997-08-09 23:45:39 +0200258}