1 /*	$OpenBSD: db_aout.c,v 1.28 2002/03/14 01:26:51 millert Exp $	*/
2 /*	$NetBSD: db_aout.c,v 1.29 2000/07/07 21:55:18 jhawk Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/proc.h>
34 
35 #include <machine/db_machdep.h>		/* data types */
36 
37 #include <ddb/db_sym.h>
38 #include <ddb/db_output.h>
39 #include <ddb/db_extern.h>
40 
41 #ifdef	DB_AOUT_SYMBOLS
42 
43 #include <ddb/db_aout.h>
44 
45 boolean_t	db_aout_sym_init(int, void *, void *, const char *);
46 db_sym_t	db_aout_lookup(db_symtab_t *, char *);
47 db_sym_t	db_aout_search_symbol(db_symtab_t *, db_addr_t,
48 		    db_strategy_t, db_expr_t *);
49 void		db_aout_symbol_values(db_symtab_t *, db_sym_t,
50 		    char **, db_expr_t *);
51 boolean_t	db_aout_line_at_pc(db_symtab_t *, db_sym_t,
52 		    char **, int *, db_expr_t);
53 boolean_t	db_aout_sym_numargs(db_symtab_t *, db_sym_t, int *,
54 		    char **);
55 void		db_aout_forall(db_symtab_t *,
56 		    db_forall_func_t db_forall_func, void *);
57 
58 db_symformat_t db_symformat_aout = {
59 	"a.out",
60 	db_aout_sym_init,
61 	db_aout_lookup,
62 	db_aout_search_symbol,
63 	db_aout_symbol_values,
64 	db_aout_line_at_pc,
65 	db_aout_sym_numargs,
66 	db_aout_forall
67 };
68 
69 /*
70  * An a.out symbol table as loaded into the kernel debugger:
71  *
72  * symtab	-> size of symbol entries, in bytes
73  * sp		-> first symbol entry
74  *		   ...
75  * ep		-> last symbol entry + 1
76  * strtab	== start of string table
77  *		   size of string table in bytes,
78  *		   including this word
79  *		-> strings
80  */
81 static char *strtab;
82 static int slen;
83 
84 #define X_db_getname(t, s)	(s->n_un.n_strx ? t->end + s->n_un.n_strx : NULL)
85 
86 /* XXX */
87 #ifndef ALIGNED_POINTER
88 #define ALIGNED_POINTER(p,t)        ((((u_long)(p)) & (sizeof(t)-1)) == 0)
89 #endif
90 
91 /*
92  * Find the symbol table and strings; tell ddb about them.
93  */
94 boolean_t
db_aout_sym_init(symsize,vsymtab,vesymtab,name)95 db_aout_sym_init(symsize, vsymtab, vesymtab, name)
96 	int symsize;		/* size of symbol table */
97 	void *vsymtab;		/* pointer to start of symbol table */
98 	void *vesymtab;		/* pointer to end of string table,
99 				   for checking - rounded up to integer
100 				   boundary */
101 	const char *name;
102 {
103 	struct nlist	*sym_start, *sym_end;
104 	struct nlist	*sp;
105 	int bad = 0;
106 	char *estrtab;
107 
108 	/*
109 	 * XXX - ddb_init should take arguments.
110 	 *       Fixup the arguments.
111 	 */
112 	symsize = *(long *)vsymtab;
113 	vsymtab = (void *)((long *)vsymtab + 1);
114 
115 
116 	if (ALIGNED_POINTER(vsymtab, long) == 0) {
117 		printf("[ %s symbol table has bad start address %p ]\n",
118 		    name, vsymtab);
119 		return (FALSE);
120 	}
121 
122 	/*
123 	 * Find pointers to the start and end of the symbol entries,
124 	 * given a pointer to the start of the symbol table.
125 	 */
126 	sym_start = (struct nlist *)vsymtab;
127 	sym_end   = (struct nlist *)((char *)sym_start + symsize);
128 
129 	strtab = (char *)sym_end;
130 	if (ALIGNED_POINTER(strtab, int) == 0) {
131 		printf("[ %s symbol table has bad string table address %p ]\n",
132 		    name, strtab);
133 		return (FALSE);
134 	}
135 	slen = *(int *)strtab;
136 
137 	estrtab = strtab + slen;
138 
139 #define	round_to_size(x) \
140     (((vaddr_t)(x) + sizeof(vsize_t) - 1) & ~(sizeof(vsize_t) - 1))
141 
142 	if (round_to_size(estrtab) != round_to_size(vesymtab)) {
143 		printf("[ %s a.out symbol table not valid ]\n", name);
144 		return (FALSE);
145         }
146 #undef	round_to_size
147 
148 	for (sp = sym_start; sp < sym_end; sp++) {
149 		int strx;
150 		strx = sp->n_un.n_strx;
151 		if (strx != 0) {
152 			if (strx > slen) {
153 				printf("[ %s has bad a.out string table index "
154 				    "(0x%x) ]\n",
155 				    name, strx);
156 				bad = 1;
157 				continue;
158 			}
159 		}
160 	}
161 
162 	if (bad)
163 		return (FALSE);
164 
165 	if (db_add_symbol_table((char *)sym_start, (char *)sym_end, name,
166 	    NULL) !=  -1) {
167                 printf("[ using %ld bytes of %s a.out symbol table ]\n",
168                     (long)vesymtab - (long)vsymtab, name);
169 		return (TRUE);
170         }
171 
172 	return (FALSE);
173 }
174 
175 db_sym_t
db_aout_lookup(stab,symstr)176 db_aout_lookup(stab, symstr)
177 	db_symtab_t	*stab;
178 	char *		symstr;
179 {
180 	struct nlist *sp, *ep;
181 	char *n_name;
182 
183 	sp = (struct nlist *)stab->start;
184 	ep = (struct nlist *)stab->end;
185 
186 	for (; sp < ep; sp++) {
187 		if ((n_name = X_db_getname(stab, sp)) == 0)
188 			continue;
189 		if ((sp->n_type & N_STAB) == 0 &&
190 		    db_eqname(n_name, symstr, '_'))
191 			return ((db_sym_t)sp);
192 	}
193 	return ((db_sym_t)0);
194 }
195 
196 db_sym_t
db_aout_search_symbol(symtab,off,strategy,diffp)197 db_aout_search_symbol(symtab, off, strategy, diffp)
198 	db_symtab_t *	symtab;
199 	db_addr_t	off;
200 	db_strategy_t	strategy;
201 	db_expr_t	*diffp;		/* in/out */
202 {
203 	unsigned int	diff = *diffp;
204 	struct nlist	*symp = 0;
205 	struct nlist	*sp, *ep;
206 
207 	sp = (struct nlist *)symtab->start;
208 	ep = (struct nlist *)symtab->end;
209 
210 	for (; sp < ep; sp++) {
211 		if ((sp->n_type & N_STAB) != 0 ||
212 		    (sp->n_type & N_TYPE) == N_FN)
213 			continue;
214 		if (X_db_getname(symtab, sp) == 0)
215 			continue;
216 		if (off >= sp->n_value) {
217 			if (off - sp->n_value < diff) {
218 				diff = off - sp->n_value;
219 				symp = sp;
220 				if (diff == 0 && ((strategy == DB_STGY_PROC &&
221 				    sp->n_type == (N_TEXT|N_EXT)) ||
222 				    (strategy == DB_STGY_ANY &&
223 				    (sp->n_type & N_EXT))))
224 					break;
225 			} else if (off - sp->n_value == diff) {
226 				if (symp == 0)
227 					symp = sp;
228 				else if ((symp->n_type & N_EXT) == 0 &&
229 				    (sp->n_type & N_EXT) != 0)
230 					symp = sp;	/* pick the ext. sym */
231 			}
232 		}
233 	}
234 	if (symp == 0) {
235 		*diffp = off;
236 	} else {
237 		*diffp = diff;
238 	}
239 	return ((db_sym_t)symp);
240 }
241 
242 /*
243  * Return the name and value for a symbol.
244  */
245 void
db_aout_symbol_values(symtab,sym,namep,valuep)246 db_aout_symbol_values(symtab, sym, namep, valuep)
247 	db_symtab_t	*symtab;
248 	db_sym_t	sym;
249 	char		**namep;
250 	db_expr_t	*valuep;
251 {
252 	struct nlist *sp;
253 
254 	sp = (struct nlist *)sym;
255 	if (namep)
256 		*namep = X_db_getname(symtab, sp);
257 	if (valuep)
258 		*valuep = sp->n_value;
259 }
260 
261 
262 boolean_t
db_aout_line_at_pc(symtab,cursym,filename,linenum,off)263 db_aout_line_at_pc(symtab, cursym, filename, linenum, off)
264 	db_symtab_t *	symtab;
265 	db_sym_t	cursym;
266 	char 		**filename;
267 	int 		*linenum;
268 	db_expr_t	off;
269 {
270 	struct nlist	*sp, *ep;
271 	unsigned long	sodiff = -1UL, lndiff = -1UL, ln = 0;
272 	char		*fname = NULL;
273 
274 	sp = (struct nlist *)symtab->start;
275 	ep = (struct nlist *)symtab->end;
276 
277 /* XXX - gcc specific */
278 #define NEWSRC(str)	((str) != NULL && \
279     (str)[0] == 'g' && strcmp((str), "gcc_compiled.") == 0)
280 
281 	for (; sp < ep; sp++) {
282 
283 		/*
284 		 * Prevent bogus linenumbers in case module not compiled
285 		 * with debugging options
286 		 */
287 #if 0
288 		if (sp->n_value <= off && (off - sp->n_value) <= sodiff &&
289 		    NEWSRC(X_db_getname(symtab, sp))) {
290 #endif
291 		if ((sp->n_type & N_TYPE) == N_FN ||
292 		    NEWSRC(X_db_getname(symtab, sp))) {
293 			sodiff = lndiff = -1UL;
294 			ln = 0;
295 			fname = NULL;
296 		}
297 
298 		if (sp->n_type == N_SO) {
299 			if (sp->n_value <= off &&
300 			    (off - sp->n_value) < sodiff) {
301 				sodiff = off - sp->n_value;
302 				fname = X_db_getname(symtab, sp);
303 			}
304 			continue;
305 		}
306 
307 		if (sp->n_type != N_SLINE)
308 			continue;
309 
310 		if (sp->n_value > off)
311 			break;
312 
313 		if (off - sp->n_value < lndiff) {
314 			lndiff = off - sp->n_value;
315 			ln = sp->n_desc;
316 		}
317 	}
318 
319 	if (fname != NULL && ln != 0) {
320 		*filename = fname;
321 		*linenum = ln;
322 		return (TRUE);
323 	}
324 
325 	return (FALSE);
326 }
327 
328 boolean_t
db_aout_sym_numargs(symtab,cursym,nargp,argnamep)329 db_aout_sym_numargs(symtab, cursym, nargp, argnamep)
330 	db_symtab_t *	symtab;
331 	db_sym_t	cursym;
332 	int		*nargp;
333 	char		**argnamep;
334 {
335 	struct nlist	*sp, *ep;
336 	u_long		addr;
337 	int		maxnarg = *nargp, nargs = 0;
338 	char		*n_name;
339 
340 	if (cursym == NULL)
341 		return (FALSE);
342 
343 	addr = ((struct nlist *)cursym)->n_value;
344 	sp = (struct nlist *)symtab->start;
345 	ep = (struct nlist *)symtab->end;
346 
347 	for (; sp < ep; sp++) {
348 		if (sp->n_type == N_FUN && sp->n_value == addr) {
349 			while (++sp < ep && sp->n_type == N_PSYM) {
350 				if (nargs >= maxnarg)
351 					break;
352 				nargs++;
353 				n_name = X_db_getname(symtab, sp);
354 				*argnamep++ = n_name ? n_name : "???";
355 				{
356 					/* XXX - remove trailers */
357 					char *cp = *(argnamep - 1);
358 
359 					while (*cp != '\0' && *cp != ':')
360 						cp++;
361 					if (*cp == ':') *cp = '\0';
362 				}
363 			}
364 			*nargp = nargs;
365 			return (TRUE);
366 		}
367 	}
368 	return (FALSE);
369 }
370 
371 void
db_aout_forall(stab,db_forall_func,arg)372 db_aout_forall(stab, db_forall_func, arg)
373 	db_symtab_t		*stab;
374 	db_forall_func_t	db_forall_func;
375 	void			*arg;
376 {
377 	static char suffix[2];
378 	struct nlist *sp, *ep;
379 
380 	sp = (struct nlist *)stab->start;
381 	ep = (struct nlist *)stab->end;
382 
383 	for (; sp < ep; sp++) {
384 		if (X_db_getname(stab, sp) == 0)
385 			continue;
386 		if ((sp->n_type & N_STAB) == 0) {
387 			suffix[1] = '\0';
388 			switch(sp->n_type & N_TYPE) {
389 			case N_ABS:
390 				suffix[0] = '@';
391 				break;
392 			case N_TEXT:
393 				suffix[0] = '*';
394 				break;
395 			case N_DATA:
396 				suffix[0] = '+';
397 				break;
398 			case N_BSS:
399 				suffix[0] = '-';
400 				break;
401 			case N_FN:
402 				suffix[0] = '/';
403 				break;
404 			default:
405 				suffix[0] = '\0';
406 			}
407 			(*db_forall_func)(stab, (db_sym_t)sp,
408 			    X_db_getname(stab, sp), suffix, '_', arg);
409 		}
410 	}
411 	return;
412 }
413 
414 
415 #endif	/* DB_AOUT_SYMBOLS */
416