Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
aicasm_symbol.c
Go to the documentation of this file.
1 /*
2  * Aic7xxx SCSI host adapter firmware assembler symbol table implementation
3  *
4  * Copyright (c) 1997 Justin T. Gibbs.
5  * Copyright (c) 2002 Adaptec Inc.
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  * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#24 $
41  *
42  * $FreeBSD$
43  */
44 
45 #include <sys/types.h>
46 
47 #ifdef __linux__
48 #include "aicdb.h"
49 #else
50 #include <db.h>
51 #endif
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>
59 
60 #include "aicasm_symbol.h"
61 #include "aicasm.h"
62 
63 static DB *symtable;
64 
65 symbol_t *
67 {
68  symbol_t *new_symbol;
69 
70  new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
71  if (new_symbol == NULL) {
72  perror("Unable to create new symbol");
73  exit(EX_SOFTWARE);
74  }
75  memset(new_symbol, 0, sizeof(*new_symbol));
76  new_symbol->name = strdup(name);
77  if (new_symbol->name == NULL)
78  stop("Unable to strdup symbol name", EX_SOFTWARE);
79  new_symbol->type = UNINITIALIZED;
80  new_symbol->count = 1;
81  return (new_symbol);
82 }
83 
84 void
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
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
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 *
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  stored_ptr->count++;
203  data.data = &stored_ptr;
204  if (symtable->put(symtable, &key, &data, /*flags*/0) !=0) {
205  perror("Symtable put failed");
206  exit(EX_SOFTWARE);
207  }
208  return (stored_ptr);
209 }
210 
212 symlist_search(symlist_t *symlist, char *symname)
213 {
214  symbol_node_t *curnode;
215 
216  curnode = SLIST_FIRST(symlist);
217  while(curnode != NULL) {
218  if (strcmp(symname, curnode->symbol->name) == 0)
219  break;
220  curnode = SLIST_NEXT(curnode, links);
221  }
222  return (curnode);
223 }
224 
225 void
226 symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
227 {
228  symbol_node_t *newnode;
229 
230  newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
231  if (newnode == NULL) {
232  stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
233  /* NOTREACHED */
234  }
235  newnode->symbol = symbol;
236  if (how == SYMLIST_SORT) {
237  symbol_node_t *curnode;
238  int field;
239 
240  field = FALSE;
241  switch(symbol->type) {
242  case REGISTER:
243  case SCBLOC:
244  case SRAMLOC:
245  break;
246  case FIELD:
247  case MASK:
248  case ENUM:
249  case ENUM_ENTRY:
250  field = TRUE;
251  break;
252  default:
253  stop("symlist_add: Invalid symbol type for sorting",
254  EX_SOFTWARE);
255  /* NOTREACHED */
256  }
257 
258  curnode = SLIST_FIRST(symlist);
259  if (curnode == NULL
260  || (field
261  && (curnode->symbol->type > newnode->symbol->type
262  || (curnode->symbol->type == newnode->symbol->type
263  && (curnode->symbol->info.finfo->value >
264  newnode->symbol->info.finfo->value))))
265  || (!field && (curnode->symbol->info.rinfo->address >
266  newnode->symbol->info.rinfo->address))) {
267  SLIST_INSERT_HEAD(symlist, newnode, links);
268  return;
269  }
270 
271  while (1) {
272  if (SLIST_NEXT(curnode, links) == NULL) {
273  SLIST_INSERT_AFTER(curnode, newnode,
274  links);
275  break;
276  } else {
277  symbol_t *cursymbol;
278 
279  cursymbol = SLIST_NEXT(curnode, links)->symbol;
280  if ((field
281  && (cursymbol->type > symbol->type
282  || (cursymbol->type == symbol->type
283  && (cursymbol->info.finfo->value >
284  symbol->info.finfo->value))))
285  || (!field
286  && (cursymbol->info.rinfo->address >
287  symbol->info.rinfo->address))) {
288  SLIST_INSERT_AFTER(curnode, newnode,
289  links);
290  break;
291  }
292  }
293  curnode = SLIST_NEXT(curnode, links);
294  }
295  } else {
296  SLIST_INSERT_HEAD(symlist, newnode, links);
297  }
298 }
299 
300 void
301 symlist_free(symlist_t *symlist)
302 {
303  symbol_node_t *node1, *node2;
304 
305  node1 = SLIST_FIRST(symlist);
306  while (node1 != NULL) {
307  node2 = SLIST_NEXT(node1, links);
308  free(node1);
309  node1 = node2;
310  }
311  SLIST_INIT(symlist);
312 }
313 
314 void
315 symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,
316  symlist_t *symlist_src2)
317 {
319 
320  *symlist_dest = *symlist_src1;
321  while((node = SLIST_FIRST(symlist_src2)) != NULL) {
322  SLIST_REMOVE_HEAD(symlist_src2, links);
323  SLIST_INSERT_HEAD(symlist_dest, node, links);
324  }
325 
326  /* These are now empty */
327  SLIST_INIT(symlist_src1);
328  SLIST_INIT(symlist_src2);
329 }
330 
331 void
333 {
334 
335  if (ofile == NULL)
336  return;
337 
338  fprintf(ofile,
339 "/*\n"
340 " * DO NOT EDIT - This file is automatically generated\n"
341 " * from the following source files:\n"
342 " *\n"
343 "%s */\n",
344  versions);
345 }
346 
347 void
348 aic_print_include(FILE *dfile, char *include_file)
349 {
350 
351  if (dfile == NULL)
352  return;
353  fprintf(dfile, "\n#include \"%s\"\n\n", include_file);
354 }
355 
356 void
358 {
359  if (ofile == NULL)
360  return;
361 
362  fprintf(ofile,
363 "typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n"
364 "typedef struct %sreg_parse_entry {\n"
365 " char *name;\n"
366 " uint8_t value;\n"
367 " uint8_t mask;\n"
368 "} %sreg_parse_entry_t;\n"
369 "\n",
370  prefix, prefix, prefix);
371 }
372 
373 static void
374 aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode)
375 {
376  if (dfile == NULL)
377  return;
378 
379  fprintf(dfile,
380 "static const %sreg_parse_entry_t %s_parse_table[] = {\n",
381  prefix,
382  regnode->symbol->name);
383 }
384 
385 static void
386 aic_print_reg_dump_end(FILE *ofile, FILE *dfile,
387  symbol_node_t *regnode, u_int num_entries)
388 {
389  char *lower_name;
390  char *letter;
391 
392  lower_name = strdup(regnode->symbol->name);
393  if (lower_name == NULL)
394  stop("Unable to strdup symbol name", EX_SOFTWARE);
395 
396  for (letter = lower_name; *letter != '\0'; letter++)
397  *letter = tolower(*letter);
398 
399  if (dfile != NULL) {
400  if (num_entries != 0)
401  fprintf(dfile,
402 "\n"
403 "};\n"
404 "\n");
405 
406  fprintf(dfile,
407 "int\n"
408 "%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n"
409 "{\n"
410 " return (%sprint_register(%s%s, %d, \"%s\",\n"
411 " 0x%02x, regvalue, cur_col, wrap));\n"
412 "}\n"
413 "\n",
414  prefix,
415  lower_name,
416  prefix,
417  num_entries != 0 ? regnode->symbol->name : "NULL",
418  num_entries != 0 ? "_parse_table" : "",
419  num_entries,
420  regnode->symbol->name,
421  regnode->symbol->info.rinfo->address);
422  }
423 
424  fprintf(ofile,
425 "#if AIC_DEBUG_REGISTERS\n"
426 "%sreg_print_t %s%s_print;\n"
427 "#else\n"
428 "#define %s%s_print(regvalue, cur_col, wrap) \\\n"
429 " %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n"
430 "#endif\n"
431 "\n",
432  prefix,
433  prefix,
434  lower_name,
435  prefix,
436  lower_name,
437  prefix,
438  regnode->symbol->name,
439  regnode->symbol->info.rinfo->address);
440 }
441 
442 static void
443 aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode)
444 {
445  int num_tabs;
446 
447  if (dfile == NULL)
448  return;
449 
450  fprintf(dfile,
451 " { \"%s\",",
452  curnode->symbol->name);
453 
454  num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8;
455 
456  while (num_tabs-- > 0)
457  fputc('\t', dfile);
458  fprintf(dfile, "0x%02x, 0x%02x }",
459  curnode->symbol->info.finfo->value,
460  curnode->symbol->info.finfo->mask);
461 }
462 
463 void
464 symtable_dump(FILE *ofile, FILE *dfile)
465 {
466  /*
467  * Sort the registers by address with a simple insertion sort.
468  * Put bitmasks next to the first register that defines them.
469  * Put constants at the end.
470  */
471  symlist_t registers;
472  symlist_t masks;
473  symlist_t constants;
474  symlist_t download_constants;
475  symlist_t aliases;
476  symlist_t exported_labels;
477  symbol_node_t *curnode;
478  symbol_node_t *regnode;
479  DBT key;
480  DBT data;
481  int flag;
482  int reg_count = 0, reg_used = 0;
483  u_int i;
484 
485  if (symtable == NULL)
486  return;
487 
488  SLIST_INIT(&registers);
489  SLIST_INIT(&masks);
490  SLIST_INIT(&constants);
491  SLIST_INIT(&download_constants);
492  SLIST_INIT(&aliases);
493  SLIST_INIT(&exported_labels);
494  flag = R_FIRST;
495  while (symtable->seq(symtable, &key, &data, flag) == 0) {
496  symbol_t *cursym;
497 
498  memcpy(&cursym, data.data, sizeof(cursym));
499  switch(cursym->type) {
500  case REGISTER:
501  case SCBLOC:
502  case SRAMLOC:
503  symlist_add(&registers, cursym, SYMLIST_SORT);
504  break;
505  case MASK:
506  case FIELD:
507  case ENUM:
508  case ENUM_ENTRY:
509  symlist_add(&masks, cursym, SYMLIST_SORT);
510  break;
511  case CONST:
512  symlist_add(&constants, cursym,
514  break;
515  case DOWNLOAD_CONST:
516  symlist_add(&download_constants, cursym,
518  break;
519  case ALIAS:
520  symlist_add(&aliases, cursym,
522  break;
523  case LABEL:
524  if (cursym->info.linfo->exported == 0)
525  break;
526  symlist_add(&exported_labels, cursym,
528  break;
529  default:
530  break;
531  }
532  flag = R_NEXT;
533  }
534 
535  /* Register dianostic functions/declarations first. */
540  SLIST_FOREACH(curnode, &registers, links) {
541 
542  if (curnode->symbol->dont_generate_debug_code)
543  continue;
544 
545  switch(curnode->symbol->type) {
546  case REGISTER:
547  case SCBLOC:
548  case SRAMLOC:
549  {
550  symlist_t *fields;
551  symbol_node_t *fieldnode;
552  int num_entries;
553 
554  num_entries = 0;
555  reg_count++;
556  if (curnode->symbol->count == 1)
557  break;
558  fields = &curnode->symbol->info.rinfo->fields;
559  SLIST_FOREACH(fieldnode, fields, links) {
560  if (num_entries == 0)
561  aic_print_reg_dump_start(dfile,
562  curnode);
563  else if (dfile != NULL)
564  fputs(",\n", dfile);
565  num_entries++;
566  aic_print_reg_dump_entry(dfile, fieldnode);
567  }
568  aic_print_reg_dump_end(ofile, dfile,
569  curnode, num_entries);
570  reg_used++;
571  }
572  default:
573  break;
574  }
575  }
576  fprintf(stderr, "%s: %d of %d register definitions used\n", appname,
577  reg_used, reg_count);
578 
579  /* Fold in the masks and bits */
580  while (SLIST_FIRST(&masks) != NULL) {
581  char *regname;
582 
583  curnode = SLIST_FIRST(&masks);
584  SLIST_REMOVE_HEAD(&masks, links);
585 
586  regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs);
587  regname = regnode->symbol->name;
588  regnode = symlist_search(&registers, regname);
589  SLIST_INSERT_AFTER(regnode, curnode, links);
590  }
591 
592  /* Add the aliases */
593  while (SLIST_FIRST(&aliases) != NULL) {
594  char *regname;
595 
596  curnode = SLIST_FIRST(&aliases);
597  SLIST_REMOVE_HEAD(&aliases, links);
598 
599  regname = curnode->symbol->info.ainfo->parent->name;
600  regnode = symlist_search(&registers, regname);
601  SLIST_INSERT_AFTER(regnode, curnode, links);
602  }
603 
604  /* Output generated #defines. */
605  while (SLIST_FIRST(&registers) != NULL) {
606  symbol_node_t *curnode;
607  u_int value;
608  char *tab_str;
609  char *tab_str2;
610 
611  curnode = SLIST_FIRST(&registers);
612  SLIST_REMOVE_HEAD(&registers, links);
613  switch(curnode->symbol->type) {
614  case REGISTER:
615  case SCBLOC:
616  case SRAMLOC:
617  fprintf(ofile, "\n");
618  value = curnode->symbol->info.rinfo->address;
619  tab_str = "\t";
620  tab_str2 = "\t\t";
621  break;
622  case ALIAS:
623  {
624  symbol_t *parent;
625 
626  parent = curnode->symbol->info.ainfo->parent;
627  value = parent->info.rinfo->address;
628  tab_str = "\t";
629  tab_str2 = "\t\t";
630  break;
631  }
632  case MASK:
633  case FIELD:
634  case ENUM:
635  case ENUM_ENTRY:
636  value = curnode->symbol->info.finfo->value;
637  tab_str = "\t\t";
638  tab_str2 = "\t";
639  break;
640  default:
641  value = 0; /* Quiet compiler */
642  tab_str = NULL;
643  tab_str2 = NULL;
644  stop("symtable_dump: Invalid symbol type "
645  "encountered", EX_SOFTWARE);
646  break;
647  }
648  fprintf(ofile, "#define%s%-16s%s0x%02x\n",
649  tab_str, curnode->symbol->name, tab_str2,
650  value);
651  free(curnode);
652  }
653  fprintf(ofile, "\n\n");
654 
655  while (SLIST_FIRST(&constants) != NULL) {
656  symbol_node_t *curnode;
657 
658  curnode = SLIST_FIRST(&constants);
659  SLIST_REMOVE_HEAD(&constants, links);
660  fprintf(ofile, "#define\t%-8s\t0x%02x\n",
661  curnode->symbol->name,
662  curnode->symbol->info.cinfo->value);
663  free(curnode);
664  }
665 
666  fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
667 
668  for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {
669  symbol_node_t *curnode;
670 
671  curnode = SLIST_FIRST(&download_constants);
672  SLIST_REMOVE_HEAD(&download_constants, links);
673  fprintf(ofile, "#define\t%-8s\t0x%02x\n",
674  curnode->symbol->name,
675  curnode->symbol->info.cinfo->value);
676  free(curnode);
677  }
678  fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i);
679 
680  fprintf(ofile, "\n\n/* Exported Labels */\n");
681 
682  while (SLIST_FIRST(&exported_labels) != NULL) {
683  symbol_node_t *curnode;
684 
685  curnode = SLIST_FIRST(&exported_labels);
686  SLIST_REMOVE_HEAD(&exported_labels, links);
687  fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n",
688  curnode->symbol->name,
689  curnode->symbol->info.linfo->address);
690  free(curnode);
691  }
692 }
693