File: | obj-scan-build/../ddb/db_sym.c |
Location: | line 416, column 2 |
Description: | Access to field 'type' results in a dereference of a null pointer (loaded from variable 'stab') |
1 | /* | |||||
2 | * Mach Operating System | |||||
3 | * Copyright (c) 1992,1991,1990 Carnegie Mellon University | |||||
4 | * All Rights Reserved. | |||||
5 | * | |||||
6 | * Permission to use, copy, modify and distribute this software and its | |||||
7 | * documentation is hereby granted, provided that both the copyright | |||||
8 | * notice and this permission notice appear in all copies of the | |||||
9 | * software, derivative works or modified versions, and any portions | |||||
10 | * thereof, and that both notices appear in supporting documentation. | |||||
11 | * | |||||
12 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |||||
13 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |||||
14 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |||||
15 | * | |||||
16 | * Carnegie Mellon requests users of this software to return to | |||||
17 | * | |||||
18 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |||||
19 | * School of Computer Science | |||||
20 | * Carnegie Mellon University | |||||
21 | * Pittsburgh PA 15213-3890 | |||||
22 | * | |||||
23 | * any improvements or extensions that they make and grant Carnegie Mellon | |||||
24 | * the rights to redistribute these changes. | |||||
25 | */ | |||||
26 | /* | |||||
27 | * Author: David B. Golub, Carnegie Mellon University | |||||
28 | * Date: 7/90 | |||||
29 | */ | |||||
30 | ||||||
31 | #if MACH_KDB1 | |||||
32 | ||||||
33 | #include <string.h> | |||||
34 | #include <mach/std_types.h> | |||||
35 | #include <machine/db_machdep.h> | |||||
36 | #include <ddb/db_command.h> | |||||
37 | #include <ddb/db_output.h> | |||||
38 | #include <ddb/db_sym.h> | |||||
39 | #include <ddb/db_task_thread.h> | |||||
40 | #include <ddb/db_aout.h> | |||||
41 | #include <ddb/db_elf.h> | |||||
42 | ||||||
43 | #include <vm/vm_map.h> /* vm_map_t */ | |||||
44 | ||||||
45 | /* | |||||
46 | * Multiple symbol tables | |||||
47 | */ | |||||
48 | #define MAXNOSYMTABS5 5 /* mach, bootstrap, ux, emulator, 1 spare */ | |||||
49 | ||||||
50 | db_symtab_t db_symtabs[MAXNOSYMTABS5] = {{0,},}; | |||||
51 | int db_nsymtab = 0; | |||||
52 | ||||||
53 | db_symtab_t *db_last_symtab; | |||||
54 | ||||||
55 | /* | |||||
56 | * Add symbol table, with given name, to list of symbol tables. | |||||
57 | */ | |||||
58 | boolean_t | |||||
59 | db_add_symbol_table( | |||||
60 | int type, | |||||
61 | char *start, | |||||
62 | char *end, | |||||
63 | char *name, | |||||
64 | char *ref, | |||||
65 | char *map_pointer) | |||||
66 | { | |||||
67 | db_symtab_t *st; | |||||
68 | extern vm_map_t kernel_map; | |||||
69 | ||||||
70 | if (db_nsymtab >= MAXNOSYMTABS5) | |||||
71 | return (FALSE((boolean_t) 0)); | |||||
72 | ||||||
73 | st = &db_symtabs[db_nsymtab]; | |||||
74 | st->type = type; | |||||
75 | st->start = start; | |||||
76 | st->end = end; | |||||
77 | st->private = ref; | |||||
78 | st->map_pointer = (map_pointer == (char *)kernel_map)? 0: map_pointer; | |||||
79 | strncpy(st->name, name, sizeof st->name - 1); | |||||
80 | st->name[sizeof st->name - 1] = '\0'; | |||||
81 | ||||||
82 | db_nsymtab++; | |||||
83 | ||||||
84 | return (TRUE((boolean_t) 1)); | |||||
85 | } | |||||
86 | ||||||
87 | /* | |||||
88 | * db_qualify("vm_map", "ux") returns "ux::vm_map". | |||||
89 | * | |||||
90 | * Note: return value points to static data whose content is | |||||
91 | * overwritten by each call... but in practice this seems okay. | |||||
92 | */ | |||||
93 | static char * __attribute__ ((pure)) | |||||
94 | db_qualify(symname, symtabname) | |||||
95 | const char *symname; | |||||
96 | const char *symtabname; | |||||
97 | { | |||||
98 | static char tmp[256]; | |||||
99 | char *s; | |||||
100 | ||||||
101 | s = tmp; | |||||
102 | while ((*s++ = *symtabname++)) { | |||||
103 | } | |||||
104 | s[-1] = ':'; | |||||
105 | *s++ = ':'; | |||||
106 | while ((*s++ = *symname++)) { | |||||
107 | } | |||||
108 | return tmp; | |||||
109 | } | |||||
110 | ||||||
111 | ||||||
112 | boolean_t | |||||
113 | db_eqname( const char* src, const char* dst, char c ) | |||||
114 | { | |||||
115 | if (!strcmp(src, dst)) | |||||
116 | return (TRUE((boolean_t) 1)); | |||||
117 | if (src[0] == c) | |||||
118 | return (!strcmp(src+1,dst)); | |||||
119 | return (FALSE((boolean_t) 0)); | |||||
120 | } | |||||
121 | ||||||
122 | boolean_t | |||||
123 | db_value_of_name( | |||||
124 | char *name, | |||||
125 | db_expr_t *valuep) | |||||
126 | { | |||||
127 | db_sym_t sym; | |||||
128 | ||||||
129 | sym = db_lookup(name); | |||||
130 | if (sym == DB_SYM_NULL((db_sym_t)0)) | |||||
131 | return (FALSE((boolean_t) 0)); | |||||
132 | db_symbol_values(0, sym, &name, valuep); | |||||
133 | ||||||
134 | db_free_symbol(sym); | |||||
135 | return (TRUE((boolean_t) 1)); | |||||
136 | } | |||||
137 | ||||||
138 | /* | |||||
139 | * Lookup a symbol. | |||||
140 | * If the symbol has a qualifier (e.g., ux::vm_map), | |||||
141 | * then only the specified symbol table will be searched; | |||||
142 | * otherwise, all symbol tables will be searched. | |||||
143 | */ | |||||
144 | db_sym_t | |||||
145 | db_lookup(char *symstr) | |||||
146 | { | |||||
147 | db_sym_t sp; | |||||
148 | int i; | |||||
149 | int symtab_start = 0; | |||||
150 | int symtab_end = db_nsymtab; | |||||
151 | char *cp; | |||||
152 | ||||||
153 | /* | |||||
154 | * Look for, remove, and remember any symbol table specifier. | |||||
155 | */ | |||||
156 | for (cp = symstr; *cp; cp++) { | |||||
157 | if (*cp == ':' && cp[1] == ':') { | |||||
158 | *cp = '\0'; | |||||
159 | for (i = 0; i < db_nsymtab; i++) { | |||||
160 | if (! strcmp(symstr, db_symtabs[i].name)) { | |||||
161 | symtab_start = i; | |||||
162 | symtab_end = i + 1; | |||||
163 | break; | |||||
164 | } | |||||
165 | } | |||||
166 | *cp = ':'; | |||||
167 | if (i == db_nsymtab) | |||||
168 | db_error("Invalid symbol table name\n"); | |||||
169 | symstr = cp+2; | |||||
170 | } | |||||
171 | } | |||||
172 | ||||||
173 | /* | |||||
174 | * Look in the specified set of symbol tables. | |||||
175 | * Return on first match. | |||||
176 | */ | |||||
177 | for (i = symtab_start; i < symtab_end; i++) { | |||||
178 | if ((sp = X_db_lookup(&db_symtabs[i], symstr)x_db[(&db_symtabs[i])->type].lookup(&db_symtabs[i] ,symstr))) { | |||||
179 | db_last_symtab = &db_symtabs[i]; | |||||
180 | return sp; | |||||
181 | } | |||||
182 | db_free_symbol(sp); | |||||
183 | } | |||||
184 | return 0; | |||||
185 | } | |||||
186 | ||||||
187 | /* | |||||
188 | * Common utility routine to parse a symbol string into a file | |||||
189 | * name, a symbol name and line number. | |||||
190 | * This routine is called from X_db_lookup if the object dependent | |||||
191 | * handler supports qualified search with a file name or a line number. | |||||
192 | * It parses the symbol string, and call an object dependent routine | |||||
193 | * with parsed file name, symbol name and line number. | |||||
194 | */ | |||||
195 | db_sym_t | |||||
196 | db_sym_parse_and_lookup( | |||||
197 | db_sym_t (*func)(), | |||||
198 | db_symtab_t *symtab, | |||||
199 | char *symstr) | |||||
200 | { | |||||
201 | char *p; | |||||
202 | int n; | |||||
203 | int n_name; | |||||
204 | int line_number; | |||||
205 | char *file_name = 0; | |||||
206 | char *sym_name = 0; | |||||
207 | char *component[3]; | |||||
208 | db_sym_t found = DB_SYM_NULL((db_sym_t)0); | |||||
209 | ||||||
210 | /* | |||||
211 | * disassemble the symbol into components: | |||||
212 | * [file_name:]symbol[:line_nubmer] | |||||
213 | */ | |||||
214 | component[0] = symstr; | |||||
215 | component[1] = component[2] = 0; | |||||
216 | for (p = symstr, n = 1; *p; p++) { | |||||
217 | if (*p == ':') { | |||||
218 | if (n >= 3) | |||||
219 | break; | |||||
220 | *p = 0; | |||||
221 | component[n++] = p+1; | |||||
222 | } | |||||
223 | } | |||||
224 | if (*p != 0) | |||||
225 | goto out; | |||||
226 | line_number = 0; | |||||
227 | n_name = n; | |||||
228 | p = component[n-1]; | |||||
229 | if (*p >= '0' && *p <= '9') { | |||||
230 | if (n == 1) | |||||
231 | goto out; | |||||
232 | for (line_number = 0; *p; p++) { | |||||
233 | if (*p < '0' || *p > '9') | |||||
234 | goto out; | |||||
235 | line_number = line_number*10 + *p - '0'; | |||||
236 | } | |||||
237 | n_name--; | |||||
238 | } else if (n >= 3) | |||||
239 | goto out; | |||||
240 | if (n_name == 1) { | |||||
241 | for (p = component[0]; *p && *p != '.'; p++); | |||||
242 | if (*p == '.') { | |||||
243 | file_name = component[0]; | |||||
244 | sym_name = 0; | |||||
245 | } else { | |||||
246 | file_name = 0; | |||||
247 | sym_name = component[0]; | |||||
248 | } | |||||
249 | } else { | |||||
250 | file_name = component[0]; | |||||
251 | sym_name = component[1]; | |||||
252 | } | |||||
253 | found = func(symtab, file_name, sym_name, line_number); | |||||
254 | ||||||
255 | out: | |||||
256 | while (--n >= 1) | |||||
257 | component[n][-1] = ':'; | |||||
258 | return(found); | |||||
259 | } | |||||
260 | ||||||
261 | /* | |||||
262 | * Does this symbol name appear in more than one symbol table? | |||||
263 | * Used by db_symbol_values to decide whether to qualify a symbol. | |||||
264 | */ | |||||
265 | boolean_t db_qualify_ambiguous_names = FALSE((boolean_t) 0); | |||||
266 | ||||||
267 | boolean_t | |||||
268 | db_name_is_ambiguous(char *sym_name) | |||||
269 | { | |||||
270 | int i; | |||||
271 | boolean_t found_once = FALSE((boolean_t) 0); | |||||
272 | ||||||
273 | if (!db_qualify_ambiguous_names) | |||||
274 | return FALSE((boolean_t) 0); | |||||
275 | ||||||
276 | for (i = 0; i < db_nsymtab; i++) { | |||||
277 | db_sym_t sp = X_db_lookup(&db_symtabs[i], sym_name)x_db[(&db_symtabs[i])->type].lookup(&db_symtabs[i] ,sym_name); | |||||
278 | if (sp) { | |||||
279 | if (found_once) | |||||
280 | { | |||||
281 | db_free_symbol(sp); | |||||
282 | return TRUE((boolean_t) 1); | |||||
283 | } | |||||
284 | found_once = TRUE((boolean_t) 1); | |||||
285 | } | |||||
286 | db_free_symbol(sp); | |||||
287 | } | |||||
288 | return FALSE((boolean_t) 0); | |||||
289 | } | |||||
290 | ||||||
291 | /* | |||||
292 | * Find the closest symbol to val, and return its name | |||||
293 | * and the difference between val and the symbol found. | |||||
294 | * | |||||
295 | * Logic change. If the task argument is non NULL and a | |||||
296 | * matching symbol is found in a symbol table which explicitly | |||||
297 | * specifies its map to be task->map, that symbol will have | |||||
298 | * precedence over any symbol from a symbol table will a null | |||||
299 | * map. This allows overlapping kernel/user maps to work correctly. | |||||
300 | * | |||||
301 | */ | |||||
302 | db_sym_t | |||||
303 | db_search_task_symbol( | |||||
304 | db_addr_t val, | |||||
305 | db_strategy_t strategy, | |||||
306 | db_addr_t *offp, /* better be unsigned */ | |||||
307 | task_t task) | |||||
308 | { | |||||
309 | db_sym_t ret; | |||||
310 | ||||||
311 | if (task != TASK_NULL((task_t) 0)) | |||||
312 | ret = db_search_in_task_symbol(val, strategy, offp, task); | |||||
313 | else | |||||
314 | { | |||||
315 | ret = db_search_in_task_symbol(val, strategy, offp, task); | |||||
316 | /* | |||||
317 | db_search_in_task_symbol will return success with | |||||
318 | a very large offset when it should have failed. | |||||
319 | */ | |||||
320 | if (ret == DB_SYM_NULL((db_sym_t)0) || (*offp) > 0x1000000) | |||||
321 | { | |||||
322 | db_free_symbol(ret); | |||||
323 | task = db_current_task()(((active_threads[(0)]))? (active_threads[(0)])->task: ((task_t ) 0)); | |||||
324 | ret = db_search_in_task_symbol(val, strategy, offp, task); | |||||
325 | } | |||||
326 | } | |||||
327 | ||||||
328 | return ret; | |||||
329 | } | |||||
330 | ||||||
331 | db_sym_t | |||||
332 | db_search_in_task_symbol( | |||||
333 | db_addr_t val, | |||||
334 | db_strategy_t strategy, | |||||
335 | db_addr_t *offp, | |||||
336 | task_t task) | |||||
337 | { | |||||
338 | vm_size_t diff; | |||||
339 | vm_size_t newdiff; | |||||
340 | int i; | |||||
341 | db_symtab_t *sp; | |||||
342 | db_sym_t ret = DB_SYM_NULL((db_sym_t)0), sym; | |||||
343 | vm_map_t map_for_val; | |||||
344 | ||||||
345 | map_for_val = (task == TASK_NULL((task_t) 0))? VM_MAP_NULL((vm_map_t) 0): task->map; | |||||
346 | newdiff = diff = ~0; | |||||
347 | db_last_symtab = (db_symtab_t *) 0; | |||||
348 | for (sp = &db_symtabs[0], i = 0; i < db_nsymtab; sp++, i++) | |||||
349 | { | |||||
350 | newdiff = ~0; | |||||
351 | if ((vm_map_t)sp->map_pointer == VM_MAP_NULL((vm_map_t) 0) || | |||||
352 | (vm_map_t)sp->map_pointer == map_for_val) | |||||
353 | { | |||||
354 | sym = X_db_search_symbol(sp, val, strategy, (db_expr_t*)&newdiff)x_db[(sp)->type].search_symbol(sp,val,strategy,(db_expr_t* )&newdiff); | |||||
355 | if (sym == DB_SYM_NULL((db_sym_t)0)) | |||||
356 | continue; | |||||
357 | if (db_last_symtab == (db_symtab_t *) 0) | |||||
358 | { /* first hit */ | |||||
359 | db_last_symtab = sp; | |||||
360 | diff = newdiff; | |||||
361 | db_free_symbol(ret); | |||||
362 | ret = sym; | |||||
363 | continue; | |||||
364 | } | |||||
365 | if ((vm_map_t) sp->map_pointer == VM_MAP_NULL((vm_map_t) 0) && | |||||
366 | (vm_map_t) db_last_symtab->map_pointer == VM_MAP_NULL((vm_map_t) 0) && | |||||
367 | newdiff < diff ) | |||||
368 | { /* closer null map match */ | |||||
369 | db_last_symtab = sp; | |||||
370 | diff = newdiff; | |||||
371 | db_free_symbol(ret); | |||||
372 | ret = sym; | |||||
373 | continue; | |||||
374 | } | |||||
375 | if ((vm_map_t) sp->map_pointer != VM_MAP_NULL((vm_map_t) 0) && | |||||
376 | (newdiff < 0x100000) && | |||||
377 | ((vm_map_t) db_last_symtab->map_pointer == VM_MAP_NULL((vm_map_t) 0) || | |||||
378 | newdiff < diff )) | |||||
379 | { /* update if new is in matching map and symbol is "close", | |||||
380 | and | |||||
381 | old is VM_MAP_NULL or old in is matching map but is further away | |||||
382 | */ | |||||
383 | db_last_symtab = sp; | |||||
384 | diff = newdiff; | |||||
385 | db_free_symbol(ret); | |||||
386 | ret = sym; | |||||
387 | continue; | |||||
388 | } | |||||
389 | } | |||||
390 | } | |||||
391 | ||||||
392 | *offp = diff; | |||||
393 | return ret; | |||||
394 | } | |||||
395 | ||||||
396 | /* | |||||
397 | * Return name and value of a symbol | |||||
398 | */ | |||||
399 | void | |||||
400 | db_symbol_values( | |||||
401 | db_symtab_t *stab, | |||||
402 | db_sym_t sym, | |||||
403 | char **namep, | |||||
404 | db_expr_t *valuep) | |||||
405 | { | |||||
406 | db_expr_t value; | |||||
407 | char *name; | |||||
408 | ||||||
409 | if (sym == DB_SYM_NULL((db_sym_t)0)) { | |||||
410 | *namep = 0; | |||||
411 | return; | |||||
412 | } | |||||
413 | if (stab == 0) | |||||
414 | stab = db_last_symtab; | |||||
415 | ||||||
416 | X_db_symbol_values(stab, sym, &name, &value)x_db[(stab)->type].symbol_values(stab,sym,&name,&value ); | |||||
| ||||||
417 | ||||||
418 | if (db_name_is_ambiguous(name)) | |||||
419 | *namep = db_qualify(name, db_last_symtab->name); | |||||
420 | else | |||||
421 | *namep = name; | |||||
422 | if (valuep) | |||||
423 | *valuep = value; | |||||
424 | } | |||||
425 | ||||||
426 | ||||||
427 | /* | |||||
428 | * Print the closest symbol to value | |||||
429 | * | |||||
430 | * After matching the symbol according to the given strategy | |||||
431 | * we print it in the name+offset format, provided the symbol's | |||||
432 | * value is close enough (eg smaller than db_maxoff). | |||||
433 | * We also attempt to print [filename:linenum] when applicable | |||||
434 | * (eg for procedure names). | |||||
435 | * | |||||
436 | * If we could not find a reasonable name+offset representation, | |||||
437 | * then we just print the value in hex. Small values might get | |||||
438 | * bogus symbol associations, e.g. 3 might get some absolute | |||||
439 | * value like _INCLUDE_VERSION or something, therefore we do | |||||
440 | * not accept symbols whose value is zero (and use plain hex). | |||||
441 | */ | |||||
442 | ||||||
443 | unsigned long db_maxoff = 0x4000; | |||||
444 | ||||||
445 | void | |||||
446 | db_task_printsym(off, strategy, task) | |||||
447 | db_addr_t off; | |||||
448 | db_strategy_t strategy; | |||||
449 | task_t task; | |||||
450 | { | |||||
451 | db_addr_t d; | |||||
452 | char *filename; | |||||
453 | char *name; | |||||
454 | db_expr_t value; | |||||
455 | int linenum; | |||||
456 | db_sym_t cursym; | |||||
457 | ||||||
458 | cursym = db_search_task_symbol(off, strategy, &d, task); | |||||
459 | db_symbol_values(0, cursym, &name, &value); | |||||
460 | if (name == 0 || d >= db_maxoff || value == 0 || *name == 0) { | |||||
461 | db_printf("%#n", off); | |||||
462 | db_free_symbol(cursym); | |||||
463 | return; | |||||
464 | } | |||||
465 | db_printf("%s", name); | |||||
466 | if (d) | |||||
467 | db_printf("+0x%x", d); | |||||
468 | if (strategy == DB_STGY_PROC2) { | |||||
469 | if (db_line_at_pc(cursym, &filename, &linenum, off)) { | |||||
470 | db_printf(" [%s", filename); | |||||
471 | if (linenum > 0) | |||||
472 | db_printf(":%d", linenum); | |||||
473 | db_printf("]"); | |||||
474 | } | |||||
475 | } | |||||
476 | db_free_symbol(cursym); | |||||
477 | } | |||||
478 | ||||||
479 | void | |||||
480 | db_printsym(off, strategy) | |||||
481 | db_expr_t off; | |||||
482 | db_strategy_t strategy; | |||||
483 | { | |||||
484 | db_task_printsym(off, strategy, TASK_NULL((task_t) 0)); | |||||
| ||||||
485 | } | |||||
486 | ||||||
487 | boolean_t | |||||
488 | db_line_at_pc( sym, filename, linenum, pc) | |||||
489 | db_sym_t sym; | |||||
490 | char **filename; | |||||
491 | int *linenum; | |||||
492 | db_addr_t pc; | |||||
493 | { | |||||
494 | return (db_last_symtab) ? | |||||
495 | X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc)x_db[(db_last_symtab)->type].line_at_pc(db_last_symtab,sym ,filename,linenum,pc) : | |||||
496 | FALSE((boolean_t) 0); | |||||
497 | } | |||||
498 | ||||||
499 | void db_free_symbol(db_sym_t s) | |||||
500 | { | |||||
501 | return (db_last_symtab) ? | |||||
502 | X_db_free_symbol( db_last_symtab, s)x_db[(db_last_symtab)->type].free_symbol(s) : | |||||
503 | FALSE((boolean_t) 0); | |||||
504 | } | |||||
505 | ||||||
506 | /* | |||||
507 | * Switch into symbol-table specific routines | |||||
508 | */ | |||||
509 | ||||||
510 | void dummy_db_free_symbol(db_sym_t symbol) { } | |||||
511 | boolean_t dummy_db_sym_init(char *a, char *b, char *c, char *d) { | |||||
512 | return FALSE((boolean_t) 0); | |||||
513 | } | |||||
514 | ||||||
515 | ||||||
516 | struct db_sym_switch x_db[] = { | |||||
517 | ||||||
518 | /* BSD a.out format (really, sdb/dbx(1) symtabs) */ | |||||
519 | #ifdef DB_NO_AOUT | |||||
520 | { 0,}, | |||||
521 | #else /* DB_NO_AOUT */ | |||||
522 | { aout_db_sym_init, aout_db_lookup, aout_db_search_symbol, | |||||
523 | aout_db_line_at_pc, aout_db_symbol_values, dummy_db_free_symbol }, | |||||
524 | #endif /* DB_NO_AOUT */ | |||||
525 | ||||||
526 | { 0,}, | |||||
527 | ||||||
528 | /* Machdep, not inited here */ | |||||
529 | { 0,}, | |||||
530 | ||||||
531 | #ifdef DB_NO_ELF | |||||
532 | { 0,}, | |||||
533 | #else /* DB_NO_ELF */ | |||||
534 | { dummy_db_sym_init, elf_db_lookup, elf_db_search_symbol, | |||||
535 | elf_db_line_at_pc, elf_db_symbol_values, dummy_db_free_symbol }, | |||||
536 | #endif /* DB_NO_ELF */ | |||||
537 | ||||||
538 | }; | |||||
539 | ||||||
540 | #endif /* MACH_KDB */ |