1 /* $OpenBSD: aicasm_symbol.c,v 1.13 2014/07/12 19:01:49 tedu Exp $ */ 2 /* $NetBSD: aicasm_symbol.c,v 1.4 2003/07/14 15:42:40 lukem Exp $ */ 3 4 /* 5 * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation 6 * 7 * Copyright (c) 1997 Justin T. Gibbs. 8 * Copyright (c) 2002 Adaptec Inc. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 * 43 * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.23 2003/01/20 18:01:37 gibbs Exp $ 44 */ 45 46 #include <sys/types.h> 47 48 #ifdef __linux__ 49 #include "aicdb.h" 50 #else 51 #include <db.h> 52 #endif 53 #include <fcntl.h> 54 #include <inttypes.h> 55 #include <regex.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <sysexits.h> 60 61 #include "aicasm_symbol.h" 62 #include "aicasm.h" 63 64 static DB *symtable; 65 66 symbol_t * 67 symbol_create(char *name) 68 { 69 symbol_t *new_symbol; 70 71 new_symbol = (symbol_t *)malloc(sizeof(symbol_t)); 72 if (new_symbol == NULL) { 73 perror("Unable to create new symbol"); 74 exit(EX_SOFTWARE); 75 } 76 memset(new_symbol, 0, sizeof(*new_symbol)); 77 new_symbol->name = strdup(name); 78 if (new_symbol->name == NULL) 79 stop("Unable to strdup symbol name", EX_SOFTWARE); 80 new_symbol->type = UNINITIALIZED; 81 return (new_symbol); 82 } 83 84 void 85 symbol_delete(symbol_t *symbol) 86 { 87 if (symtable != NULL) { 88 DBT key; 89 90 key.data = symbol->name; 91 key.size = strlen(symbol->name); 92 symtable->del(symtable, &key, /*flags*/0); 93 } 94 switch(symbol->type) { 95 case SCBLOC: 96 case SRAMLOC: 97 case REGISTER: 98 if (symbol->info.rinfo != NULL) 99 free(symbol->info.rinfo); 100 break; 101 case ALIAS: 102 if (symbol->info.ainfo != NULL) 103 free(symbol->info.ainfo); 104 break; 105 case MASK: 106 case FIELD: 107 case ENUM: 108 case ENUM_ENTRY: 109 if (symbol->info.finfo != NULL) { 110 symlist_free(&symbol->info.finfo->symrefs); 111 free(symbol->info.finfo); 112 } 113 break; 114 case DOWNLOAD_CONST: 115 case CONST: 116 if (symbol->info.cinfo != NULL) 117 free(symbol->info.cinfo); 118 break; 119 case LABEL: 120 if (symbol->info.linfo != NULL) 121 free(symbol->info.linfo); 122 break; 123 case UNINITIALIZED: 124 default: 125 break; 126 } 127 free(symbol->name); 128 free(symbol); 129 } 130 131 void 132 symtable_open() 133 { 134 symtable = dbopen(/*filename*/NULL, 135 O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH, 136 /*openinfo*/NULL); 137 138 if (symtable == NULL) { 139 perror("Symbol table creation failed"); 140 exit(EX_SOFTWARE); 141 /* NOTREACHED */ 142 } 143 } 144 145 void 146 symtable_close() 147 { 148 if (symtable != NULL) { 149 DBT key; 150 DBT data; 151 152 while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { 153 symbol_t *stored_ptr; 154 155 memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); 156 symbol_delete(stored_ptr); 157 } 158 symtable->close(symtable); 159 } 160 } 161 162 /* 163 * The semantics of get is to return an uninitialized symbol entry 164 * if a lookup fails. 165 */ 166 symbol_t * 167 symtable_get(char *name) 168 { 169 symbol_t *stored_ptr; 170 DBT key; 171 DBT data; 172 int retval; 173 174 key.data = (void *)name; 175 key.size = strlen(name); 176 177 if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) { 178 if (retval == -1) { 179 perror("Symbol table get operation failed"); 180 exit(EX_SOFTWARE); 181 /* NOTREACHED */ 182 } else if (retval == 1) { 183 /* Symbol wasn't found, so create a new one */ 184 symbol_t *new_symbol; 185 186 new_symbol = symbol_create(name); 187 data.data = &new_symbol; 188 data.size = sizeof(new_symbol); 189 if (symtable->put(symtable, &key, &data, 190 /*flags*/0) !=0) { 191 perror("Symtable put failed"); 192 exit(EX_SOFTWARE); 193 } 194 return (new_symbol); 195 } else { 196 perror("Unexpected return value from db get routine"); 197 exit(EX_SOFTWARE); 198 /* NOTREACHED */ 199 } 200 } 201 memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); 202 return (stored_ptr); 203 } 204 205 symbol_node_t * 206 symlist_search(symlist_t *symlist, char *symname) 207 { 208 symbol_node_t *curnode; 209 210 curnode = SLIST_FIRST(symlist); 211 while(curnode != NULL) { 212 if (strcmp(symname, curnode->symbol->name) == 0) 213 break; 214 curnode = SLIST_NEXT(curnode, links); 215 } 216 return (curnode); 217 } 218 219 void 220 symlist_add(symlist_t *symlist, symbol_t *symbol, int how) 221 { 222 symbol_node_t *newnode; 223 224 newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t)); 225 if (newnode == NULL) { 226 stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE); 227 /* NOTREACHED */ 228 } 229 newnode->symbol = symbol; 230 if (how == SYMLIST_SORT) { 231 symbol_node_t *curnode; 232 int field; 233 234 field = FALSE; 235 switch(symbol->type) { 236 case REGISTER: 237 case SCBLOC: 238 case SRAMLOC: 239 break; 240 case FIELD: 241 case MASK: 242 case ENUM: 243 case ENUM_ENTRY: 244 field = TRUE; 245 break; 246 default: 247 stop("symlist_add: Invalid symbol type for sorting", 248 EX_SOFTWARE); 249 /* NOTREACHED */ 250 } 251 252 curnode = SLIST_FIRST(symlist); 253 if (curnode == NULL 254 || (field 255 && (curnode->symbol->type > newnode->symbol->type 256 || (curnode->symbol->type == newnode->symbol->type 257 && (curnode->symbol->info.finfo->value > 258 newnode->symbol->info.finfo->value)))) 259 || (!field && (curnode->symbol->info.rinfo->address > 260 newnode->symbol->info.rinfo->address))) { 261 SLIST_INSERT_HEAD(symlist, newnode, links); 262 return; 263 } 264 265 while (1) { 266 if (SLIST_NEXT(curnode, links) == NULL) { 267 SLIST_INSERT_AFTER(curnode, newnode, 268 links); 269 break; 270 } else { 271 symbol_t *cursymbol; 272 273 cursymbol = SLIST_NEXT(curnode, links)->symbol; 274 if ((field 275 && (cursymbol->type > symbol->type 276 || (cursymbol->type == symbol->type 277 && (cursymbol->info.finfo->value > 278 symbol->info.finfo->value)))) 279 || (!field 280 && (cursymbol->info.rinfo->address > 281 symbol->info.rinfo->address))) { 282 SLIST_INSERT_AFTER(curnode, newnode, 283 links); 284 break; 285 } 286 } 287 curnode = SLIST_NEXT(curnode, links); 288 } 289 } else { 290 SLIST_INSERT_HEAD(symlist, newnode, links); 291 } 292 } 293 294 void 295 symlist_free(symlist_t *symlist) 296 { 297 symbol_node_t *node1, *node2; 298 299 node1 = SLIST_FIRST(symlist); 300 while (node1 != NULL) { 301 node2 = SLIST_NEXT(node1, links); 302 free(node1); 303 node1 = node2; 304 } 305 SLIST_INIT(symlist); 306 } 307 308 void 309 symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, 310 symlist_t *symlist_src2) 311 { 312 symbol_node_t *node; 313 314 *symlist_dest = *symlist_src1; 315 while((node = SLIST_FIRST(symlist_src2)) != NULL) { 316 SLIST_REMOVE_HEAD(symlist_src2, links); 317 SLIST_INSERT_HEAD(symlist_dest, node, links); 318 } 319 320 /* These are now empty */ 321 SLIST_INIT(symlist_src1); 322 SLIST_INIT(symlist_src2); 323 } 324 325 void 326 aic_print_file_prologue(FILE *ofile) 327 { 328 329 if (ofile == NULL) 330 return; 331 332 fprintf(ofile, 333 "/*\n" 334 " * DO NOT EDIT - This file is automatically generated\n" 335 " * from the following source files:\n" 336 " *\n" 337 "%s */\n", 338 versions); 339 } 340 341 void 342 aic_print_include(FILE *dfile, char *include_file) 343 { 344 345 if (dfile == NULL) 346 return; 347 fprintf(dfile, "\n#include \"%s\"\n\n", include_file); 348 } 349 350 void 351 aic_print_reg_dump_types(FILE *ofile) 352 { 353 if (ofile == NULL) 354 return; 355 356 fprintf(ofile, 357 "typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n" 358 "typedef struct %sreg_parse_entry {\n" 359 " char *name;\n" 360 " uint8_t value;\n" 361 " uint8_t mask;\n" 362 "} %sreg_parse_entry_t;\n" 363 "\n", 364 prefix, prefix, prefix); 365 } 366 367 static void 368 aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode) 369 { 370 if (dfile == NULL) 371 return; 372 373 fprintf(dfile, 374 "static %sreg_parse_entry_t %s_parse_table[] = {\n", 375 prefix, 376 regnode->symbol->name); 377 } 378 379 static void 380 aic_print_reg_dump_end(FILE *ofile, FILE *dfile, 381 symbol_node_t *regnode, u_int num_entries) 382 { 383 char *lower_name; 384 char *letter; 385 386 lower_name = strdup(regnode->symbol->name); 387 if (lower_name == NULL) 388 stop("Unable to strdup symbol name", EX_SOFTWARE); 389 390 for (letter = lower_name; *letter != '\0'; letter++) 391 *letter = tolower(*letter); 392 393 if (dfile != NULL) { 394 if (num_entries != 0) 395 fprintf(dfile, 396 "\n" 397 "};\n" 398 "\n"); 399 400 fprintf(dfile, 401 "int\n" 402 "%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n" 403 "{\n" 404 " return (%sprint_register(%s%s, %d, \"%s\",\n" 405 " 0x%02x, regvalue, cur_col, wrap));\n" 406 "}\n" 407 "\n", 408 prefix, 409 lower_name, 410 prefix, 411 num_entries != 0 ? regnode->symbol->name : "NULL", 412 num_entries != 0 ? "_parse_table" : "", 413 num_entries, 414 regnode->symbol->name, 415 regnode->symbol->info.rinfo->address); 416 } 417 418 fprintf(ofile, 419 "#if AIC_DEBUG_REGISTERS\n" 420 "%sreg_print_t %s%s_print;\n" 421 "#else\n" 422 "#define %s%s_print(regvalue, cur_col, wrap) \\\n" 423 " %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n" 424 "#endif\n" 425 "\n", 426 prefix, 427 prefix, 428 lower_name, 429 prefix, 430 lower_name, 431 prefix, 432 regnode->symbol->name, 433 regnode->symbol->info.rinfo->address); 434 } 435 436 static void 437 aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode) 438 { 439 int num_tabs; 440 441 if (dfile == NULL) 442 return; 443 444 fprintf(dfile, 445 " { \"%s\",", 446 curnode->symbol->name); 447 448 num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8; 449 450 while (num_tabs-- > 0) 451 fputc('\t', dfile); 452 fprintf(dfile, "0x%02x, 0x%02x }", 453 curnode->symbol->info.finfo->value, 454 curnode->symbol->info.finfo->mask); 455 } 456 457 void 458 symtable_dump(FILE *ofile, FILE *dfile) 459 { 460 /* 461 * Sort the registers by address with a simple insertion sort. 462 * Put bitmasks next to the first register that defines them. 463 * Put constants at the end. 464 */ 465 symlist_t registers; 466 symlist_t masks; 467 symlist_t constants; 468 symlist_t download_constants; 469 symlist_t aliases; 470 symlist_t exported_labels; 471 symbol_node_t *curnode; 472 symbol_node_t *regnode; 473 DBT key; 474 DBT data; 475 int flag; 476 u_int i; 477 478 if (symtable == NULL) 479 return; 480 481 SLIST_INIT(®isters); 482 SLIST_INIT(&masks); 483 SLIST_INIT(&constants); 484 SLIST_INIT(&download_constants); 485 SLIST_INIT(&aliases); 486 SLIST_INIT(&exported_labels); 487 flag = R_FIRST; 488 while (symtable->seq(symtable, &key, &data, flag) == 0) { 489 symbol_t *cursym; 490 491 memcpy(&cursym, data.data, sizeof(cursym)); 492 switch(cursym->type) { 493 case REGISTER: 494 case SCBLOC: 495 case SRAMLOC: 496 symlist_add(®isters, cursym, SYMLIST_SORT); 497 break; 498 case MASK: 499 case FIELD: 500 case ENUM: 501 case ENUM_ENTRY: 502 symlist_add(&masks, cursym, SYMLIST_SORT); 503 break; 504 case CONST: 505 symlist_add(&constants, cursym, 506 SYMLIST_INSERT_HEAD); 507 break; 508 case DOWNLOAD_CONST: 509 symlist_add(&download_constants, cursym, 510 SYMLIST_INSERT_HEAD); 511 break; 512 case ALIAS: 513 symlist_add(&aliases, cursym, 514 SYMLIST_INSERT_HEAD); 515 break; 516 case LABEL: 517 if (cursym->info.linfo->exported == 0) 518 break; 519 symlist_add(&exported_labels, cursym, 520 SYMLIST_INSERT_HEAD); 521 break; 522 default: 523 break; 524 } 525 flag = R_NEXT; 526 } 527 528 /* Register dianostic functions/declarations first. */ 529 aic_print_file_prologue(ofile); 530 aic_print_reg_dump_types(ofile); 531 aic_print_file_prologue(dfile); 532 aic_print_include(dfile, stock_include_file); 533 SLIST_FOREACH(curnode, ®isters, links) { 534 535 switch(curnode->symbol->type) { 536 case REGISTER: 537 case SCBLOC: 538 case SRAMLOC: 539 { 540 symlist_t *fields; 541 symbol_node_t *fieldnode; 542 int num_entries; 543 544 num_entries = 0; 545 fields = &curnode->symbol->info.rinfo->fields; 546 SLIST_FOREACH(fieldnode, fields, links) { 547 if (num_entries == 0) 548 aic_print_reg_dump_start(dfile, 549 curnode); 550 else if (dfile != NULL) 551 fputs(",\n", dfile); 552 num_entries++; 553 aic_print_reg_dump_entry(dfile, fieldnode); 554 } 555 aic_print_reg_dump_end(ofile, dfile, 556 curnode, num_entries); 557 } 558 default: 559 break; 560 } 561 } 562 563 /* Fold in the masks and bits */ 564 while (SLIST_FIRST(&masks) != NULL) { 565 char *regname; 566 567 curnode = SLIST_FIRST(&masks); 568 SLIST_REMOVE_HEAD(&masks, links); 569 570 regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs); 571 regname = regnode->symbol->name; 572 regnode = symlist_search(®isters, regname); 573 SLIST_INSERT_AFTER(regnode, curnode, links); 574 } 575 576 /* Add the aliases */ 577 while (SLIST_FIRST(&aliases) != NULL) { 578 char *regname; 579 580 curnode = SLIST_FIRST(&aliases); 581 SLIST_REMOVE_HEAD(&aliases, links); 582 583 regname = curnode->symbol->info.ainfo->parent->name; 584 regnode = symlist_search(®isters, regname); 585 SLIST_INSERT_AFTER(regnode, curnode, links); 586 } 587 588 /* Output generated #defines. */ 589 while (SLIST_FIRST(®isters) != NULL) { 590 symbol_node_t *curnode; 591 u_int value; 592 char *tab_str; 593 char *tab_str2; 594 595 curnode = SLIST_FIRST(®isters); 596 SLIST_REMOVE_HEAD(®isters, links); 597 switch(curnode->symbol->type) { 598 case REGISTER: 599 case SCBLOC: 600 case SRAMLOC: 601 fprintf(ofile, "\n"); 602 value = curnode->symbol->info.rinfo->address; 603 tab_str = "\t"; 604 tab_str2 = "\t\t"; 605 break; 606 case ALIAS: 607 { 608 symbol_t *parent; 609 610 parent = curnode->symbol->info.ainfo->parent; 611 value = parent->info.rinfo->address; 612 tab_str = "\t"; 613 tab_str2 = "\t\t"; 614 break; 615 } 616 case MASK: 617 case FIELD: 618 case ENUM: 619 case ENUM_ENTRY: 620 value = curnode->symbol->info.finfo->value; 621 tab_str = "\t\t"; 622 tab_str2 = "\t"; 623 break; 624 default: 625 value = 0; /* Quiet compiler */ 626 tab_str = NULL; 627 tab_str2 = NULL; 628 stop("symtable_dump: Invalid symbol type " 629 "encountered", EX_SOFTWARE); 630 break; 631 } 632 fprintf(ofile, "#define%s%-16s%s0x%02x\n", 633 tab_str, curnode->symbol->name, tab_str2, 634 value); 635 free(curnode); 636 } 637 fprintf(ofile, "\n\n"); 638 639 while (SLIST_FIRST(&constants) != NULL) { 640 symbol_node_t *curnode; 641 642 curnode = SLIST_FIRST(&constants); 643 SLIST_REMOVE_HEAD(&constants, links); 644 fprintf(ofile, "#define\t%-8s\t0x%02x\n", 645 curnode->symbol->name, 646 curnode->symbol->info.cinfo->value); 647 free(curnode); 648 } 649 650 651 fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); 652 653 for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) { 654 symbol_node_t *curnode; 655 656 curnode = SLIST_FIRST(&download_constants); 657 SLIST_REMOVE_HEAD(&download_constants, links); 658 fprintf(ofile, "#define\t%-8s\t0x%02x\n", 659 curnode->symbol->name, 660 curnode->symbol->info.cinfo->value); 661 free(curnode); 662 } 663 fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i); 664 665 fprintf(ofile, "\n\n/* Exported Labels */\n"); 666 667 while (SLIST_FIRST(&exported_labels) != NULL) { 668 symbol_node_t *curnode; 669 670 curnode = SLIST_FIRST(&exported_labels); 671 SLIST_REMOVE_HEAD(&exported_labels, links); 672 fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n", 673 curnode->symbol->name, 674 curnode->symbol->info.linfo->address); 675 free(curnode); 676 } 677 } 678 679