Annotation of src/usr.bin/pmdb/aout_syms.c, Revision 1.5
1.5 ! fgsch 1: /* $OpenBSD: aout_syms.c,v 1.4 2002/03/19 21:17:52 fgsch Exp $ */
1.1 art 2: /*
3: * Copyright (c) 2002 Federico Schwindt <fgsch@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 <sys/types.h>
39: #include <a.out.h>
40: #include <link.h>
41:
42: #include "pmdb.h"
43: #include "symbol.h"
44:
45: #if defined(__OpenBSD__) && (OpenBSD < 200106)
46: /* OpenBSD prior to 2.9 have a broken pread on big-endian archs. */
47: #define IGNORE_PREAD_ERRORS
48: #endif
49:
50: struct aout_symbol_handle {
51: struct sym_table ash_st;
52: int ash_fd;
53: char *ash_strtab;
54: u_int32_t ash_strsize;
55: struct nlist *ash_symtab;
56: int ash_symsize;
57: };
58:
59: #define ASH_TO_ST(ash) (&(ash)->ash_st)
60: #define ST_TO_ASH(st) ((struct aout_symbol_handle *)(st))
61:
62: struct sym_table *aout_open(const char *);
63: void aout_close(struct sym_table *);
64: char *aout_name_and_off(struct sym_table *, reg, reg *);
65: int aout_lookup(struct pstate *, const char *, reg *);
66: void aout_update(struct pstate *);
67:
68: struct sym_ops aout_sops = {
69: aout_open,
70: aout_close,
71: aout_name_and_off,
72: aout_lookup,
73: aout_update
74: };
75:
76: int
77: sym_check_aout(const char *name, struct pstate *ps)
78: {
79: struct exec ahdr;
1.4 fgsch 80: int error = 0;
1.1 art 81: int fd;
82:
83: if ((fd = open(name, O_RDONLY)) < 0)
1.4 fgsch 84: return (1);
1.1 art 85:
86: if (pread(fd, &ahdr, sizeof(ahdr), 0) != sizeof(ahdr)) {
87: #ifndef IGNORE_PREAD_ERRORS
1.4 fgsch 88: error = 1;
1.1 art 89: #endif
90: }
91:
1.5 ! fgsch 92: if (!error && N_BADMAG(ahdr)) {
1.4 fgsch 93: error = 1;
1.1 art 94: }
95:
96: close(fd);
97:
1.4 fgsch 98: if (!error)
99: ps->ps_sops = &aout_sops;
1.1 art 100:
1.4 fgsch 101: return (error);
1.1 art 102: }
103:
104: struct sym_table *
105: aout_open(const char *name)
106: {
107: struct aout_symbol_handle *ash;
108: u_int32_t symoff, stroff;
109: struct exec ahdr;
110:
111: if ((ash = malloc(sizeof(*ash))) == NULL) {
112: return NULL;
113: }
114:
115: memset(ash, 0, sizeof(*ash));
116: ash->ash_fd = -1;
117:
118: if ((ash->ash_fd = open(name, O_RDONLY)) < 0) {
119: warn("open(%s)", name);
120: goto fail;
121: }
122:
123: if (pread(ash->ash_fd, &ahdr, sizeof(ahdr), 0) != sizeof(ahdr)) {
124: #ifndef IGNORE_PREAD_ERRORS
125: warn("pread(header)");
126: goto fail;
127: #endif
128: }
129:
130: if (N_BADMAG(ahdr)) {
131: warnx("Bad magic.");
132: goto fail;
133: }
134:
135: symoff = N_SYMOFF(ahdr);
136: ash->ash_symsize = ahdr.a_syms;
137: stroff = N_STROFF(ahdr);
138:
139: if (pread(ash->ash_fd, &ash->ash_strsize, sizeof(u_int32_t),
140: stroff) != sizeof(u_int32_t)) {
141: #ifndef IGNORE_PREAD_ERRORS
142: warn("pread(strsize)");
143: goto fail;
144: #endif
145: }
146:
147: if ((ash->ash_strtab = mmap(NULL, ash->ash_strsize, PROT_READ,
148: MAP_SHARED, ash->ash_fd, stroff)) == MAP_FAILED) {
149: warn("mmap(strtab)");
150: goto fail;
151: }
152:
153: if ((ash->ash_symtab = mmap(NULL, ash->ash_symsize, PROT_READ,
154: MAP_SHARED, ash->ash_fd, symoff)) == MAP_FAILED) {
155: warn("mmap(symtab)");
156: goto fail;
157: }
158:
159: return (ASH_TO_ST(ash));
160: fail:
161:
162: aout_close(ASH_TO_ST(ash));
163: return (NULL);
164: }
165:
166: void
167: aout_close(struct sym_table *st)
168: {
169: struct aout_symbol_handle *ash = ST_TO_ASH(st);
170:
171: if (ash->ash_fd != -1)
172: close(ash->ash_fd);
173:
174: munmap(ash->ash_strtab, ash->ash_strsize);
175: munmap(ash->ash_symtab, ash->ash_symsize);
176: free(ash);
177: }
178:
179: char *
180: aout_name_and_off(struct sym_table *st, reg pc, reg *offs)
181: {
182: struct aout_symbol_handle *ash = ST_TO_ASH(st);
183: struct nlist *s, *bests = NULL;
184: int bestoff = 0;
185: int nsyms, i;
186: char *symn;
187:
1.3 art 188: #define SYMVAL(S) (unsigned long)((S)->n_value + st->st_offs)
1.1 art 189:
190: nsyms = ash->ash_symsize / sizeof(struct nlist);
191:
192: bests = NULL;
193: for (i = 0; i < nsyms; i++) {
194: s = &ash->ash_symtab[i];
195:
196: if (s->n_value == 0 ||
197: s->n_un.n_strx == 0)
198: continue;
199:
200: symn = &ash->ash_strtab[s->n_un.n_strx];
201: if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
202: symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
203: bests = s;
204: bestoff = SYMVAL(s);
205: }
206: }
207:
208: if ((s = bests) == NULL)
209: return (NULL);
210:
211: *offs = pc - SYMVAL(s);
212:
213: return &ash->ash_strtab[s->n_un.n_strx];
214: }
215:
216: static struct nlist *
217: aout_lookup_table(struct aout_symbol_handle *ash, const char *name)
218: {
219: int nsyms, i;
220: char *symn;
221: struct nlist *s = NULL;
222:
223: nsyms = ash->ash_symsize / sizeof(struct nlist);
224: for (i = 0; i < nsyms; i++) {
225: s = &ash->ash_symtab[i];
226: symn = &ash->ash_strtab[s->n_un.n_strx];
227: if (strcmp(name, symn) == 0)
228: break;
229: }
230:
231: if (i == nsyms)
232: return (NULL);
233:
234: return (s);
235: }
236:
237: int
238: aout_lookup(struct pstate *ps, const char *name, reg *res)
239: {
240: struct sym_table *st;
241: struct nlist *s;
242: int first = 1;
243: char *sname = (char *)name;
244:
245: restart:
246: TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
247: if ((s = aout_lookup_table(ST_TO_ASH(st), sname)) != NULL)
248: break;
249: }
250:
251: if (!first)
252: free(sname);
253:
254: if (s == NULL) {
255: if (first) {
256: asprintf(&sname, "_%s", sname);
257: if (sname != NULL) {
258: first = 0;
259: goto restart;
260: }
261: }
262:
263: return (-1);
264: }
265:
1.3 art 266: *res = s->n_value + st->st_offs;
1.1 art 267: return (0);
268: }
269:
270: /*
271: * Called after execution started so that we can load any dynamic symbols.
272: */
273: void
274: aout_update(struct pstate *ps)
275: {
276: pid_t pid = ps->ps_pid;
277: struct _dynamic dyn;
278: struct so_debug sdeb;
279: struct section_dispatch_table sdt;
280: struct so_map som;
281: off_t somp;
282: reg addr;
283: struct nlist *s;
284:
285: if ((s = aout_lookup_table(ST_TO_ASH(ps->ps_sym_exe), "__DYNAMIC")) == NULL) {
286: warnx("Can't find __DYNAMIC");
287: return;
288: }
1.3 art 289: addr = s->n_value + ps->ps_sym_exe->st_offs;
1.1 art 290:
291: if (read_from_pid(pid, addr, &dyn, sizeof(dyn)) < 0) {
292: warn("Can't read __DYNAMIC");
293: return;
294: }
295:
296: if (dyn.d_version != LD_VERSION_BSD) {
297: warn("Can't handle __DYNAMIC version %d", dyn.d_version);
298: return;
299: }
300:
301: if (read_from_pid(pid, (off_t)(reg)dyn.d_debug, &sdeb, sizeof(sdeb)) < 0) {
302: warn("Can't read __DYNAMIC.d_debug");
303: return;
304: }
305:
306: if (sdeb.dd_version != 0) {
307: warn("Can't handle so_debug version %d", sdeb.dd_version);
308: return;
309: }
310:
311: if (read_from_pid(pid, (off_t)(reg)dyn.d_un.d_sdt, &sdt, sizeof(sdt)) < 0) {
312: warn("Can't read section dispatch table");
313: return;
314: }
315:
316: somp = (off_t)(reg)sdt.sdt_loaded;
317: while (somp) {
318: char fname[MAXPATHLEN];
319: int i;
320:
321: if (read_from_pid(pid, somp, &som, sizeof(som)) < 0) {
322: warn("Can't read so_map");
323: break;
324: }
325: somp = (off_t)(reg)som.som_next;
326: if (read_from_pid(pid, (off_t)(reg)som.som_path, fname,
327: sizeof(fname)) < 0) {
328: warn("Can't read so filename");
329: continue;
330: }
331:
332: /* sanity check the file name */
333: for (i = 0; i < MAXPATHLEN; i++)
334: if (fname[i] == '\0')
335: break;
336: if (i == MAXPATHLEN) {
337: warnx("so filename invalid");
338: continue;
339: }
340:
1.3 art 341: if (st_open(ps, fname, (reg)som.som_addr) == NULL)
1.1 art 342: warn("symbol loading failed");
343: }
344: }