1 /* MSPDebug - debugging tool for the eZ430
2  * Copyright (C) 2009, 2010 Daniel Beer
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <stdint.h>
24 #include <regex.h>
25 #include <assert.h>
26 #include "btree.h"
27 #include "stab.h"
28 #include "util.h"
29 #include "output.h"
30 
31 /************************************************************************
32  * B+Tree definitions
33  */
34 
35 struct sym_key {
36 	char name[MAX_SYMBOL_LENGTH];
37 };
38 
39 static const struct sym_key sym_key_zero = {
40 	.name = {0}
41 };
42 
sym_key_compare(const void * left,const void * right)43 static int sym_key_compare(const void *left, const void *right)
44 {
45 	return strcmp(((const struct sym_key *)left)->name,
46 		      ((const struct sym_key *)right)->name);
47 }
48 
sym_key_init(struct sym_key * key,const char * text)49 static void sym_key_init(struct sym_key *key, const char *text)
50 {
51 	int len = strlen(text);
52 
53 	if (len >= sizeof(key->name))
54 		len = sizeof(key->name) - 1;
55 
56 	memcpy(key->name, text, len);
57 	key->name[len] = 0;
58 }
59 
60 struct addr_key {
61 	address_t      addr;
62 	char           name[MAX_SYMBOL_LENGTH];
63 };
64 
65 static const struct addr_key addr_key_zero = {
66 	.addr = 0,
67 	.name = {0}
68 };
69 
addr_key_compare(const void * left,const void * right)70 static int addr_key_compare(const void *left, const void *right)
71 {
72 	const struct addr_key *kl = (const struct addr_key *)left;
73 	const struct addr_key *kr = (const struct addr_key *)right;
74 
75 	if (kl->addr < kr->addr)
76 		return -1;
77 	if (kl->addr > kr->addr)
78 		return 1;
79 
80 	return strcmp(kl->name, kr->name);
81 }
82 
addr_key_init(struct addr_key * key,address_t addr,const char * text)83 static void addr_key_init(struct addr_key *key, address_t addr,
84 			  const char *text)
85 {
86 	int len = strlen(text);
87 
88 	if (len >= sizeof(key->name))
89 		len = sizeof(key->name) - 1;
90 
91 	key->addr = addr;
92 	memcpy(key->name, text, len);
93 	key->name[len] = 0;
94 }
95 
96 static const struct btree_def sym_table_def = {
97 	.compare = sym_key_compare,
98 	.zero = &sym_key_zero,
99 	.branches = 32,
100 	.key_size = sizeof(struct sym_key),
101 	.data_size = sizeof(address_t)
102 };
103 
104 static const struct btree_def addr_table_def = {
105 	.compare = addr_key_compare,
106 	.zero = &addr_key_zero,
107 	.branches = 32,
108 	.key_size = sizeof(struct addr_key),
109 	.data_size = 0
110 };
111 
112 /************************************************************************
113  * Symbol table methods
114  */
115 
116 static btree_t         stab_sym;
117 static btree_t         stab_addr;
118 
stab_clear(void)119 void stab_clear(void)
120 {
121 	btree_clear(stab_sym);
122 	btree_clear(stab_addr);
123 }
124 
stab_set(const char * name,int value)125 int stab_set(const char *name, int value)
126 {
127 	struct sym_key skey;
128 	struct addr_key akey;
129 	address_t addr = value;
130 	address_t old_addr;
131 
132 	sym_key_init(&skey, name);
133 
134 	/* Look for an old address first, and delete the reverse mapping
135 	 * if it's there.
136 	 */
137 	if (!btree_get(stab_sym, &skey, &old_addr)) {
138 		addr_key_init(&akey, old_addr, skey.name);
139 		btree_delete(stab_addr, &akey);
140 	}
141 
142 	/* Put the new mapping into both tables */
143 	addr_key_init(&akey, addr, name);
144 	if (btree_put(stab_addr, &akey, NULL) < 0 ||
145 	    btree_put(stab_sym, &skey, &addr) < 0) {
146 		printc_err("stab: can't set %s = 0x%04x\n", name, addr);
147 		return -1;
148 	}
149 
150 	return 0;
151 }
152 
stab_nearest(address_t addr,char * ret_name,int max_len,address_t * ret_offset)153 int stab_nearest(address_t addr, char *ret_name, int max_len,
154 		 address_t *ret_offset)
155 {
156 	struct addr_key akey;
157 	int i;
158 
159 	akey.addr = addr;
160 	for (i = 0; i < sizeof(akey.name); i++)
161 		akey.name[i] = 0xff;
162 	akey.name[sizeof(akey.name) - 1] = 0xff;
163 
164 	if (!btree_select(stab_addr, &akey, BTREE_LE, &akey, NULL)) {
165 		strncpy(ret_name, akey.name, max_len);
166 		ret_name[max_len - 1] = 0;
167 		*ret_offset = addr - akey.addr;
168 		return 0;
169 	}
170 
171 	return -1;
172 }
173 
stab_get(const char * name,address_t * value)174 int stab_get(const char *name, address_t *value)
175 {
176 	struct sym_key skey;
177 	address_t addr;
178 
179 	sym_key_init(&skey, name);
180 	if (btree_get(stab_sym, &skey, &addr))
181 		return -1;
182 
183 	*value = addr;
184 	return 0;
185 }
186 
stab_del(const char * name)187 int stab_del(const char *name)
188 {
189 	struct sym_key skey;
190 	address_t value;
191 	struct addr_key akey;
192 
193 	sym_key_init(&skey, name);
194 	if (btree_get(stab_sym, &skey, &value))
195 		return -1;
196 
197 	addr_key_init(&akey, value, name);
198 	btree_delete(stab_sym, &skey);
199 	btree_delete(stab_addr, &akey);
200 
201 	return 0;
202 }
203 
stab_enum(stab_callback_t cb,void * user_data)204 int stab_enum(stab_callback_t cb, void *user_data)
205 {
206 	int ret;
207 	struct addr_key akey;
208 
209 	ret = btree_select(stab_addr, NULL, BTREE_FIRST,
210 			   &akey, NULL);
211 	while (!ret) {
212 		if (cb(user_data, akey.name, akey.addr) < 0)
213 			return -1;
214 		ret = btree_select(stab_addr, NULL, BTREE_NEXT,
215 				   &akey, NULL);
216 	}
217 
218 	return 0;
219 }
220 
stab_init(void)221 int stab_init(void)
222 {
223 	stab_sym = btree_alloc(&sym_table_def);
224 	if (!stab_sym) {
225 		printc_err("stab: failed to allocate symbol table\n");
226 		return -1;
227 	}
228 
229 	stab_addr = btree_alloc(&addr_table_def);
230 	if (!stab_addr) {
231 		printc_err("stab: failed to allocate address table\n");
232 		btree_free(stab_sym);
233 		return -1;
234 	}
235 
236         return 0;
237 }
238 
stab_exit(void)239 void stab_exit(void)
240 {
241 	btree_free(stab_sym);
242 	btree_free(stab_addr);
243 }
244