symbol.c
上传用户:hxtd_72
上传日期:2007-06-06
资源大小:64k
文件大小:12k
源码类别:

驱动编程

开发平台:

C/C++

  1. /*
  2.     symbol.c.
  3.     Symbol handling routines for ksymoops.
  4.     Copyright 1999 Keith Owens <kaos@ocs.com.au>.
  5.     Released under the GNU Public Licence, Version 2.
  6.  */
  7. #include "ksymoops.h"
  8. #include <errno.h>
  9. #include <malloc.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. /* Initialise a symbol source */
  13. void ss_init(SYMBOL_SET *ss, const char *msg)
  14. {
  15.     memset(ss, '', sizeof(*ss));
  16.     ss->source = strdup(msg);
  17.     if (!ss->source)
  18. malloc_error(msg);
  19. }
  20. /* Free dynamic data from a symbol source */
  21. void ss_free(SYMBOL_SET *ss)
  22. {
  23.     int i;
  24.     SYMBOL *s;
  25.     for (s = ss->symbol, i = 0; i < ss->used; ++i, ++s)
  26. free(s->name);
  27.     free(ss->symbol);
  28.     free(ss->source);
  29.     memset(ss, '', sizeof(*ss));
  30. }
  31. /* Initialise common symbol sets */
  32. void ss_init_common(void)
  33. {
  34.     ss_init(&ss_Version, "Version_");
  35. }
  36. /* Find a symbol name in a symbol source.  Brute force ascending order search,
  37.  * no hashing.  If start is not NULL, it contains the starting point for the
  38.  * scan and is updated to point to the found entry.  If the entry is not found,
  39.  * return NULL with start pointing to the next highest entry.
  40.  * NOTE: Assumes that ss is sorted by name.
  41.  */
  42. SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol, int *start)
  43. {
  44.     int i, l;
  45.     SYMBOL *s;
  46.     for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
  47. if ((l = strcmp(symbol, s->name)) == 0) {
  48.     if (start)
  49. *start = i;
  50.     return(s);
  51. }
  52. if (l < 0)
  53.     break;
  54.     }
  55.     if (start)
  56. *start = i;
  57.     return NULL;
  58. }
  59. #define MIPS64_CKSEG0_MASK 0xffffffff80000000ULL
  60. #define MIPS64_CKSEG0_BASE 0xffffffff80000000ULL
  61. #define MIPS64_KSEG0_BASE 0x0000000080000000ULL
  62. #define MIPS64_XKPHYS5_BASE 0xa800000000000000ULL
  63. static addr_t normalize_address(addr_t address, const OPTIONS *options)
  64. {
  65.     if (options->target &&
  66. strstr(options->target, "mips") &&
  67. strstr(options->target, "64")) {
  68. /*
  69. * Some address gymnastics are necessary due to the weird way
  70. * in which mips64 kernels are built as elf32 then converted
  71. * to elf64 after linking.
  72. */
  73. if ((address & MIPS64_CKSEG0_MASK) == MIPS64_CKSEG0_BASE ||
  74.     (address & MIPS64_CKSEG0_MASK) == MIPS64_KSEG0_BASE) {
  75.     /* normalise physical addrs in 32-bit kernel segments */
  76.     address = (address & ~MIPS64_CKSEG0_MASK) | MIPS64_XKPHYS5_BASE;
  77. }
  78.     }
  79.     address &= truncate_mask;
  80.     return(address);
  81. }
  82. /* Find an address in a symbol source.  Brute force ascending order search, no
  83.  * hashing.  If start is not NULL, it contains the starting point for the scan
  84.  * and is updated to point to the found entry.  If the entry is not found,
  85.  * return NULL with start pointing to the next highest entry.
  86.  * NOTE: Assumes that ss is sorted by address.
  87.  */
  88. static SYMBOL *find_symbol_address(const SYMBOL_SET *ss,
  89.    addr_t address, int *start,
  90.    const OPTIONS *options)
  91. {
  92.     int i;
  93.     SYMBOL *s;
  94.     address = normalize_address(address, options);
  95.     for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
  96. addr_t saddress = normalize_address(s->address, options);
  97. if (address > saddress)
  98.     continue;
  99. else if (address == saddress) {
  100.     if (i < ss->used-1 &&
  101. address == normalize_address((s+1)->address, options) &&
  102. (s->type == 'G' || s->type == 'g'))
  103. /* more than one symbol on the same address, skip the ones that
  104.  * came from modutils assist.
  105.  */
  106. continue;
  107.     if (start)
  108. *start = i;
  109.     return(s);
  110. }
  111. else
  112.     break;
  113.     }
  114.     if (start)
  115. *start = i;
  116.     return NULL;
  117. }
  118. /* Add a symbol to a symbol set, address in binary */
  119. int add_symbol_n(SYMBOL_SET *ss, addr_t address,
  120.  const char type, const char keep, const char *symbol)
  121. {
  122.     int i;
  123.     char **string = NULL;
  124.     SYMBOL *s;
  125.     static regex_t     re_symbol_ver;
  126.     static regmatch_t *re_symbol_ver_pmatch;
  127.     static const char procname[] = "add_symbol_n";
  128.     address &= truncate_mask;
  129.     /* Strip out any trailing symbol version _R.*xxxxxxxx. */
  130.     RE_COMPILE(&re_symbol_ver,
  131. "^(.*)_R.*[0-9a-fA-F]{8,}$",
  132. REG_NEWLINE|REG_EXTENDED,
  133. &re_symbol_ver_pmatch);
  134.     i = regexec(&re_symbol_ver, symbol,
  135. re_symbol_ver.re_nsub+1, re_symbol_ver_pmatch, 0);
  136.     DEBUG(4, "regexec %d", i);
  137.     if (i == 0)
  138. re_strings(&re_symbol_ver, symbol, re_symbol_ver_pmatch,
  139.     &string);
  140.     DEBUG(4, "%s %s '%c' %d '%s'",
  141. ss->source, format_address(address, NULL),
  142. type, keep, i == 0 ? string[1] : symbol);
  143.     if (ss->used > ss->alloc)
  144. FATAL("ss %s used (%d) > alloc (%d)", ss->source, ss->used, ss->alloc);
  145.     if (ss->used == ss->alloc) {
  146. /* increase by 20% or 10, whichever is larger, arbitrary */
  147. int newsize = ss->alloc*120/100;
  148. if (newsize < ss->alloc+10)
  149.     newsize = ss->alloc+10;
  150. DEBUG(4, "increasing %s from %d to %d entries",
  151.     ss->source, ss->alloc, newsize);
  152. ss->symbol = realloc(ss->symbol, newsize*sizeof(*(ss->symbol)));
  153. if (!ss->symbol)
  154.     malloc_error("realloc ss");
  155. ss->alloc = newsize;
  156.     }
  157.     s = ss->symbol+ss->used;
  158.     if (i == 0) {
  159. s->name = string[1];
  160. string[1] = NULL;   /* don't free this one */
  161.     }
  162.     else {
  163. s->name = strdup(symbol);
  164. if (!s->name)
  165.     malloc_error("strdup symbol");
  166.     }
  167.     s->type = type;
  168.     s->keep = keep;
  169.     s->address = address;
  170.     s->module = NULL; /* only used in final map */
  171.     re_strings_free(&re_symbol_ver, &string);
  172.     return(ss->used++);
  173. }
  174. /* Add a symbol to a symbol set, address in character */
  175. int add_symbol(SYMBOL_SET *ss, const char *address, const char type,
  176.        const char keep, const char *symbol)
  177. {
  178.     addr_t a;
  179.     static char const procname[] = "add_symbol";
  180.     errno = 0;
  181.     a = hexstring(address);
  182.     if (errno) {
  183. ERROR("address '%s' is in error", address);
  184. perror(prefix);
  185.     }
  186.     return(add_symbol_n(ss, a, type, 1, symbol));
  187. }
  188. /* Map an address to symbol, offset and length, address in binary */
  189. char *map_address(const SYMBOL_SET *ss, addr_t address,
  190.   const OPTIONS *options)
  191. {
  192.     int i = 0, l;
  193.     SYMBOL *s;
  194.     static char *map = NULL;
  195.     static int size = 0;
  196.     static const char procname[] = "map_address";
  197.     address &= truncate_mask;
  198.     DEBUG(3, "%s %s", ss->source, format_address(address, options));
  199.     s = find_symbol_address(ss, address, &i, options);
  200.     if (!s && --i >= 0)
  201. s = ss->symbol+i;   /* address is between s and s+1 */
  202.     /* Extra map text is always < 100 bytes */
  203.     if (s) {
  204. l = strlen(s->name) + 100;
  205. if (s->module)
  206.     l += strlen(s->module)+2;  /* [module] */
  207.     }
  208.     else
  209. l = 100;
  210.     if (l > size) {
  211. map = realloc(map, l);
  212. if (!map)
  213.     malloc_error(procname);
  214. size = l;
  215.     }
  216.     if (!s) {
  217. if (ss->used == 0)
  218.     snprintf(map, size, "No symbols available");
  219. else
  220.     snprintf(map, size, "Before first symbol");
  221.     }
  222.     else if ((i+1) >= ss->used) {
  223. /* Somewhere past last symbol.  Length of last section of code
  224.  * is unknown, arbitrary cutoff at 32K.
  225.  * Stupid gcc warns about trigraph ? ? > so split the strings.
  226.  */
  227. addr_t offset = normalize_address(address, options) -
  228. normalize_address(s->address, options);
  229. if (offset > 32768)
  230.     snprintf(map, size,
  231.      options->hex ? "<END_OF_CODE+%llx/???" "?>"
  232.     : "<END_OF_CODE+%lld/???" "?>",
  233. offset);
  234. else
  235.     snprintf(map, size,
  236.      options->hex ? "<%s+%llx/???" "?>"
  237.     : "<%s+%lld/???" "?>",
  238. s->name, offset);
  239.     }
  240.     else {
  241. snprintf(map, size,
  242.  options->hex ? "<%s%s%s%s+%llx/%llx>"
  243. : "<%s%s%s%s+%lld/%lld>",
  244.     s->module ? "[" : "",
  245.     s->module ? s->module : "",
  246.     s->module ? "]" : "",
  247.     s->name,
  248.     normalize_address(address, options) -
  249.     normalize_address(s->address, options),
  250.     normalize_address((s+1)->address, options) -
  251.     normalize_address(s->address, options));
  252.     }
  253.     return(map);
  254. }
  255. /* After sorting, obsolete symbols are at the top.  Delete them. */
  256. static void ss_compress(SYMBOL_SET *ss)
  257. {
  258.     int i, j;
  259.     SYMBOL *s;
  260.     static const char procname[] = "ss_compress";
  261.     DEBUG(2, "table %s, before %d", ss->source, ss->used);
  262.     for (i = 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
  263. if (!s->keep) {
  264.     for (j = i; j < ss->used; ++j, ++s) {
  265. if (s->keep)
  266.     FATAL("table %s is not sorted", ss->source);
  267.     }
  268.     break;
  269. }
  270.     }
  271.     for (j = i, s = ss->symbol+j; j < ss->used; ++j, ++s) {
  272. DEBUG(4, "dropped %s", s->name);
  273. free(s->name);
  274.     }
  275.     ss->used = i;
  276.     DEBUG(2, "table %s, after %d", ss->source, ss->used);
  277. }
  278. static int ss_compare_atn(const void *a, const void *b)
  279. {
  280.     SYMBOL *c = (SYMBOL *) a;
  281.     SYMBOL *d = (SYMBOL *) b;
  282.     int i;
  283.     /* obsolete symbols to the top */
  284.     if (c->keep != d->keep)
  285. return(d->keep - c->keep);
  286.     if (c->address > d->address)
  287. return(1);
  288.     if (c->address < d->address)
  289. return(-1);
  290.     if (c->type > d->type)
  291. return(1);
  292.     if (c->type < d->type)
  293. return(-1);
  294.     if ((i = strcmp(c->name, d->name)))
  295. return(i);
  296.     return(0);
  297. }
  298. /* Sort a symbol set by address, type and name */
  299. void ss_sort_atn(SYMBOL_SET *ss)
  300. {
  301.     static char const procname[] = "ss_sort_atn";
  302.     DEBUG(1, "%s", ss->source);
  303.     qsort((char *) ss->symbol, (unsigned) ss->used,
  304. sizeof(*(ss->symbol)), ss_compare_atn);
  305.     ss_compress(ss);
  306. }
  307. static int ss_compare_na(const void *a, const void *b)
  308. {
  309.     SYMBOL *c = (SYMBOL *) a;
  310.     SYMBOL *d = (SYMBOL *) b;
  311.     int i;
  312.     /* obsolete symbols to the top */
  313.     if (c->keep != d->keep)
  314. return(d->keep - c->keep);
  315.     if ((i = strcmp(c->name, d->name)))
  316. return(i);
  317.     if (c->address > d->address)
  318. return(1);
  319.     if (c->address < d->address)
  320. return(-1);
  321.     return(0);
  322. }
  323. /* Sort a symbol set by name and address, drop duplicates.  There should be
  324.  * no duplicates but I have seen duplicates in ksyms on 2.0.35.
  325.  */
  326. void ss_sort_na(SYMBOL_SET *ss)
  327. {
  328.     int i;
  329.     SYMBOL *s;
  330.     static char const procname[] = "ss_sort_na";
  331.     DEBUG(1, "%s", ss->source);
  332.     qsort((char *) ss->symbol, (unsigned) ss->used,
  333. sizeof(*(ss->symbol)), ss_compare_na);
  334.     ss_compress(ss);
  335.     s = ss->symbol;
  336.     for (i = 0; i < ss->used-1; ++i) {
  337. if (strcmp(s->name, (s+1)->name) == 0 &&
  338.     s->address == (s+1)->address) {
  339.     if (s->type != ' ')
  340. (s+1)->keep = 0;
  341.     else
  342. s->keep = 0;
  343. }
  344. ++s;
  345.     }
  346.     qsort((char *) ss->symbol, (unsigned) ss->used,
  347. sizeof(*(ss->symbol)), ss_compare_na);
  348.     ss_compress(ss);
  349. }
  350. /* Copy a symbol set, including all its strings */
  351. SYMBOL_SET *ss_copy(const SYMBOL_SET *ss)
  352. {
  353.     SYMBOL_SET *ssc;
  354.     static char const procname[] = "ss_copy";
  355.     DEBUG(4, "%s", ss->source);
  356.     ssc = malloc(sizeof(*ssc));
  357.     if (!ssc)
  358. malloc_error("copy ssc");
  359.     ss_init(ssc, ss->source);
  360.     ssc->used = ss->used;
  361.     ssc->alloc = ss->used;  /* shrink the copy */
  362.     ssc->symbol = malloc(ssc->used*sizeof(*(ssc->symbol)));
  363.     if (!(ssc->symbol))
  364. malloc_error("copy ssc symbols");
  365.     memcpy(ssc->symbol, ss->symbol, ssc->used*sizeof(*(ssc->symbol)));
  366.     return(ssc);
  367. }
  368. /* Convert version number to major, minor string.  */
  369. static const char *format_Version(addr_t Version)
  370. {
  371.     static char string[12]; /* 255.255.255 worst case */
  372.     snprintf(string, sizeof(string), "%d.%d.%d",
  373. (int) ((Version >> 16) & 0xff),
  374. (int) ((Version >> 8) & 0xff),
  375. (int) ((Version) & 0xff));
  376.     return(string);
  377. }
  378. /* Save version number.  The "address" is the version number, the "symbol" is
  379.  * the source of the version.
  380.  */
  381. void add_Version(const char *version, const char *source)
  382. {
  383.     static char const procname[] = "add_Version";
  384.     int i = atoi(version);
  385.     DEBUG(2, "%s %s %s", source, version, format_Version(i));
  386.     add_symbol_n(&ss_Version, i, 'V', 1, source);
  387. }
  388. /* Extract Version_ number from a symbol set and save it.  */
  389. void extract_Version(SYMBOL_SET *ss)
  390. {
  391.     int i = 0;
  392.     SYMBOL *s;
  393.     s = find_symbol_name(ss, "Version_", &i);
  394.     if (!s && i < ss->used)
  395. s = ss->symbol+i;   /* first symbol after "Version_" */
  396.     if (s && !strncmp(s->name, "Version_", 8))
  397. add_Version(s->name+8, ss->source);
  398. }
  399. /* Compare all extracted Version numbers.  Silent unless there is a problem. */
  400. void compare_Version(void)
  401. {
  402.     int i = 0;
  403.     SYMBOL *s, *s0;
  404.     static int prev_used = 0;
  405.     static char const procname[] = "compare_Version";
  406.     if (!ss_Version.used)
  407. return;
  408.     /* Only check if the Version table has changed in size */
  409.     if (prev_used == ss_Version.used)
  410. return;
  411.     ss_sort_na(&ss_Version);
  412.     s0 = s = ss_Version.symbol;
  413.     DEBUG(1, "Version %s", format_Version(s0->address));
  414.     for (i = 0; i < ss_Version.used; ++i, ++s) {
  415. if (s->address != s0->address) {
  416.     /* format_Version uses static area, do separate calls */
  417.     WARNING_S("Version mismatch.  %s says %s,",
  418. s0->name, format_Version(s0->address));
  419.     WARNING_E(" %s says %s.  Expect lots of address mismatches.",
  420. s->name, format_Version(s->address));
  421. }
  422.     }
  423.     prev_used = ss_Version.used;
  424. }