Annotation of src/usr.bin/pmdb/elf_syms.c, Revision 1.9
1.9 ! deraadt 1: /* $OpenBSD: elf_syms.c,v 1.8 2003/03/28 23:33:27 mickey Exp $ */
1.1 art 2: /*
3: * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <unistd.h>
30: #include <fcntl.h>
31: #include <string.h>
32: #include <err.h>
33:
34: #include <sys/param.h>
35: #include <sys/ptrace.h>
36: #include <sys/mman.h>
37:
38: #include <nlist.h>
39: #ifdef __NetBSD__
40: #include <machine/elf_machdep.h>
41: #define ELFSIZE ARCH_ELFSIZE
42: #include <sys/exec_elf.h>
43: #else
44: #include <elf_abi.h>
45: #endif
46: #include <link.h>
47:
48: #include "pmdb.h"
49: #include "symbol.h"
50: #include "break.h"
51:
52: struct elf_symbol_handle {
53: struct sym_table esh_st;
54: int esh_fd;
55: char *esh_strtab;
56: Elf_Word esh_strsize;
57: Elf_Sym *esh_symtab;
58: Elf_Word esh_symsize;
59: };
60:
61: #define ESH_TO_ST(esh) (&(esh)->esh_st)
62: #define ST_TO_ESH(st) ((struct elf_symbol_handle *)(st))
63:
64: struct sym_table *elf_open(const char *);
65: void elf_close(struct sym_table *);
66: char *elf_name_and_off(struct sym_table *, reg, reg *);
67: int elf_lookup(struct pstate *, const char *, reg *);
68: void elf_update(struct pstate *);
69:
70: struct sym_ops elf_sops = {
71: elf_open,
72: elf_close,
73: elf_name_and_off,
74: elf_lookup,
75: elf_update
76: };
77:
78: int
79: sym_check_elf(const char *name, struct pstate *ps)
80: {
81: Elf_Ehdr ehdr;
1.4 fgsch 82: int error = 0;
1.1 art 83: int fd;
84:
85: if ((fd = open(name, O_RDONLY)) < 0)
1.4 fgsch 86: return (1);
1.1 art 87:
88: if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr))
1.4 fgsch 89: error = 1;
1.1 art 90:
91: #ifndef __NetBSD__
1.5 fgsch 92: if (!error && (!IS_ELF(ehdr) ||
1.1 art 93: ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
94: ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
95: ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
96: ehdr.e_machine != ELF_TARG_MACH ||
1.5 fgsch 97: ehdr.e_version != ELF_TARG_VER))
1.4 fgsch 98: error = 1;
1.1 art 99: #endif
100:
101: close(fd);
102:
1.4 fgsch 103: if (!error)
104: ps->ps_sops = &elf_sops;
1.1 art 105:
1.4 fgsch 106: return (error);
1.1 art 107: }
108:
109: struct sym_table *
110: elf_open(const char *name)
111: {
112: struct elf_symbol_handle *esh;
113: Elf_Off symoff, stroff;
114: Elf_Ehdr ehdr;
115: Elf_Shdr *shdr;
116: int i, fd;
117:
118: /* Just a sanity check */
119: if (sizeof(reg) != sizeof(Elf_Addr))
120: errx(1, "sym_open: sizeof(reg) != sizeof(Elf_Addr)");
121:
122: if ((esh = malloc(sizeof(*esh))) == NULL) {
123: return (NULL);
124: }
125:
126: memset(esh, 0, sizeof(*esh));
127: esh->esh_fd = -1;
128:
129: if ((fd = esh->esh_fd = open(name, O_RDONLY)) < 0) {
130: goto fail;
131: }
132:
133: if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr)) {
134: goto fail;
135: }
136: #ifndef __NetBSD__
137: if (!IS_ELF(ehdr) ||
138: ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
139: ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
140: ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
141: ehdr.e_machine != ELF_TARG_MACH ||
142: ehdr.e_version != ELF_TARG_VER) {
143: goto fail;
144: }
145: #endif
146:
147: if ((shdr = (Elf_Shdr *)mmap(NULL, ehdr.e_shentsize * ehdr.e_shnum,
148: PROT_READ, MAP_SHARED, fd, ehdr.e_shoff)) == MAP_FAILED) {
149: goto fail;
150: }
151:
152: for (i = 0; i < ehdr.e_shnum; i++) {
153: if (shdr[i].sh_type == SHT_SYMTAB) {
154: symoff = shdr[i].sh_offset;
155: esh->esh_symsize = shdr[i].sh_size;
156: stroff = shdr[shdr[i].sh_link].sh_offset;
157: esh->esh_strsize = shdr[shdr[i].sh_link].sh_size;
158: break;
159: }
160: }
161:
162: munmap(shdr, ehdr.e_shentsize * ehdr.e_shnum);
163:
164: if (i == ehdr.e_shnum) {
165: goto fail;
166: }
167:
1.8 mickey 168: if (esh->esh_symsize) {
169:
170: if ((esh->esh_strtab = mmap(NULL, esh->esh_strsize, PROT_READ,
171: MAP_SHARED, fd, stroff)) == MAP_FAILED) {
172: goto fail;
173: }
1.1 art 174:
1.8 mickey 175: if ((esh->esh_symtab = mmap(NULL, esh->esh_symsize, PROT_READ,
176: MAP_SHARED, fd, symoff)) == MAP_FAILED) {
177: goto fail;
178: }
1.1 art 179: }
180:
181: return (ESH_TO_ST(esh));
182: fail:
183:
184: elf_close(ESH_TO_ST(esh));
185: return (NULL);
186: }
187:
188: void
189: elf_close(struct sym_table *st)
190: {
191: struct elf_symbol_handle *esh = ST_TO_ESH(st);
192:
193: if (esh->esh_fd != -1)
194: close(esh->esh_fd);
195:
196: munmap(esh->esh_strtab, esh->esh_strsize);
197: munmap(esh->esh_symtab, esh->esh_symsize);
198: free(esh);
199: }
200:
201: char *
202: elf_name_and_off(struct sym_table *st, reg pc, reg *offs)
203: {
204: struct elf_symbol_handle *esh = ST_TO_ESH(st);
205: Elf_Sym *s, *bests = NULL;
206: Elf_Addr bestoff = 0;
207: int nsyms, i;
208: char *symn;
209:
1.8 mickey 210: if (esh == NULL)
211: return (NULL);
212:
1.3 art 213: #define SYMVAL(S) (unsigned long)((S)->st_value + st->st_offs)
1.1 art 214:
215: nsyms = esh->esh_symsize / sizeof(Elf_Sym);
216:
217: bests = NULL;
218: for (i = 0; i < nsyms; i++) {
219: s = &esh->esh_symtab[i];
220:
221: if (s->st_value == 0 ||
222: s->st_shndx == 0 ||
223: (ELF_ST_BIND(s->st_info) != STB_GLOBAL &&
224: ELF_ST_BIND(s->st_info) != STB_WEAK &&
225: ELF_ST_BIND(s->st_info) != STB_LOCAL))
226: continue;
227: symn = &esh->esh_strtab[s->st_name];
228: if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
229: symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
230: bests = s;
231: bestoff = SYMVAL(s);
232: }
233: }
234:
235: if ((s = bests) == NULL)
236: return (NULL);
237:
238: *offs = pc - SYMVAL(s);
239:
240: return &esh->esh_strtab[s->st_name];
241: }
242:
243: static Elf_Sym *
244: elf_lookup_table(struct elf_symbol_handle *esh, const char *name)
245: {
246: int nsyms, i;
247: char *symn;
248: Elf_Sym *s = NULL;
1.8 mickey 249:
250: if (esh == NULL)
251: return (NULL);
1.1 art 252:
253: /* XXX - dumb, doesn't follow the rules (weak, hash, etc.). */
254: nsyms = esh->esh_symsize / sizeof(Elf_Sym);
255: for (i = 0; i < nsyms; i++) {
256: s = &esh->esh_symtab[i];
257: symn = &esh->esh_strtab[s->st_name];
258: if (strcmp(name, symn) == 0)
259: break;
260: }
261: if (i == nsyms)
262: return (NULL);
263:
264: return (s);
265: }
266:
267: int
268: elf_lookup(struct pstate *ps, const char *name, reg *res)
269: {
270: struct sym_table *st;
1.9 ! deraadt 271: Elf_Sym *s = NULL;
1.1 art 272:
273: TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
274: if ((s = elf_lookup_table(ST_TO_ESH(st), name)) != NULL)
275: break;
276: }
277:
278: if (s != NULL) {
1.3 art 279: *res = s->st_value + st->st_offs;
1.1 art 280: return (0);
281: }
282:
283: return (-1);
284: }
285:
286: #ifndef __NetBSD__
287: struct elf_object_v1 {
288: Elf_Addr load_addr;
289: Elf_Addr load_offs;
290: char *load_name;
291: Elf_Dyn *load_dyn;
292: struct elf_object_v1 *next;
293: struct elf_object_v1 *prev;
294: void *load_list;
295: u_int32_t load_size;
296: u_long info[DT_NUM + DT_PROCNUM];
297: struct elf_object_v1 *dep_next;
298: int status;
299: Elf_Phdr *phdrp;
300: int phdrc;
301: int refcount;
302: int obj_type;
303: #define EOBJ1_LDR 1
304: #define EOBJ1_EXE 2
305: #define EOBJ1_LIB 3
306: #define EOBJ1_DLO 4
307: };
308: #endif
309:
310: /*
311: * dlopen breakpoint (XXX make this generic?)
312: */
313: int
314: sym_bkpt(struct pstate *ps, void *arg)
315: {
316: fprintf(stderr, "pmdb: shared lib changed\n");
317:
318: sym_update(ps);
319:
320: return BKPT_KEEP_CONT;
321: }
322:
1.7 art 323: /* Is the ABI really so daft that it doesn't include the linking offset? */
324: struct xlink_map {
325: struct link_map lm;
326: Elf_Addr a;
327: };
328:
1.1 art 329: /*
330: * Called after execution started so that we can load any dynamic symbols.
331: */
332: void
333: elf_update(struct pstate *ps)
334: {
335: #ifndef __NetBSD__
1.7 art 336: struct xlink_map xlm;
337: #define lm xlm.lm
1.1 art 338: struct r_debug rdeb;
339: reg addr;
340: Elf_Dyn dyn;
341: static int bkpt_set;
342: Elf_Sym *s;
343:
344: if ((s = elf_lookup_table(ST_TO_ESH(ps->ps_sym_exe), "_DYNAMIC")) == NULL) {
345: warnx("Can't find _DYNAMIC");
346: return;
347: }
1.3 art 348: addr = s->st_value + ps->ps_sym_exe->st_offs;
1.1 art 349:
350: do {
1.6 art 351: if (process_read(ps, addr, &dyn, sizeof(dyn)) < 0) {
1.1 art 352: warnx("Can't read _DYNAMIC");
353: return;
354: }
355: addr += sizeof(dyn);
356: } while (dyn.d_tag != 0 && dyn.d_tag != DT_DEBUG);
357:
358: if (dyn.d_tag == 0) {
359: warnx("Can't find DT_DEBUG");
360: return;
361: }
362:
1.6 art 363: if (process_read(ps, dyn.d_un.d_ptr, &rdeb, sizeof(rdeb)) < 0) {
1.1 art 364: warnx("Can't read DT_DEBUG");
365: return;
366: }
367:
368: if (rdeb.r_version != 1) {
369: warn("Can't handle debug map version %d", rdeb.r_version);
370: return;
371: }
372: if (rdeb.r_state != RT_CONSISTENT) {
373: warn("debug map not consistent: %d", rdeb.r_state);
374: return;
375: }
376:
377: if (!bkpt_set) {
378: if (bkpt_add_cb(ps, rdeb.r_brk, sym_bkpt, NULL))
379: warn("sym_exec: can't set bkpt");
380: bkpt_set = 1;
381: }
382:
383: addr = (Elf_Addr)rdeb.r_map;
384: while (addr != 0 && addr != -1) {
385: char fname[MAXPATHLEN];
386: int i;
387:
1.7 art 388: if (process_read(ps, addr, &xlm, sizeof(xlm)) < 0) {
1.1 art 389: warnx("Can't read symbols...");
390: return;
391: }
392:
1.7 art 393: addr = (Elf_Addr)lm.l_next;
1.1 art 394:
1.7 art 395: if (lm.l_name == NULL || lm.l_name == (char *)-1)
1.1 art 396: continue;
1.7 art 397: if (process_read(ps, (Elf_Addr)lm.l_name, fname,
1.1 art 398: sizeof(fname)) < 0) {
399: warnx("Can't read symbols...");
400: return;
401: }
402:
403: /* sanity check the file name */
404: for (i = 0; i < MAXPATHLEN; i++)
405: if (fname[i] == '\0')
406: break;
407: if (i == MAXPATHLEN)
408: continue;
409:
1.7 art 410: if (st_open(ps, fname, xlm.a) == NULL)
1.1 art 411: warn("symbol loading failed");
412: }
413: #endif
414: }