"Fossies" - the Fresh Open Source Software Archive 
Member "FunctionCheck-3.2.0/src/fcdump/fc_names.c" (26 May 2012, 16685 Bytes) of package /linux/privat/old/FunctionCheck-3.2.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * FunctionCheck profiler
3 * (C) Copyright 2000-2012 Yannick Perret
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /** fc_names.c: **/
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "demangle.h"
25 #include "fc_names.h"
26
27 /** static string to prevent 'null' names **/
28 #define FC_INVALID_NAME "<error>"
29
30 /** symbol list for low-level access to BFD data (local) **/
31 typedef struct
32 {
33 char *name;
34 void *addr;
35 int flag; /* an exported function */
36 } FC_Sym;
37
38 /* local table to treat symbols */
39 FC_Sym *fc_syms = NULL;
40 int fc_nb_syms = 0;
41
42 /* open a binary object using BFD */
43 int fc_open_bfd_file(char *name, bfd **core_bfd, int *core_num_syms,
44 asection **core_text_sect, asymbol ***core_syms,
45 int *core_min_insn_size, int *core_offset_to_code)
46 {
47 *core_bfd = bfd_openr(name, 0);
48 if (!(*core_bfd))
49 {
50 fc_message("cannot open file %s", name);
51 return 0;
52 }
53
54 /* check format */
55 if (!bfd_check_format(*core_bfd, bfd_object))
56 {
57 fc_message("file '%s' is not an object", name);
58 return 0;
59 }
60
61 /* get TEXT section */ /* ".text" */
62 *core_text_sect = bfd_get_section_by_name(*core_bfd, ".text");
63 if (!(*core_text_sect))
64 {
65 fc_message("BFD: trying $CODE$ section instead of .text");
66 *core_text_sect = bfd_get_section_by_name(*core_bfd, "$CODE$");
67 if (!(*core_text_sect))
68 {
69 fc_message("no TEXT section in object '%s'", name);
70 return 0;
71 }
72 }
73
74 /* read symbol table */
75 *core_num_syms = bfd_get_symtab_upper_bound(*core_bfd);
76 if (*core_num_syms < 0)
77 {
78 fc_message("bfd error: %s", bfd_errmsg(bfd_get_error()));
79 return 0;
80 }
81
82 *core_syms = (asymbol **) malloc(sizeof (asymbol*)*(*core_num_syms));
83 if (*core_syms == NULL)
84 {
85 fc_message("cannot allocate %d bytes for symbols", (int) sizeof (asymbol*)*(*core_num_syms));
86 fc_message_fatal(FC_ERR_MEM, "treatments aborted");
87 }
88
89 *core_num_syms = bfd_canonicalize_symtab(*core_bfd, *core_syms);
90 if (*core_num_syms < 0)
91 {
92 free(*core_syms);
93 fc_message("bfd error: %s", bfd_errmsg(bfd_get_error()));
94 return 0;
95 }
96
97 *core_min_insn_size = 1;
98 *core_offset_to_code = 0;
99 switch (bfd_get_arch(*core_bfd))
100 {
101 case bfd_arch_vax:
102 case bfd_arch_tahoe:
103 *core_offset_to_code = 2;
104 break;
105 case bfd_arch_alpha:
106 *core_min_insn_size = 4;
107 break;
108 default:
109 break;
110 }
111
112 /* ok */
113 return 1;
114 }
115
116 /* close a binary object open with BFD */
117 int fc_close_bfd_file(bfd *core_bfd, int core_num_syms,
118 asection *core_text_sect, asymbol **core_syms,
119 int core_min_insn_size, int core_offset_to_code)
120 {
121 bfd_close(core_bfd);
122 free(core_syms);
123
124 return 1;
125 }
126
127
128 /* sort sym. table by address */
129 int fc_compare_pointers(const void *e1, const void *e2)
130 {
131 if (((FC_Sym*) e1)->addr > ((FC_Sym*) e2)->addr)
132 return 1;
133 if (((FC_Sym*) e1)->addr < ((FC_Sym*) e2)->addr)
134 return -1;
135 return 0;
136 }
137
138 /* init symbol table from BFD data */
139 int fc_init_extract_dynamic(int core_num_syms, asymbol **core_syms)
140 {
141 int i, dest;
142
143 if ((fc_syms = malloc(sizeof (FC_Sym) * core_num_syms)) == NULL)
144 {
145 fc_message("cannot allocate local symbol table");
146 return 0;
147 }
148
149 /* put addr/names in table */
150 dest = 0;
151 for (i = 0; i < core_num_syms; i++)
152 {
153 /* only functions */
154 if (core_syms[i]->flags & BSF_FUNCTION)
155 {
156 fc_syms[dest].name = (char*) bfd_asymbol_name(core_syms[i]);
157 fc_syms[dest].addr = (void*) bfd_asymbol_value(core_syms[i]);
158 if ((core_syms[i]->flags & BSF_GLOBAL) || (core_syms[i]->flags & BSF_EXPORT))
159 fc_syms[dest].flag = 1;
160 else
161 fc_syms[dest].flag = 0;
162 dest++;
163 }
164 }
165
166 fc_nb_syms = dest;
167
168 /* empty table */
169 if (fc_nb_syms == 0)
170 {
171 return 0;
172 }
173
174 /* sort it by pointer value */
175 qsort(fc_syms, fc_nb_syms, sizeof (FC_Sym), fc_compare_pointers);
176
177 return 1;
178 }
179
180 /* freed the local sym. table */
181 int fc_fini_extract_dynamic()
182 {
183 if (fc_syms != NULL)
184 free(fc_syms);
185 fc_syms = NULL;
186 fc_nb_syms = 0;
187
188 return 1;
189 }
190
191 /* returns a name (char* to duplicate) from an address */
192 /* valid is true if it is a local name */
193 char *fc_extract_dynamic(void *addr, int *valid)
194 {
195 int i;
196 char tmp[1024], *buffer = tmp;
197
198 *valid = 0;
199 if (fc_syms == NULL)
200 return ("<err0>");
201
202 if (addr < fc_syms[0].addr)
203 {
204 sprintf(buffer, "<lo-%p>", addr);
205 return ((char*) buffer); /* before first symbol */
206 }
207
208 if (addr > fc_syms[fc_nb_syms - 1].addr)
209 {
210 sprintf(buffer, "<hi-%p>", addr);
211 return ((char*) buffer); /* after last symbol */
212 }
213
214 /* I may use a better search method :o) */
215 for (i = 0; i < fc_nb_syms; i++)
216 {
217 /* only check EXACT addresses */
218 if (addr == fc_syms[i].addr)
219 {
220 *valid = fc_syms[i].flag;
221 return (fc_syms[i].name);
222 }
223 }
224
225 /* the exact entry does not exist */
226 return NULL;
227 }
228
229 /* return true if 'name' is present in the sym-table AND
230 is exported. Gives the corresponding address for get_nearest_line */
231 int fc_find_symbol_by_name(char *name, void **addr, int demangle, int style)
232 {
233 int i;
234 char *ntemp;
235
236 *addr = NULL;
237
238 if (name == NULL)
239 return 0;
240
241 /* loop for this name */
242 for (i = 0; i < fc_nb_syms; i++)
243 {
244 /* demangle it if needed (for a coherent strcmp) */
245 if (demangle)
246 {
247 ntemp = cplus_demangle(fc_syms[i].name, style);
248 if (ntemp == NULL)
249 ntemp = fc_syms[i].name; /* use the basic name else */
250 }
251 else
252 {
253 ntemp = fc_syms[i].name; /* no demangle, use the basic name */
254 }
255
256 if ((ntemp[0] == name[0]) && (strcmp(ntemp, name) == 0))
257 {/* found. check for the export status */
258 if (fc_syms[i].flag)
259 {/* ok */
260 *addr = fc_syms[i].addr;
261 return 1;
262 }
263 else
264 {/* exit. it is not possible to get the same name twice (really?) */
265 return 0;
266 }
267 }
268 }
269 /* no match at all */
270 return 0;
271 }
272
273 /* returns the function pointer from a pointer inside the function */
274 void *fc_extract_dynamic_base(void *addr)
275 {
276 int i;
277
278 /* !?! */
279 if (fc_syms == NULL)
280 return NULL;
281
282 /* out of the bounds */
283 if ((addr < fc_syms[0].addr) || (addr > fc_syms[fc_nb_syms - 1].addr))
284 {/* no changes */
285 return addr;
286 }
287
288 /* I may use a better search method :o) */
289 for (i = 0; i < fc_nb_syms - 1; i++)
290 {
291 if ((addr >= fc_syms[i].addr) && (addr < fc_syms[i + 1].addr))
292 {
293 return (fc_syms[i].addr);
294 }
295 }
296
297 /* may not occur */
298 return addr;
299 }
300
301 /* return the symbol address of the given function */
302 void *fc_search_function_by_name(char *name, int nbf, FC_Function *fncs)
303 {
304 int i;
305
306 for (i = 0; i < nbf; i++)
307 {
308 if ((fncs[i].name.name != NULL) && (fncs[i].name.name[0] == name[0]) &&
309 (strcmp(fncs[i].name.name, name) == 0))
310 {
311 return (fncs[i].symbol);
312 }
313 }
314
315 /* not found */
316 return NULL;
317 }
318
319 /* return true if the given address exist */
320 int fc_check_address(void *addr, int nbf, FC_Function *fncs)
321 {
322 int i;
323
324 for (i = 0; i < nbf; i++)
325 {
326 if (fncs[i].symbol == addr)
327 return 1;
328 }
329 /* not found */
330 return 0;
331 }
332
333 int fc_names_solve(int force_names,
334 int nb_fnc, FC_Function *fncs,
335 int nb_lib, FC_LDyn *dyns,
336 int nb_arcs, FC_Arc *arcs,
337 char *exec_name, int demangle, int style,
338 FC_NSym *lonly, int nb_only,
339 FC_NSym *lnot, int nb_not,
340 int nb_leaks, FC_MLeak *leaks,
341 int nb_free, FC_MFree *free,
342 int nb_realloc, FC_MRealloc *realloc)
343 {
344 /* BFD data for exec */
345 bfd *core_bfd;
346 int core_min_insn_size;
347 int core_offset_to_code;
348 asection *core_text_sect;
349 int core_num_syms;
350 asymbol **core_syms;
351 /* various variables */
352 int i, j, valid;
353 char *tname, *_tname, *tobj, *ttt;
354 int tline;
355 int missing = 0;
356 void *addr;
357
358 fc_debug("Solving names...");
359
360 /* first init the list of functions names */
361 for (i = 0; i < nb_fnc; i++)
362 {
363 fncs[i].name.name = NULL;
364 fncs[i].name.object = NULL;
365 fncs[i].name.line = 0;
366 fncs[i].name.ok = FC_OK_NDEF;
367 }
368
369 /* open the executable */
370 fc_debug(" opening executable '%s'", exec_name);
371 if (!fc_open_bfd_file(exec_name, &core_bfd, &core_num_syms,
372 &core_text_sect, &core_syms,
373 &core_min_insn_size, &core_offset_to_code))
374 {
375 fc_message("The executable name given (%s) is not a valid object.", exec_name);
376 if (!force_names)
377 {
378 fc_message_fatal(FC_ERR_ARGS, "Please check your parameters (try '--help' option)");
379 }
380 else
381 {
382 fc_message("Names will not be available (check your parameters)");
383 }
384 return 0;
385 }
386
387 if (!fc_init_extract_dynamic(core_num_syms, core_syms))
388 {
389 fc_message("names treatments aborted."); /* close bfd object */
390 fc_close_bfd_file(core_bfd, core_num_syms,
391 core_text_sect, core_syms,
392 core_min_insn_size, core_offset_to_code);
393 return 0;
394 }
395
396 /* for each arc replace call-site by the corresponding function */
397 fc_debug(" cleaning arcs..");
398 for (i = 0; i < nb_arcs; i++)
399 {
400 arcs[i].from = fc_extract_dynamic_base(arcs[i].from);
401 }
402
403 /* for each entry try to extract data */
404 fc_debug(" extracting names...");
405 for (i = 0; i < nb_fnc; i++)
406 {
407 /* get the name with our method: this is due to the fact
408 that get_nearest_line failed to extract the name of a
409 function that comes from a dynamic object */
410 tname = fc_extract_dynamic(fncs[i].symbol, &valid);
411
412 /* if the name is local, try to get file:line */
413 if (valid)
414 {
415 /* get name/file/line using BFD */
416 bfd_find_nearest_line(core_bfd, core_text_sect, core_syms,
417 (bfd_vma) fncs[i].symbol - core_text_sect->vma,
418 (const char**) &tobj,
419 (const char**) &_tname,
420 (unsigned int *) &tline);
421 }
422 else
423 {
424 tobj = NULL;
425 tline = 0;
426 }
427
428 fncs[i].name.object = tobj;
429 fncs[i].name.line = tline;
430 if (valid)
431 {
432 fncs[i].name.ok = FC_OK_OK;
433 }
434 else
435 {
436 fncs[i].name.ok = FC_OK_NDEF;
437 missing = 1;
438 }
439
440 if (tname == NULL)
441 {
442 ttt = NULL;
443 }
444 else
445 {
446 if (demangle)
447 {
448 ttt = cplus_demangle(tname, style);
449 if (ttt == NULL)
450 ttt = strdup(tname);
451 else
452 {
453 tname = strdup(ttt);
454 ttt = tname;
455 }
456 }
457 else
458 {
459 ttt = strdup(tname);
460 }
461 }
462
463 fncs[i].name.name = (ttt == NULL ? FC_INVALID_NAME : ttt);
464 if (ttt == NULL)
465 {
466 fncs[i].name.ok = FC_OK_BAD; /* mem error: not ok but not solvable */
467 }
468 }
469
470 /* close our special treatments */
471 fc_fini_extract_dynamic();
472
473 /* close bfd object */
474 fc_close_bfd_file(core_bfd, core_num_syms,
475 core_text_sect, core_syms,
476 core_min_insn_size, core_offset_to_code);
477
478 /* now try to extract informations from dynamic libraries
479 if some details are missing */
480 if (missing)
481 {
482 fc_debug(" still missing details");
483 for (i = 0; i < nb_lib; i++)
484 {
485 /* open the ith lib */
486 fc_debug(" trying object '%s'", dyns[i].name);
487 if (!fc_open_bfd_file(dyns[i].name, &core_bfd, &core_num_syms,
488 &core_text_sect, &core_syms,
489 &core_min_insn_size, &core_offset_to_code))
490 {
491 fc_debug(" skipping library '%s' (bfd open error)", dyns[i].name);
492 continue;
493 }
494
495 if (!fc_init_extract_dynamic(core_num_syms, core_syms))
496 {
497 /* close the BFD file */
498 fc_close_bfd_file(core_bfd, core_num_syms,
499 core_text_sect, core_syms,
500 core_min_insn_size, core_offset_to_code);
501 fc_debug(" skipping library '%s' (empty symbol table)", dyns[i].name);
502 continue;
503 }
504
505 /* for each invalid symbol, try to extract it in this lib */
506 for (j = 0; j < nb_fnc; j++)
507 {
508 if (fncs[j].name.ok == FC_OK_NDEF)
509 {
510 /* check if this symbol is here and exported */
511 if (fc_find_symbol_by_name(fncs[j].name.name, &addr, demangle, style))
512 {
513 /* get file/line using BFD */
514 bfd_find_nearest_line(core_bfd, core_text_sect, core_syms,
515 (bfd_vma) addr - core_text_sect->vma,
516 (const char**) &tobj,
517 (const char**) &_tname,
518 (unsigned int *) &tline);
519 /* add this information in the symbol */
520 fncs[j].name.object = strdup(tobj);
521 fncs[j].name.line = tline;
522 fncs[j].name.ok = FC_OK_OK;
523 }
524 else
525 {/* still some job to do */
526 missing = 1;
527 }
528 }
529 }
530
531 fc_fini_extract_dynamic();
532 /* close the BFD file */
533 fc_close_bfd_file(core_bfd, core_num_syms,
534 core_text_sect, core_syms,
535 core_min_insn_size, core_offset_to_code);
536
537 /* no more ? */
538 if (!missing)
539 break;
540 }
541 }
542
543 /* if any, parse not/only lists to convert names to addresses */
544 for (i = 0; i < nb_only; i++)
545 {
546 if ((lonly[i].addr == NULL) && (lonly[i].name != NULL))
547 {
548 lonly[i].addr = fc_search_function_by_name(lonly[i].name, nb_fnc, fncs);
549 if (lnot[i].addr == NULL)
550 {
551 fc_message("function '%s' not found. discarded.", lnot[i].name);
552 }
553 }
554 else
555 if (lnot[i].addr != NULL)
556 {
557 if (!fc_check_address(lnot[i].addr, nb_fnc, fncs))
558 {
559 fc_message("address %p not found. discarded.", lnot[i].addr);
560 lnot[i].addr = NULL;
561 }
562 }
563 }
564
565 for (i = 0; i < nb_not; i++)
566 {
567 if ((lnot[i].addr == NULL) && (lnot[i].name != NULL))
568 {
569 lnot[i].addr = fc_search_function_by_name(lnot[i].name, nb_fnc, fncs);
570 if (lnot[i].addr == NULL)
571 {
572 fc_message("function '%s' not found. discarded.", lnot[i].name);
573 }
574 }
575 else
576 if (lnot[i].addr != NULL)
577 {
578 if (!fc_check_address(lnot[i].addr, nb_fnc, fncs))
579 {
580 fc_message("address %p not found. discarded.", lnot[i].addr);
581 lnot[i].addr = NULL;
582 }
583 }
584 }
585
586 fc_debug("End of name extraction.");
587 return 1;
588 }
589