blob: d1fb6ca03ce5420842cec90aa06a0e4c5875a970 [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"
Juan Cespedescac15c32003-01-31 18:58:58 +010024#include "debug.h"
Juan Cespedes96935a91997-08-09 23:45:39 +020025
Juan Cespedes1cd999a2001-07-03 00:46:04 +020026static void do_init_elf(struct ltelf *lte, const char *filename);
27static void do_close_elf(struct ltelf *lte);
28static void do_load_elf_symtab(struct ltelf *lte);
29static void do_init_load_libraries(void);
30static void do_close_load_libraries(void);
31static int in_load_libraries(const char *func);
32static void add_library_symbol(
33 struct ltelf *lte,
34 int i,
35 struct library_symbol **library_symbolspp
36);
Juan Cespedes96935a91997-08-09 23:45:39 +020037
Juan Cespedes1cd999a2001-07-03 00:46:04 +020038static struct ltelf library_lte[MAX_LIBRARY];
39
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010040static void
41do_init_elf(struct ltelf *lte, const char *filename) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +020042 struct stat sbuf;
43
Juan Cespedescac15c32003-01-31 18:58:58 +010044 debug(1, "Reading ELF from %s...", filename);
Juan Cespedes1afec691997-08-23 21:31:46 +020045
Juan Cespedes1cd999a2001-07-03 00:46:04 +020046 lte->fd = open(filename, O_RDONLY);
47 if (lte->fd == -1) {
48 fprintf(
49 stderr,
50 "Can't open \"%s\": %s\n",
51 filename,
52 strerror(errno)
53 );
Juan Cespedes96935a91997-08-09 23:45:39 +020054 exit(1);
55 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +020056 if (fstat(lte->fd, &sbuf) == -1) {
57 fprintf(
58 stderr,
59 "Can't stat \"%s\": %s\n",
60 filename,
61 strerror(errno)
62 );
Juan Cespedes96935a91997-08-09 23:45:39 +020063 exit(1);
64 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010065 if (sbuf.st_size < sizeof(Elf32_Ehdr)) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +020066 fprintf(
67 stderr,
68 "\"%s\" is not an ELF binary object\n",
69 filename
70 );
Juan Cespedes96935a91997-08-09 23:45:39 +020071 exit(1);
72 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +020073 lte->maddr = mmap(
74 NULL, sbuf.st_size, PROT_READ, MAP_SHARED, lte->fd, 0
75 );
76 if (lte->maddr == (void*)-1) {
77 fprintf(
78 stderr,
79 "Can't mmap \"%s\": %s\n",
80 filename,
81 strerror(errno)
82 );
Juan Cespedes96935a91997-08-09 23:45:39 +020083 exit(1);
84 }
Juan Cespedes96935a91997-08-09 23:45:39 +020085
Juan Cespedes1cd999a2001-07-03 00:46:04 +020086 lte->ehdr = lte->maddr;
87
88 if (strncmp(lte->ehdr->e_ident, ELFMAG, SELFMAG)) {
89 fprintf(
90 stderr,
91 "\"%s\" is not an ELF binary object\n",
92 filename
93 );
94 exit(1);
95 }
96
97/*
98 more ELF checks should go here - the e_arch/e_machine fields in the
99 ELF header are specific to each architecture. perhaps move some code
100 into sysdeps (have check_ehdr_arch) - silvio
101*/
102
103 lte->strtab = NULL;
104
105 lte->symtab = NULL;
106 lte->symtab_len = 0;
107}
108
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100109static void
110do_close_elf(struct ltelf *lte) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200111 close(lte->fd);
112}
113
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100114static void
115do_load_elf_symtab(struct ltelf *lte) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200116 void *maddr = lte->maddr;
117 Elf32_Ehdr *ehdr = lte->ehdr;
118 Elf32_Shdr *shdr = (Elf32_Shdr *)(maddr + ehdr->e_shoff);
119 int i;
120
121/*
122 an ELF object should only ever one dynamic symbol section (DYNSYM), but
123 can have multiple string tables. the sh_link entry from DYNSYM points
124 to the correct STRTAB section - silvio
125*/
126
127 for(i = 0; i < ehdr->e_shnum; i++) {
128 if (shdr[i].sh_type == SHT_DYNSYM) {
129 lte->symtab = (Elf32_Sym *)(maddr + shdr[i].sh_offset);
130 lte->symtab_len = shdr[i].sh_size;
131 lte->strtab = (char *)(
132 maddr + shdr[shdr[i].sh_link].sh_offset
133 );
134 }
135 }
136
Juan Cespedescac15c32003-01-31 18:58:58 +0100137 debug(2, "symtab: 0x%08x", (unsigned)lte->symtab);
138 debug(2, "symtab_len: %lu", lte->symtab_len);
139 debug(2, "strtab: 0x%08x", (unsigned)lte->strtab);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200140}
141
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100142static void
143add_library_symbol(
144 struct ltelf *lte,
145 int i,
146 struct library_symbol **library_symbolspp) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200147 struct library_symbol *tmp = *library_symbolspp;
148 struct library_symbol *library_symbols;
149
150 *library_symbolspp = (struct library_symbol *)malloc(
151 sizeof(struct library_symbol)
152 );
153 library_symbols = *library_symbolspp;
154 if (library_symbols == NULL) {
155 perror("ltrace: malloc");
156 exit(1);
157 }
158
159 library_symbols->enter_addr = (void *)lte->symtab[i].st_value;
160 library_symbols->name = &lte->strtab[lte->symtab[i].st_name];
161 library_symbols->next = tmp;
162
Juan Cespedescac15c32003-01-31 18:58:58 +0100163 debug(2, "addr: 0x%08x, symbol: \"%s\"",
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200164 (unsigned)lte->symtab[i].st_value,
Juan Cespedescac15c32003-01-31 18:58:58 +0100165 &lte->strtab[lte->symtab[i].st_name]);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200166}
167
168/*
169 this is all pretty slow. perhaps using .hash would be faster, or
170 even just a custum built hash table. its all initialization though,
171 so its not that bad - silvio
172*/
173
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100174static void
175do_init_load_libraries(void) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200176 int i;
177
178 for (i = 0; i < library_num; i++) {
179 do_init_elf(&library_lte[i], library[i]);
180 do_load_elf_symtab(&library_lte[i]);
181 }
182}
183
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100184static void
185do_close_load_libraries(void) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200186 int i;
187
188 for (i = 0; i < library_num; i++) {
189 do_close_elf(&library_lte[i]);
190 }
191}
192
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100193static int
194in_load_libraries(const char *func) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200195 int i, j;
196/*
197 if no libraries are specified, assume we want all
198*/
199 if (library_num == 0) return 1;
200
201 for (i = 0; i < library_num; i++) {
202 Elf32_Sym *symtab = library_lte[i].symtab;
203 char *strtab = library_lte[i].strtab;
204
205 for(
206 j = 0;
207 j < library_lte[i].symtab_len / sizeof(Elf32_Sym);
208 j++
209 ) {
210 if (
211 symtab[j].st_value &&
212 !strcmp(func, &strtab[symtab[j].st_name])
213 ) return 1;
214 }
215 }
216 return 0;
217}
218
219/*
220 this is the main function
221*/
222
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100223struct library_symbol *
224read_elf(const char *filename) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200225 struct library_symbol *library_symbols = NULL;
226 struct ltelf lte;
227 int i;
228
229 do_init_elf(&lte, filename);
230 do_load_elf_symtab(&lte);
231 do_init_load_libraries();
232
233 for(i = 0; i < lte.symtab_len / sizeof(Elf32_Sym); i++) {
234 Elf32_Sym *symtab = lte.symtab;
235 char *strtab = lte.strtab;
236
237 if (!symtab[i].st_shndx && symtab[i].st_value) {
238 if (in_load_libraries(&strtab[symtab[i].st_name])) {
239 add_library_symbol(&lte, i, &library_symbols);
Juan Cespedes96935a91997-08-09 23:45:39 +0200240 }
241 }
242 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200243
244 do_close_load_libraries();
245 do_close_elf(&lte);
246
Juan Cespedes5e01f651998-03-08 22:31:44 +0100247 return library_symbols;
Juan Cespedes96935a91997-08-09 23:45:39 +0200248}