Path: blob/main/sys/dev/aic7xxx/aicasm/aicasm_symbol.c
39566 views
/*-1* Aic7xxx SCSI host adapter firmware asssembler symbol table implementation2*3* SPDX-License-Identifier: BSD-3-Clause4*5* Copyright (c) 1997 Justin T. Gibbs.6* Copyright (c) 2002 Adaptec Inc.7* All rights reserved.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions, and the following disclaimer,14* without modification.15* 2. Redistributions in binary form must reproduce at minimum a disclaimer16* substantially similar to the "NO WARRANTY" disclaimer below17* ("Disclaimer") and any redistribution must be conditioned upon18* including a substantially similar Disclaimer requirement for further19* binary redistribution.20* 3. Neither the names of the above-listed copyright holders nor the names21* of any contributors may be used to endorse or promote products derived22* from this software without specific prior written permission.23*24* Alternatively, this software may be distributed under the terms of the25* GNU General Public License ("GPL") version 2 as published by the Free26* Software Foundation.27*28* NO WARRANTY29* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS30* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT31* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR32* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT33* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL34* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS35* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)36* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,37* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING38* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE39* POSSIBILITY OF SUCH DAMAGES.40*41* $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#24 $42*/4344#include <sys/types.h>45#include <sys/param.h>46#if defined(BSD) && !defined(__GNU__)47#include <db.h>48#else49#include <db_185.h>50#endif51#include <ctype.h>52#include <fcntl.h>53#include <inttypes.h>54#include <regex.h>55#include <stdio.h>56#include <stdlib.h>57#include <string.h>58#include <sysexits.h>5960#include "aicasm_symbol.h"61#include "aicasm.h"6263static DB *symtable;6465static symbol_t *66symbol_create(const char *name)67{68symbol_t *new_symbol;6970new_symbol = (symbol_t *)malloc(sizeof(symbol_t));71if (new_symbol == NULL) {72perror("Unable to create new symbol");73exit(EX_SOFTWARE);74}75memset(new_symbol, 0, sizeof(*new_symbol));76new_symbol->name = strdup(name);77if (new_symbol->name == NULL)78stop("Unable to strdup symbol name", EX_SOFTWARE);79new_symbol->type = UNINITIALIZED;80return (new_symbol);81}8283void84symbol_delete(symbol_t *symbol)85{86if (symtable != NULL) {87DBT key;8889key.data = symbol->name;90key.size = strlen(symbol->name);91symtable->del(symtable, &key, /*flags*/0);92}93switch(symbol->type) {94case SCBLOC:95case SRAMLOC:96case REGISTER:97if (symbol->info.rinfo != NULL)98free(symbol->info.rinfo);99break;100case ALIAS:101if (symbol->info.ainfo != NULL)102free(symbol->info.ainfo);103break;104case MASK:105case FIELD:106case ENUM:107case ENUM_ENTRY:108if (symbol->info.finfo != NULL) {109symlist_free(&symbol->info.finfo->symrefs);110free(symbol->info.finfo);111}112break;113case DOWNLOAD_CONST:114case CONST:115if (symbol->info.cinfo != NULL)116free(symbol->info.cinfo);117break;118case LABEL:119if (symbol->info.linfo != NULL)120free(symbol->info.linfo);121break;122case UNINITIALIZED:123default:124break;125}126free(symbol->name);127free(symbol);128}129130void131symtable_open(void)132{133symtable = dbopen(/*filename*/NULL,134O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,135/*openinfo*/NULL);136137if (symtable == NULL) {138perror("Symbol table creation failed");139exit(EX_SOFTWARE);140/* NOTREACHED */141}142}143144void145symtable_close(void)146{147if (symtable != NULL) {148DBT key;149DBT data;150151while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {152symbol_t *stored_ptr;153154memcpy(&stored_ptr, data.data, sizeof(stored_ptr));155symbol_delete(stored_ptr);156}157symtable->close(symtable);158}159}160161/*162* The semantics of get is to return an uninitialized symbol entry163* if a lookup fails.164*/165symbol_t *166symtable_get(const char *name)167{168symbol_t *stored_ptr;169DBT key;170DBT data;171int retval;172173key.data = strdup(name);174key.size = strlen(name);175176if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {177if (retval == -1) {178perror("Symbol table get operation failed");179exit(EX_SOFTWARE);180/* NOTREACHED */181} else if (retval == 1) {182/* Symbol wasn't found, so create a new one */183symbol_t *new_symbol;184185new_symbol = symbol_create(name);186data.data = &new_symbol;187data.size = sizeof(new_symbol);188if (symtable->put(symtable, &key, &data,189/*flags*/0) !=0) {190perror("Symtable put failed");191exit(EX_SOFTWARE);192}193free(key.data);194return (new_symbol);195} else {196perror("Unexpected return value from db get routine");197exit(EX_SOFTWARE);198/* NOTREACHED */199}200}201memcpy(&stored_ptr, data.data, sizeof(stored_ptr));202free(key.data);203return (stored_ptr);204}205206symbol_node_t *207symlist_search(symlist_t *symlist, char *symname)208{209symbol_node_t *curnode;210211curnode = SLIST_FIRST(symlist);212while(curnode != NULL) {213if (strcmp(symname, curnode->symbol->name) == 0)214break;215curnode = SLIST_NEXT(curnode, links);216}217return (curnode);218}219220void221symlist_add(symlist_t *symlist, symbol_t *symbol, int how)222{223symbol_node_t *newnode;224225newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));226if (newnode == NULL) {227stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);228/* NOTREACHED */229}230newnode->symbol = symbol;231if (how == SYMLIST_SORT) {232symbol_node_t *curnode;233int field;234235field = FALSE;236switch(symbol->type) {237case REGISTER:238case SCBLOC:239case SRAMLOC:240break;241case FIELD:242case MASK:243case ENUM:244case ENUM_ENTRY:245field = TRUE;246break;247default:248stop("symlist_add: Invalid symbol type for sorting",249EX_SOFTWARE);250/* NOTREACHED */251}252253curnode = SLIST_FIRST(symlist);254if (curnode == NULL255|| (field256&& (curnode->symbol->type > newnode->symbol->type257|| (curnode->symbol->type == newnode->symbol->type258&& (curnode->symbol->info.finfo->value >259newnode->symbol->info.finfo->value))))260|| (!field && (curnode->symbol->info.rinfo->address >261newnode->symbol->info.rinfo->address))) {262SLIST_INSERT_HEAD(symlist, newnode, links);263return;264}265266while (1) {267if (SLIST_NEXT(curnode, links) == NULL) {268SLIST_INSERT_AFTER(curnode, newnode,269links);270break;271} else {272symbol_t *cursymbol;273274cursymbol = SLIST_NEXT(curnode, links)->symbol;275if ((field276&& (cursymbol->type > symbol->type277|| (cursymbol->type == symbol->type278&& (cursymbol->info.finfo->value >279symbol->info.finfo->value))))280|| (!field281&& (cursymbol->info.rinfo->address >282symbol->info.rinfo->address))) {283SLIST_INSERT_AFTER(curnode, newnode,284links);285break;286}287}288curnode = SLIST_NEXT(curnode, links);289}290} else {291SLIST_INSERT_HEAD(symlist, newnode, links);292}293}294295void296symlist_free(symlist_t *symlist)297{298symbol_node_t *node1, *node2;299300node1 = SLIST_FIRST(symlist);301while (node1 != NULL) {302node2 = SLIST_NEXT(node1, links);303free(node1);304node1 = node2;305}306SLIST_INIT(symlist);307}308309void310symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,311symlist_t *symlist_src2)312{313symbol_node_t *node;314315*symlist_dest = *symlist_src1;316while((node = SLIST_FIRST(symlist_src2)) != NULL) {317SLIST_REMOVE_HEAD(symlist_src2, links);318SLIST_INSERT_HEAD(symlist_dest, node, links);319}320321/* These are now empty */322SLIST_INIT(symlist_src1);323SLIST_INIT(symlist_src2);324}325326static void327aic_print_file_prologue(FILE *ofile)328{329330if (ofile == NULL)331return;332333fprintf(ofile,334"/*\n"335" * DO NOT EDIT - This file is automatically generated\n"336" * from the following source files:\n"337" *\n"338"%s */\n",339versions);340}341342static void343aic_print_include(FILE *dfile, char *header_file)344{345if (dfile == NULL)346return;347348if (header_file[0] == '<')349fprintf(dfile, "\n#include %s\n\n", header_file);350else351fprintf(dfile, "\n#include \"%s\"\n\n", header_file);352}353354static void355aic_print_reg_dump_types(FILE *ofile)356{357if (ofile == NULL)358return;359360fprintf(ofile,361"typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n"362"typedef struct %sreg_parse_entry {\n"363" char *name;\n"364" uint8_t value;\n"365" uint8_t mask;\n"366"} %sreg_parse_entry_t;\n"367"\n",368prefix, prefix, prefix);369}370371static void372aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode)373{374if (dfile == NULL)375return;376377fprintf(dfile,378"static %sreg_parse_entry_t %s_parse_table[] = {\n",379prefix,380regnode->symbol->name);381}382383static void384aic_print_reg_dump_end(FILE *ofile, FILE *dfile,385symbol_node_t *regnode, u_int num_entries)386{387char *lower_name;388char *letter;389390lower_name = strdup(regnode->symbol->name);391if (lower_name == NULL)392stop("Unable to strdup symbol name", EX_SOFTWARE);393394for (letter = lower_name; *letter != '\0'; letter++)395*letter = tolower(*letter);396397if (dfile != NULL) {398if (num_entries != 0)399fprintf(dfile,400"\n"401"};\n"402"\n");403404fprintf(dfile,405"int\n"406"%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n"407"{\n"408" return (%sprint_register(%s%s, %d, \"%s\",\n"409" 0x%02x, regvalue, cur_col, wrap));\n"410"}\n"411"\n",412prefix,413lower_name,414prefix,415num_entries != 0 ? regnode->symbol->name : "NULL",416num_entries != 0 ? "_parse_table" : "",417num_entries,418regnode->symbol->name,419regnode->symbol->info.rinfo->address);420}421422fprintf(ofile,423"#if AIC_DEBUG_REGISTERS\n"424"%sreg_print_t %s%s_print;\n"425"#else\n"426"#define %s%s_print(regvalue, cur_col, wrap) \\\n"427" %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n"428"#endif\n"429"\n",430prefix,431prefix,432lower_name,433prefix,434lower_name,435prefix,436regnode->symbol->name,437regnode->symbol->info.rinfo->address);438}439440static void441aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode)442{443int num_tabs;444445if (dfile == NULL)446return;447448fprintf(dfile,449" { \"%s\",",450curnode->symbol->name);451452num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8;453454while (num_tabs-- > 0)455fputc('\t', dfile);456fprintf(dfile, "0x%02x, 0x%02x }",457curnode->symbol->info.finfo->value,458curnode->symbol->info.finfo->mask);459}460461void462symtable_dump(FILE *ofile, FILE *dfile)463{464/*465* Sort the registers by address with a simple insertion sort.466* Put bitmasks next to the first register that defines them.467* Put constants at the end.468*/469symlist_t registers;470symlist_t masks;471symlist_t constants;472symlist_t download_constants;473symlist_t aliases;474symlist_t exported_labels;475symbol_node_t *curnode;476symbol_node_t *regnode;477DBT key;478DBT data;479int flag;480u_int i;481482if (symtable == NULL)483return;484485SLIST_INIT(®isters);486SLIST_INIT(&masks);487SLIST_INIT(&constants);488SLIST_INIT(&download_constants);489SLIST_INIT(&aliases);490SLIST_INIT(&exported_labels);491flag = R_FIRST;492while (symtable->seq(symtable, &key, &data, flag) == 0) {493symbol_t *cursym;494495memcpy(&cursym, data.data, sizeof(cursym));496switch(cursym->type) {497case REGISTER:498case SCBLOC:499case SRAMLOC:500symlist_add(®isters, cursym, SYMLIST_SORT);501break;502case MASK:503case FIELD:504case ENUM:505case ENUM_ENTRY:506symlist_add(&masks, cursym, SYMLIST_SORT);507break;508case CONST:509symlist_add(&constants, cursym,510SYMLIST_INSERT_HEAD);511break;512case DOWNLOAD_CONST:513symlist_add(&download_constants, cursym,514SYMLIST_INSERT_HEAD);515break;516case ALIAS:517symlist_add(&aliases, cursym,518SYMLIST_INSERT_HEAD);519break;520case LABEL:521if (cursym->info.linfo->exported == 0)522break;523symlist_add(&exported_labels, cursym,524SYMLIST_INSERT_HEAD);525break;526default:527break;528}529flag = R_NEXT;530}531532/* Register dianostic functions/declarations first. */533aic_print_file_prologue(ofile);534aic_print_reg_dump_types(ofile);535aic_print_file_prologue(dfile);536aic_print_include(dfile, stock_include_file);537SLIST_FOREACH(curnode, ®isters, links) {538switch(curnode->symbol->type) {539case REGISTER:540case SCBLOC:541case SRAMLOC:542{543symlist_t *fields;544symbol_node_t *fieldnode;545int num_entries;546547num_entries = 0;548fields = &curnode->symbol->info.rinfo->fields;549SLIST_FOREACH(fieldnode, fields, links) {550if (num_entries == 0)551aic_print_reg_dump_start(dfile,552curnode);553else if (dfile != NULL)554fputs(",\n", dfile);555num_entries++;556aic_print_reg_dump_entry(dfile, fieldnode);557}558aic_print_reg_dump_end(ofile, dfile,559curnode, num_entries);560}561default:562break;563}564}565566/* Fold in the masks and bits */567while (SLIST_FIRST(&masks) != NULL) {568char *regname;569570curnode = SLIST_FIRST(&masks);571SLIST_REMOVE_HEAD(&masks, links);572573regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs);574regname = regnode->symbol->name;575regnode = symlist_search(®isters, regname);576SLIST_INSERT_AFTER(regnode, curnode, links);577}578579/* Add the aliases */580while (SLIST_FIRST(&aliases) != NULL) {581char *regname;582583curnode = SLIST_FIRST(&aliases);584SLIST_REMOVE_HEAD(&aliases, links);585586regname = curnode->symbol->info.ainfo->parent->name;587regnode = symlist_search(®isters, regname);588SLIST_INSERT_AFTER(regnode, curnode, links);589}590591/* Output generated #defines. */592while (SLIST_FIRST(®isters) != NULL) {593u_int value;594const char *tab_str;595const char *tab_str2;596597curnode = SLIST_FIRST(®isters);598SLIST_REMOVE_HEAD(®isters, links);599switch(curnode->symbol->type) {600case REGISTER:601case SCBLOC:602case SRAMLOC:603fprintf(ofile, "\n");604value = curnode->symbol->info.rinfo->address;605tab_str = "\t";606tab_str2 = "\t\t";607break;608case ALIAS:609{610symbol_t *parent;611612parent = curnode->symbol->info.ainfo->parent;613value = parent->info.rinfo->address;614tab_str = "\t";615tab_str2 = "\t\t";616break;617}618case MASK:619case FIELD:620case ENUM:621case ENUM_ENTRY:622value = curnode->symbol->info.finfo->value;623tab_str = "\t\t";624tab_str2 = "\t";625break;626default:627value = 0; /* Quiet compiler */628tab_str = NULL;629tab_str2 = NULL;630stop("symtable_dump: Invalid symbol type "631"encountered", EX_SOFTWARE);632break;633}634fprintf(ofile, "#define%s%-16s%s0x%02x\n",635tab_str, curnode->symbol->name, tab_str2,636value);637free(curnode);638}639fprintf(ofile, "\n\n");640641while (SLIST_FIRST(&constants) != NULL) {642curnode = SLIST_FIRST(&constants);643SLIST_REMOVE_HEAD(&constants, links);644fprintf(ofile, "#define\t%-8s\t0x%02x\n",645curnode->symbol->name,646curnode->symbol->info.cinfo->value);647free(curnode);648}649650fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");651652for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {653curnode = SLIST_FIRST(&download_constants);654SLIST_REMOVE_HEAD(&download_constants, links);655fprintf(ofile, "#define\t%-8s\t0x%02x\n",656curnode->symbol->name,657curnode->symbol->info.cinfo->value);658free(curnode);659}660fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i);661662fprintf(ofile, "\n\n/* Exported Labels */\n");663664while (SLIST_FIRST(&exported_labels) != NULL) {665curnode = SLIST_FIRST(&exported_labels);666SLIST_REMOVE_HEAD(&exported_labels, links);667fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n",668curnode->symbol->name,669curnode->symbol->info.linfo->address);670free(curnode);671}672}673674675