resolve_stack_dump.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:7k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* Resolve numeric stack dump produced by mysqld 3.23.30 and later
  14.    versions into symbolic names. By Sasha Pachev <sasha@mysql.com>
  15.  */
  16. #define DONT_USE_RAID
  17. #include <my_global.h>
  18. #include <m_ctype.h>
  19. #include <my_sys.h>
  20. #include <m_string.h>
  21. #include <mysql_version.h>
  22. #include <errno.h>
  23. #include <my_getopt.h>
  24. #define INIT_SYM_TABLE  4096
  25. #define INC_SYM_TABLE  4096
  26. #define MAX_SYM_SIZE   128
  27. #define DUMP_VERSION "1.4"
  28. #define HEX_INVALID  (uchar)255
  29. typedef ulong my_long_addr_t ; /* at some point, we need to fix configure
  30. * to define this for us  
  31. */
  32. typedef struct sym_entry
  33. {
  34.   char symbol[MAX_SYM_SIZE];
  35.   uchar* addr;
  36. } SYM_ENTRY;
  37. static char* dump_fname = 0, *sym_fname = 0;
  38. static DYNAMIC_ARRAY sym_table; /* how do you like this , static DYNAMIC ? */
  39. static FILE* fp_dump, *fp_sym = 0, *fp_out; 
  40. static struct my_option my_long_options[] =
  41. {
  42.   {"help", 'h', "Display this help and exit.",
  43.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  44.   {"version", 'V', "Output version information and exit.",
  45.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  46.   {"symbols-file", 's', "Use specified symbols file.", (gptr*) &sym_fname,
  47.    (gptr*) &sym_fname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  48.   {"numeric-dump-file", 'n', "Read the dump from specified file.",
  49.    (gptr*) &dump_fname, (gptr*) &dump_fname, 0, GET_STR, REQUIRED_ARG,
  50.    0, 0, 0, 0, 0, 0},
  51.   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
  52. };
  53. static void verify_sort();
  54. #include <help_start.h>
  55. static void print_version(void)
  56. {
  57.   printf("%s  Ver %s Distrib %s, for %s (%s)n",my_progname,DUMP_VERSION,
  58.  MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  59. }
  60. static void usage()
  61. {
  62.   print_version();
  63.   printf("MySQL AB, by Sasha Pachevn");
  64.   printf("This software comes with ABSOLUTELY NO WARRANTYnn");
  65.   printf("Resolve numeric stack strace dump into symbols.nn");
  66.   printf("Usage: %s [OPTIONS] symbols-file [numeric-dump-file]n",
  67.  my_progname);
  68.   my_print_help(my_long_options);
  69.   my_print_variables(my_long_options);
  70.   printf("n
  71. The symbols-file should include the output from:  'nm --numeric-sort mysqld'.n
  72. The numeric-dump-file should contain a numeric stack trace from mysqld.n
  73. If the numeric-dump-file is not given, the stack trace is read from stdin.n");
  74. }
  75. #include <help_end.h>
  76. static void die(const char* fmt, ...)
  77. {
  78.   va_list args;
  79.   va_start(args, fmt);
  80.   fprintf(stderr, "%s: ", my_progname);
  81.   vfprintf(stderr, fmt, args);
  82.   fprintf(stderr, "n");
  83.   va_end(args);
  84.   exit(1);
  85. }
  86. static my_bool
  87. get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
  88.        char *argument __attribute__((unused)))
  89. {
  90.   switch(optid) {
  91.   case 'V':
  92.     print_version();
  93.     exit(0);
  94.   case '?':
  95.     usage();
  96.     exit(0);
  97.   }
  98.   return 0;
  99. }
  100. static int parse_args(int argc, char **argv)
  101. {
  102.   int ho_error;
  103.   if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
  104.     exit(ho_error);
  105.   /*
  106.     The following code is to make the command compatible with the old
  107.     version that required one to use the -n and -s options
  108.   */
  109.   if (argc == 2)
  110.   {
  111.     sym_fname= argv[0];
  112.     dump_fname= argv[1];
  113.   }
  114.   else if (argc == 1)
  115.   {
  116.     if (!sym_fname)
  117.       sym_fname = argv[0];
  118.     else if (!dump_fname)
  119.       dump_fname = argv[0];
  120.     else
  121.     {
  122.       usage();
  123.       exit(1);
  124.     }
  125.   }
  126.   else if (argc != 0 || !sym_fname)
  127.   {
  128.     usage();
  129.     exit(1);
  130.   }
  131.   return 0;
  132. }
  133. static void open_files()
  134. {
  135.   fp_out = stdout;
  136.   fp_dump = stdin;
  137.   if (dump_fname && !(fp_dump = my_fopen(dump_fname, O_RDONLY, MYF(MY_WME))))
  138.       die("Could not open %s", dump_fname);
  139.   /* if name not given, assume stdin*/
  140.   if (!sym_fname)
  141.     die("Please run nm --numeric-sort on mysqld binary that produced stack 
  142. trace dump and specify the path to it with -s or --symbols-file");
  143.   if (!(fp_sym = my_fopen(sym_fname, O_RDONLY, MYF(MY_WME))))
  144.     die("Could not open %s", sym_fname);
  145. }
  146. static uchar hex_val(char c)
  147. {
  148.   uchar l;
  149.   if (my_isdigit(&my_charset_latin1,c))
  150.     return c - '0';
  151.   l = my_tolower(&my_charset_latin1,c);
  152.   if (l < 'a' || l > 'f')
  153.     return HEX_INVALID; 
  154.   return (uchar)10 + ((uchar)c - (uchar)'a');
  155. }
  156. static my_long_addr_t read_addr(char** buf)
  157. {
  158.   uchar c;
  159.   char* p = *buf;
  160.   my_long_addr_t addr = 0;
  161.   while((c = hex_val(*p++)) != HEX_INVALID)
  162.       addr = (addr << 4) + c;
  163.   *buf = p; 
  164.   return addr;
  165. }
  166. static int init_sym_entry(SYM_ENTRY* se, char* buf)
  167. {
  168.   char* p, *p_end;
  169.   se->addr = (uchar*)read_addr(&buf);
  170.   if (!se->addr)
  171.     return -1;
  172.   while (my_isspace(&my_charset_latin1,*buf++))
  173.     /* empty */;
  174.   while (my_isspace(&my_charset_latin1,*buf++))
  175.     /* empty - skip more space */;
  176.   --buf;
  177.   /* now we are on the symbol */
  178.   for (p = se->symbol, p_end = se->symbol + sizeof(se->symbol) - 1;
  179.        *buf != 'n' && *buf && p < p_end; ++buf,++p)
  180.     *p = *buf;
  181.   *p = 0;
  182.   if (!strcmp(se->symbol, "gcc2_compiled."))
  183.     return -1;
  184.   return 0;
  185. }
  186. static void init_sym_table()
  187. {
  188.   char buf[512];
  189.   if (my_init_dynamic_array(&sym_table, sizeof(SYM_ENTRY), INIT_SYM_TABLE,
  190.     INC_SYM_TABLE))
  191.     die("Failed in my_init_dynamic_array() -- looks like out of memory problem");
  192.   while (fgets(buf, sizeof(buf), fp_sym))
  193.   {
  194.     SYM_ENTRY se;
  195.     if (init_sym_entry(&se, buf))
  196.       continue;
  197.     if (insert_dynamic(&sym_table, (gptr)&se))
  198.       die("insert_dynamic() failed - looks like we are out of memory");
  199.   }
  200.   verify_sort();
  201. }
  202. static void clean_up()
  203. {
  204.   delete_dynamic(&sym_table);
  205. }
  206. static void verify_sort()
  207. {
  208.   uint i;
  209.   uchar* last = 0;
  210.   for (i = 0; i < sym_table.elements; i++)
  211.   {
  212.     SYM_ENTRY se;
  213.     get_dynamic(&sym_table, (gptr)&se, i);
  214.     if (se.addr < last)
  215.       die("sym table does not appear to be sorted, did you forget 
  216. --numeric-sort arg to nm? trouble addr = %p, last = %p", se.addr, last);
  217.     last = se.addr;
  218.   }
  219. }
  220. static SYM_ENTRY* resolve_addr(uchar* addr, SYM_ENTRY* se)
  221. {
  222.   uint i;
  223.   get_dynamic(&sym_table, (gptr)se, 0);
  224.   if (addr < se->addr)
  225.     return 0;
  226.   for (i = 1; i < sym_table.elements; i++)
  227.   {
  228.     get_dynamic(&sym_table, (gptr)se, i);
  229.     if (addr < se->addr)
  230.     {
  231.       get_dynamic(&sym_table, (gptr)se, i - 1);
  232.       return se;
  233.     }
  234.   }
  235.   return se;
  236. }
  237. static void do_resolve()
  238. {
  239.   char buf[1024], *p;
  240.   while (fgets(buf, sizeof(buf), fp_dump))
  241.   {
  242.     p = buf;
  243.     /* skip space */
  244.     while (my_isspace(&my_charset_latin1,*p))
  245.       ++p;
  246.     if (*p++ == '0' && *p++ == 'x')
  247.     {
  248.       SYM_ENTRY se ;
  249.       uchar* addr = (uchar*)read_addr(&p);
  250.       if (resolve_addr(addr, &se))
  251. fprintf(fp_out, "%p %s + %dn", addr, se.symbol,
  252. (int) (addr - se.addr));
  253.       else
  254. fprintf(fp_out, "%p (?)n", addr);
  255.     }
  256.     else
  257.     {
  258.       fputs(buf, fp_out);
  259.       continue;
  260.     }
  261.   }
  262. }
  263. int main(int argc, char** argv)
  264. {
  265.   MY_INIT(argv[0]);
  266.   parse_args(argc, argv);
  267.   open_files();
  268.   init_sym_table();
  269.   do_resolve();
  270.   clean_up();
  271.   return 0;
  272. }