Annotation of src/usr.bin/pmdb/elf_syms.c, Revision 1.3
1.3 ! art 1: /* $OpenBSD: elf_syms.c,v 1.2 2002/03/15 16:41:06 jason 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;
82: int fd;
83:
84: if ((fd = open(name, O_RDONLY)) < 0)
85: return (-1);
86:
87: if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr))
88: return (-1);
89:
90: #ifndef __NetBSD__
91: if (!IS_ELF(ehdr) ||
92: ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
93: ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
94: ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
95: ehdr.e_machine != ELF_TARG_MACH ||
96: ehdr.e_version != ELF_TARG_VER)
97: return (-1);
98: #endif
99:
100: close(fd);
101:
102: ps->ps_sops = &elf_sops;
103:
104: return (0);
105: }
106:
107: struct sym_table *
108: elf_open(const char *name)
109: {
110: struct elf_symbol_handle *esh;
111: Elf_Off symoff, stroff;
112: Elf_Ehdr ehdr;
113: Elf_Shdr *shdr;
114: int i, fd;
115:
116: /* Just a sanity check */
117: if (sizeof(reg) != sizeof(Elf_Addr))
118: errx(1, "sym_open: sizeof(reg) != sizeof(Elf_Addr)");
119:
120: if ((esh = malloc(sizeof(*esh))) == NULL) {
121: return (NULL);
122: }
123:
124: memset(esh, 0, sizeof(*esh));
125: esh->esh_fd = -1;
126:
127: if ((fd = esh->esh_fd = open(name, O_RDONLY)) < 0) {
128: goto fail;
129: }
130:
131: if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr)) {
132: goto fail;
133: }
134: #ifndef __NetBSD__
135: if (!IS_ELF(ehdr) ||
136: ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
137: ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
138: ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
139: ehdr.e_machine != ELF_TARG_MACH ||
140: ehdr.e_version != ELF_TARG_VER) {
141: goto fail;
142: }
143: #endif
144:
145: if ((shdr = (Elf_Shdr *)mmap(NULL, ehdr.e_shentsize * ehdr.e_shnum,
146: PROT_READ, MAP_SHARED, fd, ehdr.e_shoff)) == MAP_FAILED) {
147: goto fail;
148: }
149:
150: for (i = 0; i < ehdr.e_shnum; i++) {
151: if (shdr[i].sh_type == SHT_SYMTAB) {
152: symoff = shdr[i].sh_offset;
153: esh->esh_symsize = shdr[i].sh_size;
154: stroff = shdr[shdr[i].sh_link].sh_offset;
155: esh->esh_strsize = shdr[shdr[i].sh_link].sh_size;
156: break;
157: }
158: }
159:
160: munmap(shdr, ehdr.e_shentsize * ehdr.e_shnum);
161:
162: if (i == ehdr.e_shnum) {
163: goto fail;
164: }
165:
166: if ((esh->esh_strtab = mmap(NULL, esh->esh_strsize, PROT_READ,
167: MAP_SHARED, fd, stroff)) == MAP_FAILED) {
168: goto fail;
169: }
170:
171: if ((esh->esh_symtab = mmap(NULL, esh->esh_symsize, PROT_READ,
172: MAP_SHARED, fd, symoff)) == MAP_FAILED) {
173: goto fail;
174: }
175:
176: return (ESH_TO_ST(esh));
177: fail:
178:
179: elf_close(ESH_TO_ST(esh));
180: return (NULL);
181: }
182:
183: void
184: elf_close(struct sym_table *st)
185: {
186: struct elf_symbol_handle *esh = ST_TO_ESH(st);
187:
188: if (esh->esh_fd != -1)
189: close(esh->esh_fd);
190:
191: munmap(esh->esh_strtab, esh->esh_strsize);
192: munmap(esh->esh_symtab, esh->esh_symsize);
193: free(esh);
194: }
195:
196: char *
197: elf_name_and_off(struct sym_table *st, reg pc, reg *offs)
198: {
199: struct elf_symbol_handle *esh = ST_TO_ESH(st);
200: Elf_Sym *s, *bests = NULL;
201: Elf_Addr bestoff = 0;
202: int nsyms, i;
203: char *symn;
204:
1.3 ! art 205: #define SYMVAL(S) (unsigned long)((S)->st_value + st->st_offs)
1.1 art 206:
207: nsyms = esh->esh_symsize / sizeof(Elf_Sym);
208:
209: bests = NULL;
210: for (i = 0; i < nsyms; i++) {
211: s = &esh->esh_symtab[i];
212:
213: if (s->st_value == 0 ||
214: s->st_shndx == 0 ||
215: (ELF_ST_BIND(s->st_info) != STB_GLOBAL &&
216: ELF_ST_BIND(s->st_info) != STB_WEAK &&
217: ELF_ST_BIND(s->st_info) != STB_LOCAL))
218: continue;
219: symn = &esh->esh_strtab[s->st_name];
220: if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
221: symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
222: bests = s;
223: bestoff = SYMVAL(s);
224: }
225: }
226:
227: if ((s = bests) == NULL)
228: return (NULL);
229:
230: *offs = pc - SYMVAL(s);
231:
232: return &esh->esh_strtab[s->st_name];
233: }
234:
235: static Elf_Sym *
236: elf_lookup_table(struct elf_symbol_handle *esh, const char *name)
237: {
238: int nsyms, i;
239: char *symn;
240: Elf_Sym *s = NULL;
241:
242: /* XXX - dumb, doesn't follow the rules (weak, hash, etc.). */
243: nsyms = esh->esh_symsize / sizeof(Elf_Sym);
244: for (i = 0; i < nsyms; i++) {
245: s = &esh->esh_symtab[i];
246: symn = &esh->esh_strtab[s->st_name];
247: if (strcmp(name, symn) == 0)
248: break;
249: }
250: if (i == nsyms)
251: return (NULL);
252:
253: return (s);
254: }
255:
256: int
257: elf_lookup(struct pstate *ps, const char *name, reg *res)
258: {
259: struct sym_table *st;
260: Elf_Sym *s;
261:
262: TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
263: if ((s = elf_lookup_table(ST_TO_ESH(st), name)) != NULL)
264: break;
265: }
266:
267: if (s != NULL) {
1.3 ! art 268: *res = s->st_value + st->st_offs;
1.1 art 269: return (0);
270: }
271:
272: return (-1);
273: }
274:
275: #ifndef __NetBSD__
276: struct elf_object_v1 {
277: Elf_Addr load_addr;
278: Elf_Addr load_offs;
279: char *load_name;
280: Elf_Dyn *load_dyn;
281: struct elf_object_v1 *next;
282: struct elf_object_v1 *prev;
283: void *load_list;
284: u_int32_t load_size;
285: u_long info[DT_NUM + DT_PROCNUM];
286: struct elf_object_v1 *dep_next;
287: int status;
288: Elf_Phdr *phdrp;
289: int phdrc;
290: int refcount;
291: int obj_type;
292: #define EOBJ1_LDR 1
293: #define EOBJ1_EXE 2
294: #define EOBJ1_LIB 3
295: #define EOBJ1_DLO 4
296: };
297: #endif
298:
299: /*
300: * dlopen breakpoint (XXX make this generic?)
301: */
302: int
303: sym_bkpt(struct pstate *ps, void *arg)
304: {
305: fprintf(stderr, "pmdb: shared lib changed\n");
306:
307: sym_update(ps);
308:
309: return BKPT_KEEP_CONT;
310: }
311:
312: /*
313: * Called after execution started so that we can load any dynamic symbols.
314: */
315: void
316: elf_update(struct pstate *ps)
317: {
318: #ifndef __NetBSD__
319: pid_t pid = ps->ps_pid;
320: struct elf_object_v1 eobj;
321: struct r_debug rdeb;
322: reg addr;
323: Elf_Dyn dyn;
324: static int bkpt_set;
325: Elf_Sym *s;
326:
327: if ((s = elf_lookup_table(ST_TO_ESH(ps->ps_sym_exe), "_DYNAMIC")) == NULL) {
328: warnx("Can't find _DYNAMIC");
329: return;
330: }
1.3 ! art 331: addr = s->st_value + ps->ps_sym_exe->st_offs;
1.1 art 332:
333: do {
334: if (read_from_pid(pid, addr, &dyn, sizeof(dyn)) < 0) {
335: warnx("Can't read _DYNAMIC");
336: return;
337: }
338: addr += sizeof(dyn);
339: } while (dyn.d_tag != 0 && dyn.d_tag != DT_DEBUG);
340:
341: if (dyn.d_tag == 0) {
342: warnx("Can't find DT_DEBUG");
343: return;
344: }
345:
346: if (read_from_pid(pid, dyn.d_un.d_ptr, &rdeb, sizeof(rdeb)) < 0) {
347: warnx("Can't read DT_DEBUG");
348: return;
349: }
350:
351: if (rdeb.r_version != 1) {
352: warn("Can't handle debug map version %d", rdeb.r_version);
353: return;
354: }
355: if (rdeb.r_state != RT_CONSISTENT) {
356: warn("debug map not consistent: %d", rdeb.r_state);
357: return;
358: }
359:
360: if (!bkpt_set) {
361: if (bkpt_add_cb(ps, rdeb.r_brk, sym_bkpt, NULL))
362: warn("sym_exec: can't set bkpt");
363: bkpt_set = 1;
364: }
365:
366: addr = (Elf_Addr)rdeb.r_map;
367: while (addr != 0 && addr != -1) {
368: char fname[MAXPATHLEN];
369: int i;
370:
371: if (read_from_pid(pid, addr, &eobj, sizeof(eobj)) < 0) {
372: warnx("Can't read symbols...");
373: return;
374: }
375:
376: addr = (Elf_Addr)eobj.next;
377:
378: if (eobj.load_name == NULL || eobj.load_name == (char *)-1)
379: continue;
380: if (read_from_pid(pid, (Elf_Addr)eobj.load_name, fname,
381: sizeof(fname)) < 0) {
382: warnx("Can't read symbols...");
383: return;
384: }
385:
386: /* sanity check the file name */
387: for (i = 0; i < MAXPATHLEN; i++)
388: if (fname[i] == '\0')
389: break;
390: if (i == MAXPATHLEN)
391: continue;
392:
1.3 ! art 393: if (st_open(ps, fname, eobj.load_offs) == NULL)
1.1 art 394: warn("symbol loading failed");
395: }
396: #endif
397: }