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