From 3cc5f47304fd8636defa67dce967a16a60f39414 Mon Sep 17 00:00:00 2001 From: Ingo van Lil Date: Thu, 12 Jul 2012 14:13:20 +0200 Subject: [PATCH] Support for demangling of C++ symbol names. --- AUTHORS | 3 ++ Makefile | 1 + ui/sym.c | 26 +++++++--- util/demangle.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ util/demangle.h | 25 ++++++++++ util/expr.c | 3 +- util/output_util.c | 28 ++++++----- util/stab.c | 4 +- util/stab.h | 2 + 9 files changed, 189 insertions(+), 20 deletions(-) create mode 100644 util/demangle.c create mode 100644 util/demangle.h diff --git a/AUTHORS b/AUTHORS index b28b7b1..8b6e72a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -65,3 +65,6 @@ James Nuss : Tamas Tevesz : * Improvements to interactive interface. * Support for MSP430AFE253. + +Ingo van Lil : + * Support for demangling of C++ function names. diff --git a/Makefile b/Makefile index d6e8721..b32f9e8 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,7 @@ OBJ=\ util/dis.o \ util/gdb_proto.o \ util/dynload.o \ + util/demangle.o \ drivers/device.o \ drivers/bsl.o \ drivers/fet.o \ diff --git a/ui/sym.c b/ui/sym.c index 2ba54d4..6aa7879 100644 --- a/ui/sym.c +++ b/ui/sym.c @@ -32,11 +32,12 @@ #include "vector.h" #include "sym.h" #include "reader.h" +#include "demangle.h" int cmd_eval(char **arg) { address_t addr; - char name[64]; + char name[MAX_SYMBOL_LENGTH]; if (expr_eval(*arg, &addr) < 0) { printc_err("=: can't parse: %s\n", *arg); @@ -132,7 +133,12 @@ static int print_sym(void *user_data, const char *name, address_t value) { (void)user_data; - printc("0x%04x: %s\n", value, name); + char demangled[MAX_SYMBOL_LENGTH]; + if (demangle(name, demangled, sizeof(demangled)) > 0) + printc("0x%04x: %s (%s)\n", value, name, demangled); + else + printc("0x%04x: %s\n", value, name); + return 0; } @@ -140,8 +146,16 @@ static int find_sym(void *user_data, const char *name, address_t value) { regex_t *find_preg = (regex_t *)user_data; - if (!regexec(find_preg, name, 0, NULL, 0)) - printc("0x%04x: %s\n", value, name); + char demangled[MAX_SYMBOL_LENGTH]; + int len = demangle(name, demangled, sizeof(demangled)); + + if (!regexec(find_preg, name, 0, NULL, 0) || + (len > 0 && !regexec(find_preg, demangled, 0, NULL, 0))) { + if (len > 0) + printc("0x%04x: %s (%s)\n", value, name, demangled); + else + printc("0x%04x: %s\n", value, name); + } return 0; } @@ -167,7 +181,7 @@ static int cmd_sym_find(char **arg) } struct rename_record { - char old_name[64]; + char old_name[MAX_SYMBOL_LENGTH]; int start, end; }; @@ -184,7 +198,7 @@ static int renames_do(struct rename_data *rename, const char *replace) for (i = 0; i < rename->list.size; i++) { struct rename_record *r = VECTOR_PTR(rename->list, i, struct rename_record); - char new_name[128]; + char new_name[MAX_SYMBOL_LENGTH]; int len = r->start; address_t value; diff --git a/util/demangle.c b/util/demangle.c new file mode 100644 index 0000000..31ad8d6 --- /dev/null +++ b/util/demangle.c @@ -0,0 +1,117 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009-2012 Daniel Beer + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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-1301 USA + */ + +#include +#include +#include + +#include "opdb.h" +#include "stab.h" + +/* Buffer in which the demangler result will be constructed. */ +struct dmbuf { + char *out; + int max_len; + int len; +}; + +/* Add a chunk of text to the buffer */ +static int dm_append(struct dmbuf *d, const char *text, int len) +{ + int i; + + if (d->len + len + 1 > d->max_len) + return -1; + + for (i = 0; i < len; i++) { + if (!text[i]) + return -1; + + d->out[d->len++] = text[i]; + } + + d->out[d->len] = 0; + return 0; +} + +/* Demangle a single component (possibly part of a nested name). */ +static int dm_component(struct dmbuf *d, const char *text, const char **out) +{ + char *next; + unsigned int len = strtoul(text, &next, 10); + + if (next == text) + return -1; + + if (dm_append(d, next, len) < 0) + return -1; + + if (out) + *out = next + len; + + return 0; +} + +/* Demangler interface */ +int demangle(const char *raw, char *out, int max_len) +{ + struct dmbuf d; + + d.out = out; + d.max_len = max_len; + d.len = 0; + + if (*raw != '_' || raw[1] != 'Z') + return -1; + raw += 2; + + if (*raw == 'N') { + const char *next; + + /* Skip CV qualifiers */ + raw++; + while (*raw == 'v' || *raw == 'V' || *raw == 'K') + raw++; + + next = raw; + + while (*next != 'C' && *next != 'D' && *next != 'E') { + const char *comp = next; + + if (d.len > 0 && dm_append(&d, "::", 2) < 0) + return -1; + if (dm_component(&d, comp, &next) < 0) + return -1; + + if (*next == 'C' || *next == 'D') { + /* Constructor/Destructor */ + if (dm_append(&d, "::", 2) < 0) + return -1; + if (*next == 'D' && dm_append(&d, "~", 1) < 0) + return -1; + if (dm_component(&d, comp, NULL) < 0) + return -1; + } + } + } else { + if (dm_component(&d, raw, NULL) < 0) + return -1; + } + + return d.len; +} diff --git a/util/demangle.h b/util/demangle.h new file mode 100644 index 0000000..ab0e1b2 --- /dev/null +++ b/util/demangle.h @@ -0,0 +1,25 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009-2012 Daniel Beer + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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-1301 USA + */ + +#ifndef DEMANGLE_H_ +#define DEMANGLE_H_ + +/* Demangle a function name into the buffer "out". */ +int demangle(const char *raw, char *out, size_t max_len); + +#endif diff --git a/util/expr.c b/util/expr.c index 7a37501..0e08294 100644 --- a/util/expr.c +++ b/util/expr.c @@ -28,6 +28,7 @@ #include "util.h" #include "output.h" #include "opdb.h" +#include "demangle.h" /************************************************************************ * Address expression parsing. @@ -233,7 +234,7 @@ static int addr_exp_finish(struct addr_exp_state *s, address_t *ret) int expr_eval(const char *text, address_t *addr) { const char *text_save = text; - char token_buf[64]; + char token_buf[MAX_SYMBOL_LENGTH]; int token_len = 0; struct addr_exp_state s = {0}; diff --git a/util/output_util.c b/util/output_util.c index c30f408..36c770b 100644 --- a/util/output_util.c +++ b/util/output_util.c @@ -23,10 +23,11 @@ #include "output_util.h" #include "stab.h" #include "util.h" +#include "demangle.h" static int format_addr(msp430_amode_t amode, address_t addr) { - char name[64]; + char name[MAX_SYMBOL_LENGTH]; const char *prefix = ""; switch (amode) { @@ -166,14 +167,14 @@ void disassemble(address_t offset, const uint8_t *data, int length) int count; int i; address_t oboff; - char obname[64]; + char obname[MAX_SYMBOL_LENGTH]; - if (!stab_nearest(offset, obname, sizeof(obname), &oboff) && - !oboff) { - printc("\x1b[m%s\x1b[0m:\n", obname); - } else if (first_line) { - print_address(offset, obname, sizeof(obname)); - printc("\x1b[m%s\x1b[0m:\n", obname); + if (first_line || + (!stab_nearest(offset, obname, sizeof(obname), &oboff) && + !oboff)) { + char buffer[MAX_SYMBOL_LENGTH]; + print_address(offset, buffer, sizeof(buffer)); + printc("\x1b[m%s\x1b[0m:\n", buffer); } first_line = 0; @@ -254,15 +255,20 @@ void show_regs(const address_t *regs) int print_address(address_t addr, char *out, int max_len) { - char name[128]; + char name[MAX_SYMBOL_LENGTH]; address_t offset; if (!stab_nearest(addr, name, sizeof(name), &offset)) { + int len; if (offset) - snprintf(out, max_len, "%s+0x%x", name, offset); + len = snprintf(out, max_len, "%s+0x%x", name, offset); else - snprintf(out, max_len, "%s", name); + len = snprintf(out, max_len, "%s", name); + char demangled[MAX_SYMBOL_LENGTH]; + if (demangle(name, demangled, sizeof(demangled)) > 0) { + snprintf(out + len, max_len - len, " (%s)", demangled); + } return 1; } diff --git a/util/stab.c b/util/stab.c index 89935dc..c08365f 100644 --- a/util/stab.c +++ b/util/stab.c @@ -33,7 +33,7 @@ */ struct sym_key { - char name[64]; + char name[MAX_SYMBOL_LENGTH]; }; static const struct sym_key sym_key_zero = { @@ -59,7 +59,7 @@ static void sym_key_init(struct sym_key *key, const char *text) struct addr_key { address_t addr; - char name[64]; + char name[MAX_SYMBOL_LENGTH]; }; static const struct addr_key addr_key_zero = { diff --git a/util/stab.h b/util/stab.h index 68a8bfa..bbd896a 100644 --- a/util/stab.h +++ b/util/stab.h @@ -22,6 +22,8 @@ #include #include "util.h" +#define MAX_SYMBOL_LENGTH 512 + /* Create/destroy a symbol table. The constructor returns NULL if it * was unable to allocate memory for the table. */