aboutsummaryrefslogtreecommitdiff
path: root/demangle.c
diff options
context:
space:
mode:
authorJuan Cespedes <cespedes@debian.org>1999-08-30 19:34:50 +0200
committerJuan Cespedes <cespedes@debian.org>1999-08-30 19:34:50 +0200
commit1b9cfd6ad305ad909e8ff17139111a7c78f01464 (patch)
tree352a033cfd2ab78eab367c81f30b46ec5b886947 /demangle.c
parente3eb9aa37086f16c0c8c2778dcd8020a39a92564 (diff)
downloadltrace-1b9cfd6ad305ad909e8ff17139111a7c78f01464.tar.gz
Version: 0.3.8
* glibc-2.1 does no longer need `_GNU_SOURCE' defined to use <getopt.h> * Changed description of package; adopted Red Hat's one (thanks to whoever wrote it) * Close all the file descriptors used before executing program (close-on-exec) * Updated copyright file for new location /usr/share/common-licenses/GPL. * Used GNU autoconf instead of "uname" to guess host system type * Install man page in /usr/share/man instead of /usr/man * Added a few functions to /etc/ltrace.conf * Updated list of syscalls and signals to linux-2.2.12 * Fixed bugs in C++ demangle (Morten Eriksen <mortene@sim.no>) * New Standards-Version: 3.0.1 (but keeping docs in /usr/doc)
Diffstat (limited to 'demangle.c')
-rw-r--r--demangle.c130
1 files changed, 126 insertions, 4 deletions
diff --git a/demangle.c b/demangle.c
index 3469003..cb10d73 100644
--- a/demangle.c
+++ b/demangle.c
@@ -5,15 +5,137 @@
#if HAVE_LIBIBERTY
#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "options.h"
+#include "output.h"
#include "demangle.h"
-char * my_demangle(char * function_name)
+/*****************************************************************************/
+
+/*
+ The string dictionary code done by Morten Eriksen <mortene@sim.no>.
+
+ FIXME: since this is a generic string dictionary, it should perhaps
+ be cleaned up a bit, "object-ified" and placed in its own .c + .h
+ pair of files? 19990702 mortene.
+*/
+
+struct dict_entry
+{
+ unsigned int key;
+ const char * mangled, * demangled;
+ struct dict_entry * next;
+};
+
+#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
+static struct dict_entry * dict_buckets[DICTTABLESIZE];
+static int dict_initialized = 0;
+
+static void dict_init(void);
+static void dict_clear(void);
+static void dict_enter(const char * mangled, const char * demangled);
+static const char * dict_find_entry(const char * mangled);
+static unsigned int dict_hash_string(const char * s);
+
+
+static void dict_init(void)
+{
+ int i;
+ /* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */
+ for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL;
+ dict_initialized = 1;
+}
+
+static void dict_clear(void)
+{
+ int i;
+ struct dict_entry * entry, * nextentry;
+
+ for (i = 0; i < DICTTABLESIZE; i++) {
+ for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) {
+ nextentry = entry->next;
+ free((void *)(entry->mangled));
+ if (entry->mangled != entry->demangled)
+ free((void *)(entry->demangled));
+ free(entry);
+ }
+ dict_buckets[i] = NULL;
+ }
+}
+
+static void dict_enter(const char * mangled, const char * demangled)
+{
+ struct dict_entry * entry, * newentry;
+ unsigned int key = dict_hash_string(mangled);
+
+ newentry = malloc(sizeof(struct dict_entry));
+ if (!newentry) {
+ perror("malloc");
+ return;
+ }
+
+ newentry->key = key;
+ newentry->mangled = mangled;
+ newentry->demangled = demangled;
+ newentry->next = NULL;
+
+ entry = dict_buckets[key % DICTTABLESIZE];
+ while (entry && entry->next) entry = entry->next;
+
+ if (entry) entry->next = newentry;
+ else dict_buckets[key % DICTTABLESIZE] = newentry;
+
+ if (opt_d > 2)
+ output_line(0, "new dict entry: '%s' -> '%s'\n", mangled, demangled);
+}
+
+static const char * dict_find_entry(const char * mangled)
+{
+ unsigned int key = dict_hash_string(mangled);
+ struct dict_entry * entry = dict_buckets[key % DICTTABLESIZE];
+ while (entry) {
+ if ((entry->key == key) && (strcmp(entry->mangled, mangled) == 0)) break;
+ entry = entry->next;
+ }
+ return entry ? entry->demangled : NULL;
+}
+
+static unsigned int dict_hash_string(const char * s)
+{
+ unsigned int total = 0, shift = 0;
+
+ while (*s) {
+ total = total ^ ((*s) << shift);
+ shift += 5;
+ if (shift > 24) shift -= 24;
+ s++;
+ }
+ return total;
+}
+
+#undef DICTTABLESIZE
+
+/*****************************************************************************/
+
+const char * my_demangle(const char * function_name)
{
- char * tmp;
+ const char * tmp, * fn_copy;
- tmp = cplus_demangle(function_name+strspn(function_name,"_"),DMGL_ANSI | DMGL_PARAMS);
- return tmp ? tmp : strdup(function_name);
+ if (!dict_initialized) {
+ dict_init();
+ atexit(dict_clear);
+ }
+
+ tmp = dict_find_entry(function_name);
+ if (!tmp) {
+ fn_copy = strdup(function_name);
+ tmp = cplus_demangle(function_name+strspn(function_name, "_"), DMGL_ANSI | DMGL_PARAMS);
+ if (!tmp) tmp = fn_copy;
+ if (tmp) dict_enter(fn_copy, tmp);
+ }
+ return tmp;
}
#endif