demangle.c revision 1b9cfd6ad305ad909e8ff17139111a7c78f01464
1#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#if HAVE_LIBIBERTY
6
7#include <string.h>
8#include <stdlib.h>
9#include <stdio.h>
10
11#include "options.h"
12#include "output.h"
13#include "demangle.h"
14
15/*****************************************************************************/
16
17/*
18  The string dictionary code done by Morten Eriksen <mortene@sim.no>.
19
20  FIXME: since this is a generic string dictionary, it should perhaps
21  be cleaned up a bit, "object-ified" and placed in its own .c + .h
22  pair of files? 19990702 mortene.
23*/
24
25struct dict_entry
26{
27	unsigned int key;
28	const char * mangled, * demangled;
29	struct dict_entry * next;
30};
31
32#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
33static struct dict_entry * dict_buckets[DICTTABLESIZE];
34static int dict_initialized = 0;
35
36static void dict_init(void);
37static void dict_clear(void);
38static void dict_enter(const char * mangled, const char * demangled);
39static const char * dict_find_entry(const char * mangled);
40static unsigned int dict_hash_string(const char * s);
41
42
43static void dict_init(void)
44{
45	int i;
46	/* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */
47	for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL;
48	dict_initialized = 1;
49}
50
51static void dict_clear(void)
52{
53	int i;
54	struct dict_entry * entry, * nextentry;
55
56	for (i = 0; i < DICTTABLESIZE; i++) {
57		for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) {
58			nextentry = entry->next;
59			free((void *)(entry->mangled));
60			if (entry->mangled != entry->demangled)
61				free((void *)(entry->demangled));
62			free(entry);
63		}
64		dict_buckets[i] = NULL;
65	}
66}
67
68static void dict_enter(const char * mangled, const char * demangled)
69{
70	struct dict_entry * entry, * newentry;
71	unsigned int key = dict_hash_string(mangled);
72
73	newentry = malloc(sizeof(struct dict_entry));
74	if (!newentry) {
75		perror("malloc");
76		return;
77	}
78
79	newentry->key = key;
80	newentry->mangled = mangled;
81	newentry->demangled = demangled;
82	newentry->next = NULL;
83
84	entry = dict_buckets[key % DICTTABLESIZE];
85	while (entry && entry->next) entry = entry->next;
86
87	if (entry) entry->next = newentry;
88	else dict_buckets[key % DICTTABLESIZE] = newentry;
89
90	if (opt_d > 2)
91		output_line(0, "new dict entry: '%s' -> '%s'\n", mangled, demangled);
92}
93
94static const char * dict_find_entry(const char * mangled)
95{
96	unsigned int key = dict_hash_string(mangled);
97	struct dict_entry * entry = dict_buckets[key % DICTTABLESIZE];
98	while (entry) {
99		if ((entry->key == key) && (strcmp(entry->mangled, mangled) == 0)) break;
100		entry = entry->next;
101	}
102	return entry ? entry->demangled : NULL;
103}
104
105static unsigned int dict_hash_string(const char * s)
106{
107	unsigned int total = 0, shift = 0;
108
109	while (*s) {
110		total = total ^ ((*s) << shift);
111		shift += 5;
112		if (shift > 24) shift -= 24;
113		s++;
114	}
115	return total;
116}
117
118#undef DICTTABLESIZE
119
120/*****************************************************************************/
121
122const char * my_demangle(const char * function_name)
123{
124	const char * tmp, * fn_copy;
125
126	if (!dict_initialized) {
127		dict_init();
128		atexit(dict_clear);
129	}
130
131	tmp = dict_find_entry(function_name);
132	if (!tmp) {
133		fn_copy = strdup(function_name);
134		tmp = cplus_demangle(function_name+strspn(function_name, "_"), DMGL_ANSI | DMGL_PARAMS);
135		if (!tmp) tmp = fn_copy;
136		if (tmp) dict_enter(fn_copy, tmp);
137	}
138	return tmp;
139}
140
141#endif
142