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