1 /* $OpenBSD: aicasm_symbol.c,v 1.6 2002/11/19 18:36:18 jason Exp $ */
2 /*
3  * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
4  *
5  * Copyright (c) 1997 Justin T. Gibbs.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification.
14  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15  *    substantially similar to the "NO WARRANTY" disclaimer below
16  *    ("Disclaimer") and any redistribution must be conditioned upon
17  *    including a substantially similar Disclaimer requirement for further
18  *    binary redistribution.
19  * 3. Neither the names of the above-listed copyright holders nor the names
20  *    of any contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * Alternatively, this software may be distributed under the terms of the
24  * GNU General Public License ("GPL") version 2 as published by the Free
25  * Software Foundation.
26  *
27  * NO WARRANTY
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
37  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGES.
39  *
40  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.17 2002/06/06 16:07:18 gibbs Exp $
41  */
42 
43 #include <sys/types.h>
44 
45 #include <db.h>
46 #include <fcntl.h>
47 #include <regex.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <sysexits.h>
52 
53 #include "aicasm_symbol.h"
54 #include "aicasm.h"
55 
56 static DB *symtable;
57 
58 symbol_t *
59 symbol_create(name)
60 	char *name;
61 {
62 	symbol_t *new_symbol;
63 
64 	new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
65 	if (new_symbol == NULL) {
66 		perror("Unable to create new symbol");
67 		exit(EX_SOFTWARE);
68 	}
69 	memset(new_symbol, 0, sizeof(*new_symbol));
70 	new_symbol->name = strdup(name);
71 	new_symbol->type = UNINITIALIZED;
72 	return (new_symbol);
73 }
74 
75 void
76 symbol_delete(symbol)
77 	symbol_t *symbol;
78 {
79 	if (symtable != NULL) {
80 		DBT	 key;
81 
82 		key.data = symbol->name;
83 		key.size = strlen(symbol->name);
84 		symtable->del(symtable, &key, /*flags*/0);
85 	}
86 	switch(symbol->type) {
87 	case SCBLOC:
88 	case SRAMLOC:
89 	case REGISTER:
90 		if (symbol->info.rinfo != NULL)
91 			free(symbol->info.rinfo);
92 		break;
93 	case ALIAS:
94 		if (symbol->info.ainfo != NULL)
95 			free(symbol->info.ainfo);
96 		break;
97 	case MASK:
98 	case BIT:
99 		if (symbol->info.minfo != NULL) {
100 			symlist_free(&symbol->info.minfo->symrefs);
101 			free(symbol->info.minfo);
102 		}
103 		break;
104 	case DOWNLOAD_CONST:
105 	case CONST:
106 		if (symbol->info.cinfo != NULL)
107 			free(symbol->info.cinfo);
108 		break;
109 	case LABEL:
110 		if (symbol->info.linfo != NULL)
111 			free(symbol->info.linfo);
112 		break;
113 	case UNINITIALIZED:
114 	default:
115 		break;
116 	}
117 	free(symbol->name);
118 	free(symbol);
119 }
120 
121 void
122 symtable_open()
123 {
124 	symtable = dbopen(/*filename*/NULL,
125 			  O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
126 			  /*openinfo*/NULL);
127 
128 	if (symtable == NULL) {
129 		perror("Symbol table creation failed");
130 		exit(EX_SOFTWARE);
131 		/* NOTREACHED */
132 	}
133 }
134 
135 void
136 symtable_close()
137 {
138 	if (symtable != NULL) {
139 		DBT	 key;
140 		DBT	 data;
141 
142 		while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
143 			symbol_t *stored_ptr;
144 
145 			memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
146 			symbol_delete(stored_ptr);
147 		}
148 		symtable->close(symtable);
149 	}
150 }
151 
152 /*
153  * The semantics of get is to return an uninitialized symbol entry
154  * if a lookup fails.
155  */
156 symbol_t *
157 symtable_get(name)
158 	char *name;
159 {
160 	symbol_t *stored_ptr;
161 	DBT	  key;
162 	DBT	  data;
163 	int	  retval;
164 
165 	key.data = (void *)name;
166 	key.size = strlen(name);
167 
168 	if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
169 		if (retval == -1) {
170 			perror("Symbol table get operation failed");
171 			exit(EX_SOFTWARE);
172 			/* NOTREACHED */
173 		} else if (retval == 1) {
174 			/* Symbol wasn't found, so create a new one */
175 			symbol_t *new_symbol;
176 
177 			new_symbol = symbol_create(name);
178 			data.data = &new_symbol;
179 			data.size = sizeof(new_symbol);
180 			if (symtable->put(symtable, &key, &data,
181 					  /*flags*/0) !=0) {
182 				perror("Symtable put failed");
183 				exit(EX_SOFTWARE);
184 			}
185 			return (new_symbol);
186 		} else {
187 			perror("Unexpected return value from db get routine");
188 			exit(EX_SOFTWARE);
189 			/* NOTREACHED */
190 		}
191 	}
192 	memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
193 	return (stored_ptr);
194 }
195 
196 symbol_node_t *
197 symlist_search(symlist, symname)
198 	symlist_t *symlist;
199 	char	  *symname;
200 {
201 	symbol_node_t *curnode;
202 
203 	SLIST_FOREACH(curnode, symlist, links) {
204 		if (strcmp(symname, curnode->symbol->name) == 0)
205 			break;
206 	}
207 	return (curnode);
208 }
209 
210 void
211 symlist_add(symlist, symbol, how)
212 	symlist_t *symlist;
213 	symbol_t  *symbol;
214 	int	  how;
215 {
216 	symbol_node_t *newnode;
217 
218 	newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
219 	if (newnode == NULL) {
220 		stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
221 		/* NOTREACHED */
222 	}
223 	newnode->symbol = symbol;
224 	if (how == SYMLIST_SORT) {
225 		symbol_node_t *curnode;
226 		int mask;
227 
228 		mask = FALSE;
229 		switch(symbol->type) {
230 		case REGISTER:
231 		case SCBLOC:
232 		case SRAMLOC:
233 			break;
234 		case BIT:
235 		case MASK:
236 			mask = TRUE;
237 			break;
238 		default:
239 			stop("symlist_add: Invalid symbol type for sorting",
240 			     EX_SOFTWARE);
241 			/* NOTREACHED */
242 		}
243 
244 		curnode = SLIST_FIRST(symlist);
245 		if (curnode == NULL
246 		 || (mask && (curnode->symbol->info.minfo->mask >
247 		              newnode->symbol->info.minfo->mask))
248 		 || (!mask && (curnode->symbol->info.rinfo->address >
249 		               newnode->symbol->info.rinfo->address))) {
250 			SLIST_INSERT_HEAD(symlist, newnode, links);
251 			return;
252 		}
253 
254 		while (1) {
255 			if (SLIST_NEXT(curnode, links) == SLIST_END(symlist)) {
256 				SLIST_INSERT_AFTER(curnode, newnode,
257 						   links);
258 				break;
259 			} else {
260 				symbol_t *cursymbol;
261 
262 				cursymbol = SLIST_NEXT(curnode, links)->symbol;
263 				if ((mask && (cursymbol->info.minfo->mask >
264 				              symbol->info.minfo->mask))
265 				 || (!mask &&(cursymbol->info.rinfo->address >
266 				              symbol->info.rinfo->address))){
267 					SLIST_INSERT_AFTER(curnode, newnode,
268 							   links);
269 					break;
270 				}
271 			}
272 			curnode = SLIST_NEXT(curnode, links);
273 		}
274 	} else {
275 		SLIST_INSERT_HEAD(symlist, newnode, links);
276 	}
277 }
278 
279 void
280 symlist_free(symlist)
281 	symlist_t *symlist;
282 {
283 	symbol_node_t *node;
284 
285 	while (!SLIST_EMPTY(symlist)) {
286 		node = SLIST_FIRST(symlist);
287 		SLIST_REMOVE_HEAD(symlist, links);
288 		free(node);
289 	}
290 }
291 
292 void
293 symlist_merge(symlist_dest, symlist_src1, symlist_src2)
294 	symlist_t *symlist_dest;
295 	symlist_t *symlist_src1;
296 	symlist_t *symlist_src2;
297 {
298 	symbol_node_t *node;
299 
300 	*symlist_dest = *symlist_src1;
301 	while((node = SLIST_FIRST(symlist_src2)) != NULL) {
302 		SLIST_REMOVE_HEAD(symlist_src2, links);
303 		SLIST_INSERT_HEAD(symlist_dest, node, links);
304 	}
305 
306 	/* These are now empty */
307 	SLIST_INIT(symlist_src1);
308 	SLIST_INIT(symlist_src2);
309 }
310 
311 void
312 symtable_dump(ofile)
313 	FILE *ofile;
314 {
315 	/*
316 	 * Sort the registers by address with a simple insertion sort.
317 	 * Put bitmasks next to the first register that defines them.
318 	 * Put constants at the end.
319 	 */
320 	symlist_t registers;
321 	symlist_t masks;
322 	symlist_t constants;
323 	symlist_t download_constants;
324 	symlist_t aliases;
325 	symlist_t exported_labels;
326 	u_int	  i;
327 
328 	SLIST_INIT(&registers);
329 	SLIST_INIT(&masks);
330 	SLIST_INIT(&constants);
331 	SLIST_INIT(&download_constants);
332 	SLIST_INIT(&aliases);
333 	SLIST_INIT(&exported_labels);
334 
335 	if (symtable != NULL) {
336 		DBT	 key;
337 		DBT	 data;
338 		int	 flag = R_FIRST;
339 
340 		while (symtable->seq(symtable, &key, &data, flag) == 0) {
341 			symbol_t *cursym;
342 
343 			memcpy(&cursym, data.data, sizeof(cursym));
344 			switch(cursym->type) {
345 			case REGISTER:
346 			case SCBLOC:
347 			case SRAMLOC:
348 				symlist_add(&registers, cursym, SYMLIST_SORT);
349 				break;
350 			case MASK:
351 			case BIT:
352 				symlist_add(&masks, cursym, SYMLIST_SORT);
353 				break;
354 			case CONST:
355 				symlist_add(&constants, cursym,
356 						    SYMLIST_INSERT_HEAD);
357 				break;
358 			case DOWNLOAD_CONST:
359 				symlist_add(&download_constants, cursym,
360 					    SYMLIST_INSERT_HEAD);
361 				break;
362 			case ALIAS:
363 				symlist_add(&aliases, cursym,
364 					    SYMLIST_INSERT_HEAD);
365 				break;
366 			case LABEL:
367 				if (cursym->info.linfo->exported == 0)
368 					break;
369 				symlist_add(&exported_labels, cursym,
370 					    SYMLIST_INSERT_HEAD);
371 				break;
372 			default:
373 				break;
374 			}
375 			flag = R_NEXT;
376 		}
377 
378 		/* Put in the masks and bits */
379 		while (SLIST_FIRST(&masks) != SLIST_END(&masks)) {
380 			symbol_node_t *curnode;
381 			symbol_node_t *regnode;
382 			char *regname;
383 
384 			curnode = SLIST_FIRST(&masks);
385 			SLIST_REMOVE_HEAD(&masks, links);
386 
387 			regnode =
388 			    SLIST_FIRST(&curnode->symbol->info.minfo->symrefs);
389 			regname = regnode->symbol->name;
390 			regnode = symlist_search(&registers, regname);
391 			SLIST_INSERT_AFTER(regnode, curnode, links);
392 		}
393 
394 		/* Add the aliases */
395 		while (SLIST_FIRST(&aliases) != SLIST_END(&aliases)) {
396 			symbol_node_t *curnode;
397 			symbol_node_t *regnode;
398 			char *regname;
399 
400 			curnode = SLIST_FIRST(&aliases);
401 			SLIST_REMOVE_HEAD(&aliases, links);
402 
403 			regname = curnode->symbol->info.ainfo->parent->name;
404 			regnode = symlist_search(&registers, regname);
405 			SLIST_INSERT_AFTER(regnode, curnode, links);
406 		}
407 
408 		/* Output what we have */
409 		fprintf(ofile,
410 "/*\n"
411 " * DO NOT EDIT - This file is automatically generated\n"
412 " *		 from the following source files:\n"
413 " *\n"
414 "%s */\n", versions);
415                 while (SLIST_FIRST(&registers) != SLIST_END(&registers)) {
416 			symbol_node_t *curnode;
417 			u_int value;
418 			char *tab_str;
419 			char *tab_str2;
420 
421 			curnode = SLIST_FIRST(&registers);
422 			SLIST_REMOVE_HEAD(&registers, links);
423 			switch(curnode->symbol->type) {
424 			case REGISTER:
425 			case SCBLOC:
426 			case SRAMLOC:
427 				fprintf(ofile, "\n");
428 				value = curnode->symbol->info.rinfo->address;
429 				tab_str = "\t";
430 				tab_str2 = "\t\t";
431 				break;
432 			case ALIAS:
433 			{
434 				symbol_t *parent;
435 
436 				parent = curnode->symbol->info.ainfo->parent;
437 				value = parent->info.rinfo->address;
438 				tab_str = "\t";
439 				tab_str2 = "\t\t";
440 				break;
441 			}
442 			case MASK:
443 			case BIT:
444 				value = curnode->symbol->info.minfo->mask;
445 				tab_str = "\t\t";
446 				tab_str2 = "\t";
447 				break;
448 			default:
449 				value = 0; /* Quiet compiler */
450 				tab_str = NULL;
451 				tab_str2 = NULL;
452 				stop("symtable_dump: Invalid symbol type "
453 				     "encountered", EX_SOFTWARE);
454 				break;
455 			}
456 			fprintf(ofile, "#define%s%-16s%s0x%02x\n",
457 				tab_str, curnode->symbol->name, tab_str2,
458 				value);
459 			free(curnode);
460 		}
461 		fprintf(ofile, "\n\n");
462 
463 		while (SLIST_FIRST(&constants) != SLIST_END(&constants)) {
464 			symbol_node_t *curnode;
465 
466 			curnode = SLIST_FIRST(&constants);
467 			SLIST_REMOVE_HEAD(&constants, links);
468 			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
469 				curnode->symbol->name,
470 				curnode->symbol->info.cinfo->value);
471 			free(curnode);
472 		}
473 
474 
475 		fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
476 
477 		while (SLIST_FIRST(&download_constants) !=
478 		    SLIST_END(&download_constants)) {
479 			symbol_node_t *curnode;
480 
481 			curnode = SLIST_FIRST(&download_constants);
482 			SLIST_REMOVE_HEAD(&download_constants, links);
483 			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
484 				curnode->symbol->name,
485 				curnode->symbol->info.cinfo->value);
486 			free(curnode);
487 		}
488 		fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i);
489 
490 		fprintf(ofile, "\n\n/* Exported Labels */\n");
491 
492 		while (SLIST_FIRST(&exported_labels) !=
493 		    SLIST_END(&exported_labels)) {
494 			symbol_node_t *curnode;
495 
496 			curnode = SLIST_FIRST(&exported_labels);
497 			SLIST_REMOVE_HEAD(&exported_labels, links);
498 			fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n",
499 				curnode->symbol->name,
500 				curnode->symbol->info.linfo->address);
501 			free(curnode);
502 		}
503 	}
504 }
505 
506