blob: e8b446b2076d83d5de197ae0ecc7115a46c5b628 [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
41static void do_init_elf(struct ltelf *lte, const char *filename)
42{
43 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
112static void do_close_elf(struct ltelf *lte)
113{
114 close(lte->fd);
115}
116
117static void do_load_elf_symtab(struct ltelf *lte)
118{
119 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
147static void add_library_symbol(
148 struct ltelf *lte,
149 int i,
150 struct library_symbol **library_symbolspp
151)
152{
153 struct library_symbol *tmp = *library_symbolspp;
154 struct library_symbol *library_symbols;
155
156 *library_symbolspp = (struct library_symbol *)malloc(
157 sizeof(struct library_symbol)
158 );
159 library_symbols = *library_symbolspp;
160 if (library_symbols == NULL) {
161 perror("ltrace: malloc");
162 exit(1);
163 }
164
165 library_symbols->enter_addr = (void *)lte->symtab[i].st_value;
166 library_symbols->name = &lte->strtab[lte->symtab[i].st_name];
167 library_symbols->next = tmp;
168
169 if (opt_d > 1) {
170 output_line(
171 0,
172 "addr: 0x%08x, symbol: \"%s\"",
173 (unsigned)lte->symtab[i].st_value,
174 &lte->strtab[lte->symtab[i].st_name]
175 );
176 }
177}
178
179/*
180 this is all pretty slow. perhaps using .hash would be faster, or
181 even just a custum built hash table. its all initialization though,
182 so its not that bad - silvio
183*/
184
185static void do_init_load_libraries(void)
186{
187 int i;
188
189 for (i = 0; i < library_num; i++) {
190 do_init_elf(&library_lte[i], library[i]);
191 do_load_elf_symtab(&library_lte[i]);
192 }
193}
194
195static void do_close_load_libraries(void)
196{
197 int i;
198
199 for (i = 0; i < library_num; i++) {
200 do_close_elf(&library_lte[i]);
201 }
202}
203
204static int in_load_libraries(const char *func)
205{
206 int i, j;
207/*
208 if no libraries are specified, assume we want all
209*/
210 if (library_num == 0) return 1;
211
212 for (i = 0; i < library_num; i++) {
213 Elf32_Sym *symtab = library_lte[i].symtab;
214 char *strtab = library_lte[i].strtab;
215
216 for(
217 j = 0;
218 j < library_lte[i].symtab_len / sizeof(Elf32_Sym);
219 j++
220 ) {
221 if (
222 symtab[j].st_value &&
223 !strcmp(func, &strtab[symtab[j].st_name])
224 ) return 1;
225 }
226 }
227 return 0;
228}
229
230/*
231 this is the main function
232*/
233
234struct library_symbol * read_elf(const char *filename)
235{
236 struct library_symbol *library_symbols = NULL;
237 struct ltelf lte;
238 int i;
239
240 do_init_elf(&lte, filename);
241 do_load_elf_symtab(&lte);
242 do_init_load_libraries();
243
244 for(i = 0; i < lte.symtab_len / sizeof(Elf32_Sym); i++) {
245 Elf32_Sym *symtab = lte.symtab;
246 char *strtab = lte.strtab;
247
248 if (!symtab[i].st_shndx && symtab[i].st_value) {
249 if (in_load_libraries(&strtab[symtab[i].st_name])) {
250 add_library_symbol(&lte, i, &library_symbols);
Juan Cespedes96935a91997-08-09 23:45:39 +0200251 }
252 }
253 }
Juan Cespedes1cd999a2001-07-03 00:46:04 +0200254
255 do_close_load_libraries();
256 do_close_elf(&lte);
257
Juan Cespedes5e01f651998-03-08 22:31:44 +0100258 return library_symbols;
Juan Cespedes96935a91997-08-09 23:45:39 +0200259}