From 06eaf7232e9a920468c0f8d74dcf2fe8b555501c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 14:24:36 +0200 Subject: Adding upstream version 1:10.11.6. Signed-off-by: Daniel Baumann --- extra/resolve_stack_dump.c | 356 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 extra/resolve_stack_dump.c (limited to 'extra/resolve_stack_dump.c') diff --git a/extra/resolve_stack_dump.c b/extra/resolve_stack_dump.c new file mode 100644 index 00000000..fe2f297f --- /dev/null +++ b/extra/resolve_stack_dump.c @@ -0,0 +1,356 @@ +/* + Copyright (c) 2001, 2010, Oracle and/or its affiliates + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ + +/* Resolve numeric stack dump produced by mysqld 3.23.30 and later + versions into symbolic names. By Sasha Pachev + */ + +#include +#include +#include +#include +#include +#include +#include + +#define INIT_SYM_TABLE 4096 +#define INC_SYM_TABLE 4096 +#define MAX_SYM_SIZE 128 +#define DUMP_VERSION "1.4" +#define HEX_INVALID (uchar)255 + +typedef ulong my_long_addr_t ; /* at some point, we need to fix configure + * to define this for us + */ + +typedef struct sym_entry +{ + char symbol[MAX_SYM_SIZE]; + uchar* addr; +} SYM_ENTRY; + + +static char* dump_fname = 0, *sym_fname = 0; +static DYNAMIC_ARRAY sym_table; /* how do you like this , static DYNAMIC ? */ +static FILE* fp_dump, *fp_sym = 0, *fp_out; + +static struct my_option my_long_options[] = +{ + {"help", 'h', "Display this help and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"symbols-file", 's', "Use specified symbols file", &sym_fname, + &sym_fname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"numeric-dump-file", 'n', "Read the dump from specified file.", + &dump_fname, &dump_fname, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +static void verify_sort(); +static void clean_up(); + +static void print_version(void) +{ + printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION, + MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); +} + + +static void usage() +{ + print_version(); + printf("MariaDB Corporation, originally created by Sasha Pachev\n"); + printf("This software comes with ABSOLUTELY NO WARRANTY\n\n"); + printf("Resolve numeric stack strace dump into symbols.\n\n"); + printf("Usage: %s [OPTIONS] symbols-file [numeric-dump-file]\n", + my_progname); + my_print_help(my_long_options); + my_print_variables(my_long_options); + printf("\n\ +The symbols-file should include the output from: 'nm --numeric-sort mysqld'.\n\ +The numeric-dump-file should contain a numeric stack trace from mysqld.\n\ +If the numeric-dump-file is not given, the stack trace is read from stdin.\n"); +} + + +static void die(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "%s: ", my_progname); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + clean_up(); + my_end(0); + exit(1); +} + +void local_exit(int error) +{ + clean_up(); + my_end(0); + exit(error); +} + + +static my_bool +get_one_option(const struct my_option *opt, + const char *argument __attribute__((unused)), + const char *filename __attribute__((unused))) +{ + switch(opt->id) { + case 'V': + print_version(); + local_exit(0); + break; + case '?': + usage(); + local_exit(0); + break; + } + return 0; +} + + +static int parse_args(int argc, char **argv) +{ + int ho_error; + + if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) + local_exit(ho_error); + + /* + The following code is to make the command compatible with the old + version that required one to use the -n and -s options + */ + + if (argc == 2) + { + sym_fname= argv[0]; + dump_fname= argv[1]; + } + else if (argc == 1) + { + if (!sym_fname) + sym_fname = argv[0]; + else if (!dump_fname) + dump_fname = argv[0]; + else + { + usage(); + local_exit(1); + } + } + else if (argc != 0 || !sym_fname) + { + usage(); + local_exit(1); + } + return 0; +} + + +static void open_files() +{ + fp_out = stdout; + fp_dump = stdin; + + if (dump_fname && !(fp_dump = my_fopen(dump_fname, O_RDONLY, MYF(MY_WME)))) + die("Could not open %s", dump_fname); + /* if name not given, assume stdin*/ + + if (!sym_fname) + die("Please run nm --numeric-sort on mariadbd binary that produced stack \ +trace dump and specify the path to it with -s or --symbols-file"); + if (!(fp_sym = my_fopen(sym_fname, O_RDONLY, MYF(MY_WME)))) + die("Could not open %s", sym_fname); + +} + +static uchar hex_val(char c) +{ + uchar l; + if (my_isdigit(&my_charset_latin1,c)) + return c - '0'; + l = my_tolower(&my_charset_latin1,c); + if (l < 'a' || l > 'f') + return HEX_INVALID; + return (uchar)10 + ((uchar)c - (uchar)'a'); +} + +static my_long_addr_t read_addr(char** buf) +{ + uchar c; + char* p = *buf; + my_long_addr_t addr = 0; + + while((c = hex_val(*p++)) != HEX_INVALID) + addr = (addr << 4) + c; + + *buf= p-1; + return addr; +} + +static int init_sym_entry(SYM_ENTRY* se, char* buf) +{ + char* p, *p_end; + se->addr = (uchar*)read_addr(&buf); + + if (!se->addr) + return -1; + buf++; + while (my_isspace(&my_charset_latin1,*buf++)) + /* empty */; + + while (my_isspace(&my_charset_latin1,*buf++)) + /* empty - skip more space */; + --buf; + /* now we are on the symbol */ + for (p = se->symbol, p_end = se->symbol + sizeof(se->symbol) - 1; + *buf != '\n' && *buf && p < p_end; ++buf,++p) + *p = *buf; + *p = 0; + if (!strcmp(se->symbol, "gcc2_compiled.")) + return -1; + return 0; +} + +static void init_sym_table() +{ + char buf[512]; + if (my_init_dynamic_array(PSI_NOT_INSTRUMENTED, &sym_table, sizeof(SYM_ENTRY), + INIT_SYM_TABLE, INC_SYM_TABLE, MYF(0))) + die("Failed in my_init_dynamic_array() -- looks like out of memory problem"); + + while (fgets(buf, sizeof(buf), fp_sym)) + { + SYM_ENTRY se; + if (init_sym_entry(&se, buf)) + continue; + if (insert_dynamic(&sym_table, (uchar*)&se)) + die("insert_dynamic() failed - looks like we are out of memory"); + } + + verify_sort(); +} + +static void clean_up() +{ + delete_dynamic(&sym_table); + if (fp_dump && fp_dump != stdin) + my_fclose(fp_dump, MYF(0)); + if (fp_sym) + my_fclose(fp_sym, MYF(0)); +} + +static void verify_sort() +{ + uint i; + uchar* last = 0; + + for (i = 0; i < sym_table.elements; i++) + { + SYM_ENTRY se; + get_dynamic(&sym_table, (uchar*)&se, i); + if (se.addr < last) + die("sym table does not appear to be sorted, did you forget \ +--numeric-sort arg to nm? trouble addr = %p, last = %p", se.addr, last); + last = se.addr; + } +} + + +static SYM_ENTRY* resolve_addr(uchar* addr, SYM_ENTRY* se) +{ + uint i; + get_dynamic(&sym_table, (uchar*)se, 0); + if (addr < se->addr) + return 0; + + for (i = 1; i < sym_table.elements; i++) + { + get_dynamic(&sym_table, (uchar*)se, i); + if (addr < se->addr) + { + get_dynamic(&sym_table, (uchar*)se, i - 1); + return se; + } + } + + return se; +} + + +/* + Resolve anything that starts with [0x or (+0x or 0x + Skip '_end' as this is an indication of a wrong symbol (stack?) +*/ + +static void do_resolve() +{ + char buf[1024], *p; + while (fgets(buf, sizeof(buf), fp_dump)) + { + for (p= buf ; *p ; p++) + { + int found= 0; + if (p[0] == '[' && p[1] == '0' && p[2] == 'x') + found= 3; + if (p[0] == '(' && p[1] == '+' && p[2] == '0' && p[3] == 'x') + found= 4; + if (p[0] == '0' && p[1] == 'x') + found= 2; + + if (found) + { + SYM_ENTRY se ; + uchar *addr; + char *tmp= p + found; + addr= (uchar*)read_addr(&tmp); + if (resolve_addr(addr, &se) && strcmp(se.symbol, "_end")) + { + found-= 2; /* Don't print 0x as it's added by %p */ + while (found--) + fputc(*p++, stdout); + fprintf(fp_out, "%p %s + %d", addr, + se.symbol, (int) (addr - se.addr)); + p= tmp-1; + } + else + fputc(*p, stdout); + } + else + fputc(*p, stdout); + } + } +} + + +int main(int argc, char** argv) +{ + MY_INIT(argv[0]); + parse_args(argc, argv); + open_files(); + init_sym_table(); + do_resolve(); + clean_up(); + my_end(0); + return 0; +} -- cgit v1.2.3