blob: ad4e8fe66f5d408f708ead1b0a90026cd40f1634 [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 Cespedesefe85f02004-04-04 01:31:38 +020065 if (sbuf.st_size < sizeof(Elf_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 Cespedesefe85f02004-04-04 01:31:38 +020086#if defined(FILEFORMAT_CHECK)
87 if (! ffcheck(lte->maddr)) {
88 fprintf(
89 stderr,
90 "%s: wrong architecture or ELF format\n",
91 filename
92 );
93 exit(1);
94 }
95#endif
96
Juan Cespedes1cd999a2001-07-03 00:46:04 +020097 lte->ehdr = lte->maddr;
98
99 if (strncmp(lte->ehdr->e_ident, ELFMAG, SELFMAG)) {
100 fprintf(
101 stderr,
102 "\"%s\" is not an ELF binary object\n",
103 filename
104 );
105 exit(1);
106 }
107
108/*
109 more ELF checks should go here - the e_arch/e_machine fields in the
110 ELF header are specific to each architecture. perhaps move some code
111 into sysdeps (have check_ehdr_arch) - silvio
112*/
113
114 lte->strtab = NULL;
115
116 lte->symtab = NULL;
117 lte->symtab_len = 0;
118}
119
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100120static void
121do_close_elf(struct ltelf *lte) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200122 close(lte->fd);
123}
124
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100125static void
126do_load_elf_symtab(struct ltelf *lte) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200127 void *maddr = lte->maddr;
Juan Cespedesefe85f02004-04-04 01:31:38 +0200128 Elf_Ehdr *ehdr = lte->ehdr;
129 Elf_Shdr *shdr = (Elf_Shdr *)(maddr + ehdr->e_shoff);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200130 int i;
131
132/*
133 an ELF object should only ever one dynamic symbol section (DYNSYM), but
134 can have multiple string tables. the sh_link entry from DYNSYM points
135 to the correct STRTAB section - silvio
136*/
137
138 for(i = 0; i < ehdr->e_shnum; i++) {
139 if (shdr[i].sh_type == SHT_DYNSYM) {
Juan Cespedesefe85f02004-04-04 01:31:38 +0200140 lte->symtab = (Elf_Sym *)(maddr + shdr[i].sh_offset);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200141 lte->symtab_len = shdr[i].sh_size;
142 lte->strtab = (char *)(
143 maddr + shdr[shdr[i].sh_link].sh_offset
144 );
145 }
146 }
147
Juan Cespedesefe85f02004-04-04 01:31:38 +0200148 debug(2, "symtab: %p", lte->symtab);
Juan Cespedescac15c32003-01-31 18:58:58 +0100149 debug(2, "symtab_len: %lu", lte->symtab_len);
Juan Cespedesefe85f02004-04-04 01:31:38 +0200150 debug(2, "strtab: %p", lte->strtab);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200151}
152
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100153static void
154add_library_symbol(
155 struct ltelf *lte,
156 int i,
157 struct library_symbol **library_symbolspp) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200158 struct library_symbol *tmp = *library_symbolspp;
159 struct library_symbol *library_symbols;
160
161 *library_symbolspp = (struct library_symbol *)malloc(
162 sizeof(struct library_symbol)
163 );
164 library_symbols = *library_symbolspp;
165 if (library_symbols == NULL) {
166 perror("ltrace: malloc");
167 exit(1);
168 }
169
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200170#ifdef __sparc__
171 library_symbols->enter_addr = (void *)(lte->symtab[i].st_value + 4 /* plt(?) */);
172#else
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200173 library_symbols->enter_addr = (void *)lte->symtab[i].st_value;
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200174#endif
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200175 library_symbols->name = &lte->strtab[lte->symtab[i].st_name];
176 library_symbols->next = tmp;
177
Juan Cespedesefe85f02004-04-04 01:31:38 +0200178 debug(2, "addr: %p, symbol: \"%s\"",
179 lte->symtab[i].st_value,
Juan Cespedescac15c32003-01-31 18:58:58 +0100180 &lte->strtab[lte->symtab[i].st_name]);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200181}
182
183/*
184 this is all pretty slow. perhaps using .hash would be faster, or
185 even just a custum built hash table. its all initialization though,
186 so its not that bad - silvio
187*/
188
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100189static void
190do_init_load_libraries(void) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200191 int i;
192
193 for (i = 0; i < library_num; i++) {
194 do_init_elf(&library_lte[i], library[i]);
195 do_load_elf_symtab(&library_lte[i]);
196 }
197}
198
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100199static void
200do_close_load_libraries(void) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200201 int i;
202
203 for (i = 0; i < library_num; i++) {
204 do_close_elf(&library_lte[i]);
205 }
206}
207
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100208static int
209in_load_libraries(const char *func) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200210 int i, j;
211/*
212 if no libraries are specified, assume we want all
213*/
214 if (library_num == 0) return 1;
215
216 for (i = 0; i < library_num; i++) {
Juan Cespedesefe85f02004-04-04 01:31:38 +0200217 Elf_Sym *symtab = library_lte[i].symtab;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200218 char *strtab = library_lte[i].strtab;
219
220 for(
221 j = 0;
Juan Cespedesefe85f02004-04-04 01:31:38 +0200222 j < library_lte[i].symtab_len / sizeof(Elf_Sym);
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200223 j++
224 ) {
225 if (
226 symtab[j].st_value &&
227 !strcmp(func, &strtab[symtab[j].st_name])
228 ) return 1;
229 }
230 }
231 return 0;
232}
233
234/*
235 this is the main function
236*/
237
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100238struct library_symbol *
239read_elf(const char *filename) {
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200240 struct library_symbol *library_symbols = NULL;
241 struct ltelf lte;
242 int i;
243
244 do_init_elf(&lte, filename);
245 do_load_elf_symtab(&lte);
246 do_init_load_libraries();
247
Juan Cespedesefe85f02004-04-04 01:31:38 +0200248 for(i = 0; i < lte.symtab_len / sizeof(Elf_Sym); i++) {
249 Elf_Sym *symtab = lte.symtab;
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200250 char *strtab = lte.strtab;
251
252 if (!symtab[i].st_shndx && symtab[i].st_value) {
253 if (in_load_libraries(&strtab[symtab[i].st_name])) {
254 add_library_symbol(&lte, i, &library_symbols);
Juan Cespedes96935a91997-08-09 23:45:39 +0200255 }
256 }
257 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200258
259 do_close_load_libraries();
260 do_close_elf(&lte);
261
Juan Cespedes5e01f651998-03-08 22:31:44 +0100262 return library_symbols;
Juan Cespedes96935a91997-08-09 23:45:39 +0200263}