~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to extra/resolve_stack_dump.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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