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

驱动编程

开发平台:

C/C++

  1. /*
  2.     ksyms.c.
  3.     Process ksyms 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. /* Modutils adds symbols to assist ksymoops.  Decode them here.
  13.  * Use type 'G' for generated symbols added by modutils (discarded in
  14.  * the final map), type 'g' for derived generated symbols (kept in the
  15.  * final map).
  16.  */
  17. static void assist_ksyms(SYMBOL_SET *ss, int symnum)
  18. {
  19.     int i;
  20.     char **string = NULL;
  21.     static regex_t     re_modutils;
  22.     static regmatch_t *re_modutils_pmatch;
  23.     static char const procname[] = "assist_ksyms";
  24.     RE_COMPILE(&re_modutils,
  25. "^(" MODUTILS_PREFIX ".*)" /* 1, prefix, module name */
  26. "(" /* 2 */
  27.    "_O(.*)" /* 3 object filename */
  28.    "_M([0-9a-fA-F]+)" /* 4 mtime, hex */
  29.    "_V(-?[0-9]+)" /* 5 version, dec */
  30. "|"
  31.    "_S(.*)" /* 6 section name */
  32.    "_L([0-9]+)" /* 7 length, dec */
  33. ")",
  34. REG_NEWLINE|REG_EXTENDED,
  35. &re_modutils_pmatch);
  36.     i = regexec(&re_modutils, (ss->symbol)[symnum].name,
  37.     re_modutils.re_nsub+1, re_modutils_pmatch, 0);
  38.     DEBUG(4, "regexec %d", i);
  39.     if (i)
  40. return;
  41.     re_strings(&re_modutils, (ss->symbol)[symnum].name, re_modutils_pmatch,
  42. &string);
  43.     if (string[3]) {
  44. /* object filename, mtime, version */
  45. ss->object = string[3];
  46. string[3] = NULL;   /* do not free this substring */
  47. errno = 0;
  48. ss->mtime = hexstring(string[4]);
  49. if (errno) {
  50.     ERROR("mtime '%s' is not valid hex", string[4]);
  51.     perror(prefix);
  52.     ss->mtime = 0;
  53. }
  54. if (*(string[5]) != '-')    /* -ve means no version available */
  55.     add_Version(string[5], ss->source);
  56.     }
  57.     else if (string[6]) {
  58. /* section name, length */
  59. U64 end;
  60. int l;
  61. char *gsym;
  62. l = re_modutils_pmatch[6].rm_eo -
  63.       re_modutils_pmatch[6].rm_so + 1 + /* section name */
  64.     5 + /* ".start" */
  65.     1; /* nul */
  66. gsym = malloc(l);
  67. if (!gsym)
  68.     malloc_error("alloc gsym");
  69. snprintf(gsym, l, "%s.start", string[6]);
  70. add_symbol_n(ss, (ss->symbol)[symnum].address, 'g', 1, gsym);
  71. errno = 0;
  72. end = strtoul(string[7], NULL, 10);
  73. if (errno) {
  74.     ERROR("mtime '%s' is not valid decimal", string[7]);
  75.     perror(prefix);
  76.     end = 0;
  77. }
  78. if (end) {
  79.     end = (ss->symbol)[symnum].address + end - 1;
  80.     snprintf(gsym, l, "%s.end", string[6]);
  81.     add_symbol_n(ss, end, 'g', 1, gsym);
  82. }
  83. free(gsym);
  84.     }
  85.     re_strings_free(&re_modutils, &string);
  86. }
  87. void add_ksyms(const char *address, char type, const char *symbol, const char *module,
  88.        const OPTIONS *options)
  89. {
  90.     int n;
  91.     SYMBOL_SET *ssp;
  92.     static char *prev_module = NULL;
  93.     if (module) {
  94. if (!prev_module || strcmp(prev_module, module)) {
  95.     /* start of a new module in ksyms */
  96.     ++ss_ksyms_modules;
  97.     ss_ksyms_module = realloc(ss_ksyms_module,
  98. ss_ksyms_modules*sizeof(*ss_ksyms_module));
  99.     if (!ss_ksyms_module)
  100. malloc_error("realloc ss_ksyms_module");
  101.     ssp = ss_ksyms_module[ss_ksyms_modules-1] =
  102. malloc(sizeof(*(ss_ksyms_module[0])));
  103.     if (!ssp)
  104. malloc_error("alloc ss_ksyms_module[n]");
  105.     ss_init(ssp, module);
  106.     prev_module = strdup(module);
  107.     if (!prev_module)
  108. malloc_error("strdup prev_module");
  109. }
  110. ssp = ss_ksyms_module[ss_ksyms_modules-1];
  111.     }
  112.     else
  113. ssp = &ss_ksyms_base;
  114.     if (type == ' ' && strncmp(symbol, MODUTILS_PREFIX, sizeof(MODUTILS_PREFIX)-1) == 0) {
  115. if (options->ignore_insmod_all)
  116.     return;
  117. type = 'G'; /* generated symbol to assist ksymoops */
  118.     }
  119.     n = add_symbol(ssp, address, type, 1, symbol);
  120.     if (type == 'G')
  121. assist_ksyms(ssp, n);
  122. }
  123. /* Scan one line from ksyms.  Split lines into the base symbols and the module
  124.  * symbols.  Separate ss for base and each module.
  125.  */
  126. static void scan_ksyms_line(const char *line, const OPTIONS *options)
  127. {
  128.     int i;
  129.     char **string = NULL;
  130.     static regex_t     re_ksyms;
  131.     static regmatch_t *re_ksyms_pmatch;
  132.     static char const procname[] = "scan_ksyms_line";
  133.     /* ksyms: address, symbol, optional module */
  134.     RE_COMPILE(&re_ksyms,
  135. "^([0-9a-fA-F]{4,})" /* 1 address */
  136. " +" /* white space */
  137. "([^ ]+)" /* 2 symbol */
  138. "( +\[([^ ]+)\])?$", /* 3,4 space, module (optional) */
  139. REG_NEWLINE|REG_EXTENDED,
  140. &re_ksyms_pmatch);
  141.     i = regexec(&re_ksyms, line,
  142.     re_ksyms.re_nsub+1, re_ksyms_pmatch, 0);
  143.     DEBUG(4, "regexec %d", i);
  144.     if (i)
  145. return;
  146.     re_strings(&re_ksyms, line, re_ksyms_pmatch, &string);
  147.     if (strncmp(string[2], "GPLONLY_", 8) == 0)
  148. strcpy(string[2], string[2]+8);
  149.     add_ksyms(string[1], ' ', string[2], string[4], options);
  150.     re_strings_free(&re_ksyms, &string);
  151. }
  152. /* Read the symbols from ksyms.  */
  153. void read_ksyms(const OPTIONS *options)
  154. {
  155.     FILE *f;
  156.     char *line = NULL;
  157.     int i, size;
  158.     static char const procname[] = "read_ksyms";
  159.     const char *ksyms = options->ksyms;
  160.     if (!ksyms)
  161. return;
  162.     ss_init(&ss_ksyms_base, "ksyms_base");
  163.     DEBUG(1, "%s", ksyms);
  164.     if (!regular_file(ksyms, procname))
  165. return;
  166.     if (!(f = fopen_local(ksyms, "r", procname)))
  167. return;
  168.     while (fgets_local(&line, &size, f, procname))
  169. scan_ksyms_line(line, options);
  170.     fclose_local(f, procname);
  171.     free(line);
  172.     for (i = 0; i < ss_ksyms_modules; ++i) {
  173. ss_sort_na(ss_ksyms_module[i]);
  174. extract_Version(ss_ksyms_module[i]);
  175.     }
  176.     if (ss_ksyms_base.used) {
  177. ss_sort_na(&ss_ksyms_base);
  178. extract_Version(&ss_ksyms_base);
  179.     }
  180.     else {
  181. WARNING("no kernel symbols in ksyms, is %s a valid ksyms file?",
  182.     ksyms);
  183.     }
  184.      for (i = 0; i < ss_ksyms_modules; ++i) {
  185.  DEBUG(2, "%s used %d out of %d entries",
  186.      ss_ksyms_module[i]->source,
  187.      ss_ksyms_module[i]->used,
  188.      ss_ksyms_module[i]->alloc);
  189.      }
  190.      DEBUG(2, "%s used %d out of %d entries", ss_ksyms_base.source,
  191.  ss_ksyms_base.used, ss_ksyms_base.alloc);
  192. }
  193. /* Map each ksyms module entry to the corresponding object entry.  Tricky,
  194.  * see the comments in the docs about needing a unique symbol in each
  195.  * module.
  196.  */
  197. static void map_ksym_to_module(SYMBOL_SET *ss)
  198. {
  199.     int i, j, matches;
  200.     char *name = NULL;
  201.     static char const procname[] = "map_ksym_to_module";
  202.     for (i = 0; i < ss->used; ++i) {
  203. matches = 0;
  204. for (j = 0; j < ss_objects; ++j) {
  205.     name = (ss->symbol)[i].name;
  206.     if (find_symbol_name(ss_object[j], name, NULL)) {
  207. ++matches;
  208. ss->related = ss_object[j];
  209.     }
  210. }
  211. if (matches == 1)
  212.     break;      /* unique symbol over all objects */
  213. ss->related = NULL; /* keep looking */
  214.     }
  215.     if (!(ss->related)) {
  216. WARNING("cannot match loaded module %s to a unique module object.  "
  217. "Trace may not be reliable.", ss->source);
  218.     }
  219.     else DEBUG(1, "ksyms %s matches to %s based on unique symbol %s",
  220.        ss->source, ss->related->source, name);
  221. }
  222. /* Map all ksyms module entries to their corresponding objects */
  223. void map_ksyms_to_modules(void)
  224. {
  225.     int i;
  226.     SYMBOL_SET *ss, *ssc;
  227.     static char const procname[] = "map_ksyms_to_modules";
  228.     for (i = 0; i < ss_ksyms_modules; ++i) {
  229. ss = ss_ksyms_module[i];
  230. if (ss->related) {
  231.     DEBUG(1, "ksyms %s matches to %s based on modutils assist",
  232. ss->source, ss->related->source);
  233. }
  234. else
  235.     map_ksym_to_module(ss);
  236. if (ss->related) {
  237.     ssc = adjust_object_offsets(ss);
  238.     compare_maps(ss, ssc, 1);
  239. }
  240.     }
  241. }
  242. /* Read the modules from lsmod.  */
  243. void read_lsmod(const OPTIONS *options)
  244. {
  245.     FILE *f;
  246.     char *line = NULL;
  247.     int i, size;
  248.     char **string = NULL;
  249.     static regex_t     re_lsmod;
  250.     static regmatch_t *re_lsmod_pmatch;
  251.     static char const procname[] = "read_lsmod";
  252.     const char *lsmod = options->lsmod;
  253.     if (!lsmod)
  254. return;
  255.     ss_init(&ss_lsmod, "lsmod");
  256.     DEBUG(1, "%s", lsmod);
  257.     if (!regular_file(lsmod, procname))
  258. return;
  259.     if (!(f = fopen_local(lsmod, "r", procname)))
  260. return;
  261.     /* lsmod: module, size, use count, optional used by */
  262.     RE_COMPILE(&re_lsmod,
  263. "^"
  264. " *([^ ]+)"                 /* 1 module */
  265. " *([^ ]+)"                 /* 2 size */
  266. " *([^ ]+)"                 /* 3 count */
  267. " *(.*)"                    /* 4 used by */
  268. "$",
  269. REG_NEWLINE|REG_EXTENDED,
  270. &re_lsmod_pmatch);
  271.     while (fgets_local(&line, &size, f, procname)) {
  272. i = regexec(&re_lsmod, line,
  273. re_lsmod.re_nsub+1, re_lsmod_pmatch, 0);
  274. DEBUG(4, "regexec %d", i);
  275. if (i)
  276.     continue;
  277. re_strings(&re_lsmod, line, re_lsmod_pmatch, &string);
  278. add_symbol(&ss_lsmod, string[2], ' ', 1, string[1]);
  279.     }
  280.     fclose_local(f, procname);
  281.     free(line);
  282.     re_strings_free(&re_lsmod, &string);
  283.     if (ss_lsmod.used)
  284. ss_sort_na(&ss_lsmod);
  285.     else {
  286. WARNING("no symbols in lsmod, is %s a valid lsmod file?",
  287.     lsmod);
  288.     }
  289.     DEBUG(2, "%s used %d out of %d entries", ss_lsmod.source, ss_lsmod.used,
  290. ss_lsmod.alloc);
  291. }
  292. /* Compare modules from ksyms against module list in lsmod and vice versa.
  293.  * There is one ss_ for each ksyms module and a single ss_lsmod to cross
  294.  * check.
  295.  */
  296. void compare_ksyms_lsmod(void)
  297. {
  298.     int i, j;
  299.     SYMBOL_SET *ss;
  300.     SYMBOL *s;
  301.     static char const procname[] = "compare_ksyms_lsmod";
  302.     if (!(ss_lsmod.used && ss_ksyms_modules))
  303. return;
  304.     s = ss_lsmod.symbol;
  305.     for (i = 0; i < ss_lsmod.used; ++i, ++s) {
  306. for (j = 0; j < ss_ksyms_modules; ++j) {
  307.     ss = ss_ksyms_module[j];
  308.     if (strcmp(s->name, ss->source) == 0)
  309. break;
  310. }
  311. if (j >= ss_ksyms_modules) {
  312.     WARNING("module %s is in lsmod but not in ksyms, probably no "
  313.     "symbols exported", s->name);
  314. }
  315.     }
  316.     for (i = 0; i < ss_ksyms_modules; ++i) {
  317. ss = ss_ksyms_module[i];
  318. if (!find_symbol_name(&ss_lsmod, ss->source, NULL))
  319.     ERROR("module %s is in ksyms but not in lsmod", ss->source);
  320.     }
  321. }