1
/* Copyright (C) 2000 MySQL AB
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.
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.
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 */
16
/* Resolve numeric stack dump produced by mysqld 3.23.30 and later
17
versions into symbolic names. By Sasha Pachev <sasha@mysql.com>
21
#include <my_global.h>
25
#include <mysql_version.h>
27
#include <my_getopt.h>
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
35
typedef ulong my_long_addr_t ; /* at some point, we need to fix configure
36
* to define this for us
39
typedef struct sym_entry
41
char symbol[MAX_SYM_SIZE];
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;
50
static struct my_option my_long_options[] =
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,
61
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
65
static void verify_sort();
68
#include <help_start.h>
70
static void print_version(void)
72
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
73
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
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",
85
my_print_help(my_long_options);
86
my_print_variables(my_long_options);
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");
96
static void die(const char* fmt, ...)
100
fprintf(stderr, "%s: ", my_progname);
101
vfprintf(stderr, fmt, args);
102
fprintf(stderr, "\n");
109
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
110
char *argument __attribute__((unused)))
124
static int parse_args(int argc, char **argv)
128
if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
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
145
else if (!dump_fname)
146
dump_fname = argv[0];
153
else if (argc != 0 || !sym_fname)
162
static void open_files()
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*/
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);
179
static uchar hex_val(char c)
182
if (my_isdigit(&my_charset_latin1,c))
184
l = my_tolower(&my_charset_latin1,c);
185
if (l < 'a' || l > 'f')
187
return (uchar)10 + ((uchar)c - (uchar)'a');
190
static my_long_addr_t read_addr(char** buf)
194
my_long_addr_t addr = 0;
196
while((c = hex_val(*p++)) != HEX_INVALID)
197
addr = (addr << 4) + c;
203
static int init_sym_entry(SYM_ENTRY* se, char* buf)
206
se->addr = (uchar*)read_addr(&buf);
210
while (my_isspace(&my_charset_latin1,*buf++))
213
while (my_isspace(&my_charset_latin1,*buf++))
214
/* empty - skip more space */;
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)
221
if (!strcmp(se->symbol, "gcc2_compiled."))
226
static void init_sym_table()
229
if (my_init_dynamic_array(&sym_table, sizeof(SYM_ENTRY), INIT_SYM_TABLE,
231
die("Failed in my_init_dynamic_array() -- looks like out of memory problem");
233
while (fgets(buf, sizeof(buf), fp_sym))
236
if (init_sym_entry(&se, buf))
238
if (insert_dynamic(&sym_table, (uchar*)&se))
239
die("insert_dynamic() failed - looks like we are out of memory");
245
static void clean_up()
247
delete_dynamic(&sym_table);
250
static void verify_sort()
255
for (i = 0; i < sym_table.elements; i++)
258
get_dynamic(&sym_table, (uchar*)&se, i);
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);
267
static SYM_ENTRY* resolve_addr(uchar* addr, SYM_ENTRY* se)
270
get_dynamic(&sym_table, (uchar*)se, 0);
274
for (i = 1; i < sym_table.elements; i++)
276
get_dynamic(&sym_table, (uchar*)se, i);
279
get_dynamic(&sym_table, (uchar*)se, i - 1);
288
static void do_resolve()
291
while (fgets(buf, sizeof(buf), fp_dump))
295
while (my_isspace(&my_charset_latin1,*p))
298
if (*p++ == '0' && *p++ == 'x')
301
uchar* addr = (uchar*)read_addr(&p);
302
if (resolve_addr(addr, &se))
303
fprintf(fp_out, "%p %s + %d\n", addr, se.symbol,
304
(int) (addr - se.addr));
306
fprintf(fp_out, "%p (?)\n", addr);
318
int main(int argc, char** argv)
321
parse_args(argc, argv);