Deleted Added
sdiff udiff text old ( 100272 ) new ( 109607 )
full compact
1/*
2 * Copyright (c) 2000, Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: head/usr.sbin/kldxref/ef.c 100272 2002-07-17 23:41:58Z peter $
33 */
34
35#include <sys/param.h>
36#include <sys/linker.h>
37#include <string.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <machine/elf.h>
44#define FREEBSD_ELF
45#include <link.h>
46
47#include <err.h>
48
49#include "ef.h"
50
51static void ef_print_phdr(Elf_Phdr *);
52static u_long ef_get_offset(elf_file_t, Elf_Off);
53static int ef_parse_dynamic(elf_file_t);
54
55void
56ef_print_phdr(Elf_Phdr *phdr)
57{
58
59 if ((phdr->p_flags & PF_W) == 0) {
60 printf("text=0x%lx ", (long)phdr->p_filesz);
61 } else {
62 printf("data=0x%lx", (long)phdr->p_filesz);
63 if (phdr->p_filesz < phdr->p_memsz)
64 printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz));
65 printf(" ");
66 }
67}
68
69u_long
70ef_get_offset(elf_file_t ef, Elf_Off off)
71{
72 Elf_Phdr *ph;
73 int i;
74
75 for (i = 0; i < ef->ef_nsegs; i++) {
76 ph = ef->ef_segs[i];
77 if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) {
78 return ph->p_offset + (off - ph->p_vaddr);
79 }
80 }
81 return 0;
82}
83
84/*
85 * next three functions copied from link_elf.c
86 */
87static unsigned long
88elf_hash(const char *name)
89{
90 const unsigned char *p = (const unsigned char *) name;
91 unsigned long h = 0;
92 unsigned long g;
93
94 while (*p != '\0') {
95 h = (h << 4) + *p++;
96 if ((g = h & 0xf0000000) != 0)
97 h ^= g >> 24;
98 h &= ~g;
99 }
100 return h;
101}
102
103int
104ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
105{
106 unsigned long symnum;
107 Elf_Sym* symp;
108 char *strp;
109 unsigned long hash;
110
111 /* First, search hashed global symbols */
112 hash = elf_hash(name);
113 symnum = ef->ef_buckets[hash % ef->ef_nbuckets];
114
115 while (symnum != STN_UNDEF) {
116 if (symnum >= ef->ef_nchains) {
117 warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
118 ef->ef_name);
119 return ENOENT;
120 }
121
122 symp = ef->ef_symtab + symnum;
123 if (symp->st_name == 0) {
124 warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
125 ef->ef_name);
126 return ENOENT;
127 }
128
129 strp = ef->ef_strtab + symp->st_name;
130
131 if (strcmp(name, strp) == 0) {
132 if (symp->st_shndx != SHN_UNDEF ||
133 (symp->st_value != 0 &&
134 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
135 *sym = symp;
136 return 0;
137 } else
138 return ENOENT;
139 }
140
141 symnum = ef->ef_chains[symnum];
142 }
143
144 return ENOENT;
145}
146
147int
148ef_parse_dynamic(elf_file_t ef)
149{
150 Elf_Dyn *dp;
151 Elf_Hashelt hashhdr[2];
152/* int plttype = DT_REL;*/
153 int error;
154
155 for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) {
156 switch (dp->d_tag) {
157 case DT_HASH:
158 error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr),
159 sizeof(hashhdr), hashhdr);
160 if (error) {
161 warnx("can't read hash header (%lx)",
162 ef_get_offset(ef, dp->d_un.d_ptr));
163 return error;
164 }
165 ef->ef_nbuckets = hashhdr[0];
166 ef->ef_nchains = hashhdr[1];
167 error = ef_read_entry(ef, -1,
168 (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt),
169 (void**)&ef->ef_hashtab);
170 if (error) {
171 warnx("can't read hash table");
172 return error;
173 }
174 ef->ef_buckets = ef->ef_hashtab;
175 ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
176 break;
177 case DT_STRTAB:
178 ef->ef_stroff = dp->d_un.d_ptr;
179 break;
180 case DT_STRSZ:
181 ef->ef_strsz = dp->d_un.d_val;
182 break;
183 case DT_SYMTAB:
184 ef->ef_symoff = dp->d_un.d_ptr;
185 break;
186 case DT_SYMENT:
187 if (dp->d_un.d_val != sizeof(Elf_Sym))
188 return EFTYPE;
189 break;
190 }
191 }
192 if (ef->ef_symoff == 0) {
193 warnx("%s: no .dynsym section found\n", ef->ef_name);
194 return EFTYPE;
195 }
196 if (ef->ef_stroff == 0) {
197 warnx("%s: no .dynstr section found\n", ef->ef_name);
198 return EFTYPE;
199 }
200 if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff),
201 ef->ef_nchains * sizeof(Elf_Sym),
202 (void**)&ef->ef_symtab) != 0) {
203 if (ef->ef_verbose)
204 warnx("%s: can't load .dynsym section (0x%lx)",
205 ef->ef_name, (long)ef->ef_symoff);
206 return EIO;
207 }
208 if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz,
209 (void**)&ef->ef_strtab) != 0) {
210 warnx("can't load .dynstr section");
211 return EIO;
212 }
213 return 0;
214}
215
216int
217ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
218{
219 ssize_t r;
220
221 if (offset != (Elf_Off)-1) {
222 if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
223 return EIO;
224 }
225
226 r = read(ef->ef_fd, dest, len);
227 if (r != -1 && (size_t)r == len)
228 return 0;
229 else
230 return EIO;
231}
232
233int
234ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
235{
236 int error;
237
238 *ptr = malloc(len);
239 if (*ptr == NULL)
240 return ENOMEM;
241 error = ef_read(ef, offset, len, *ptr);
242 if (error)
243 free(*ptr);
244 return error;
245}
246
247int
248ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
249{
250 u_long ofs = ef_get_offset(ef, offset);
251
252 if (ofs == 0) {
253 if (ef->ef_verbose)
254 warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
255 ef->ef_name, (long)offset, ofs);
256 return EFAULT;
257 }
258 return ef_read(ef, ofs, len, dest);
259}
260
261int
262ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
263{
264 int error;
265
266 *ptr = malloc(len);
267 if (*ptr == NULL)
268 return ENOMEM;
269 error = ef_seg_read(ef, offset, len, *ptr);
270 if (error)
271 free(*ptr);
272 return error;
273}
274
275int
276ef_open(const char *filename, elf_file_t ef, int verbose)
277{
278 Elf_Ehdr *hdr;
279 int fd;
280 int error;
281 int phlen, res;
282 int nsegs;
283 Elf_Phdr *phdr, *phdyn, *phphdr, *phlimit;
284
285 bzero(ef, sizeof(*ef));
286 if (filename == NULL)
287 return EFTYPE;
288 ef->ef_verbose = verbose;
289 if ((fd = open(filename, O_RDONLY)) == -1)
290 return errno;
291 ef->ef_fd = fd;
292 ef->ef_name = strdup(filename);
293 hdr = (Elf_Ehdr *)&ef->ef_hdr;
294 do {
295 res = read(fd, hdr, sizeof(*hdr));
296 error = EFTYPE;
297 if (res != sizeof(*hdr))
298 break;
299 if (!IS_ELF(*hdr))
300 break;
301 if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
302 hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
303 hdr->e_ident[EI_VERSION] != EV_CURRENT ||
304 hdr->e_version != EV_CURRENT ||
305 hdr->e_machine != ELF_TARG_MACH ||
306 hdr->e_phentsize != sizeof(Elf_Phdr))
307 break;
308 phlen = hdr->e_phnum * sizeof(Elf_Phdr);
309 if (ef_read_entry(ef, hdr->e_phoff, phlen,
310 (void**)&ef->ef_ph) != 0)
311 break;
312 phdr = ef->ef_ph;
313 phlimit = phdr + hdr->e_phnum;
314 nsegs = 0;
315 phdyn = NULL;
316 phphdr = NULL;
317 while (phdr < phlimit) {
318 if (verbose > 1)
319 ef_print_phdr(phdr);
320 switch (phdr->p_type) {
321 case PT_LOAD:
322 if (nsegs == 2) {
323 warnx("%s: too many sections",
324 filename);
325 break;
326 }
327 ef->ef_segs[nsegs++] = phdr;
328 break;
329 case PT_PHDR:
330 phphdr = phdr;
331 break;
332 case PT_DYNAMIC:
333 phdyn = phdr;
334 break;
335 }
336 phdr++;
337 }
338 if (verbose > 1)
339 printf("\n");
340 ef->ef_nsegs = nsegs;
341 if (phdyn == NULL) {
342 warnx("file isn't dynamically-linked");
343 break;
344 }
345 if (ef_read_entry(ef, phdyn->p_offset,
346 phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) {
347 printf("ef_read_entry failed\n");
348 break;
349 }
350 error = ef_parse_dynamic(ef);
351 if (error)
352 break;
353 if (hdr->e_type == ET_DYN) {
354 ef->ef_type = EFT_KLD;
355/* pad = (u_int)dest & PAGE_MASK;
356 if (pad)
357 dest += PAGE_SIZE - pad;*/
358 error = 0;
359 } else if (hdr->e_type == ET_EXEC) {
360/* dest = hdr->e_entry;
361 if (dest == 0)
362 break;*/
363 ef->ef_type = EFT_KERNEL;
364 error = 0;
365 } else
366 break;
367 } while(0);
368 if (error) {
369 ef_close(ef);
370 if (ef->ef_verbose)
371 warnc(error, "elf_open(%s)", filename);
372 }
373 return error;
374}
375
376int
377ef_close(elf_file_t ef)
378{
379 close(ef->ef_fd);
380/* if (ef->ef_fpage)
381 free(ef->ef_fpage);*/
382 if (ef->ef_name)
383 free(ef->ef_name);
384 return 0;
385}