Home | History | Annotate | Line # | Download | only in aic7xxx
      1  1.14    andvar /*	$NetBSD: aicasm.c,v 1.14 2023/09/01 11:23:39 andvar Exp $	*/
      2   1.1      fvdl 
      3   1.1      fvdl /*
      4  1.13    andvar  * Aic7xxx SCSI host adapter firmware assembler
      5   1.1      fvdl  *
      6   1.4      fvdl  * Copyright (c) 1997, 1998, 2000, 2001 Justin T. Gibbs.
      7   1.4      fvdl  * Copyright (c) 2001, 2002 Adaptec Inc.
      8   1.1      fvdl  * All rights reserved.
      9   1.1      fvdl  *
     10   1.1      fvdl  * Redistribution and use in source and binary forms, with or without
     11   1.1      fvdl  * modification, are permitted provided that the following conditions
     12   1.1      fvdl  * are met:
     13   1.1      fvdl  * 1. Redistributions of source code must retain the above copyright
     14   1.1      fvdl  *    notice, this list of conditions, and the following disclaimer,
     15   1.4      fvdl  *    without modification.
     16   1.4      fvdl  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     17   1.4      fvdl  *    substantially similar to the "NO WARRANTY" disclaimer below
     18   1.4      fvdl  *    ("Disclaimer") and any redistribution must be conditioned upon
     19   1.4      fvdl  *    including a substantially similar Disclaimer requirement for further
     20   1.4      fvdl  *    binary redistribution.
     21   1.4      fvdl  * 3. Neither the names of the above-listed copyright holders nor the names
     22   1.4      fvdl  *    of any contributors may be used to endorse or promote products derived
     23   1.4      fvdl  *    from this software without specific prior written permission.
     24   1.1      fvdl  *
     25   1.4      fvdl  * Alternatively, this software may be distributed under the terms of the
     26   1.4      fvdl  * GNU General Public License ("GPL") version 2 as published by the Free
     27   1.4      fvdl  * Software Foundation.
     28   1.4      fvdl  *
     29   1.4      fvdl  * NO WARRANTY
     30   1.4      fvdl  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     31   1.4      fvdl  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     32   1.4      fvdl  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     33   1.4      fvdl  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     34   1.4      fvdl  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     35   1.1      fvdl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     36   1.1      fvdl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     37   1.4      fvdl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     38   1.4      fvdl  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     39   1.4      fvdl  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     40   1.4      fvdl  * POSSIBILITY OF SUCH DAMAGES.
     41   1.1      fvdl  *
     42   1.4      fvdl  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.35 2002/08/31 06:39:40 gibbs Exp $
     43   1.1      fvdl  */
     44   1.5     lukem 
     45   1.5     lukem #include <sys/cdefs.h>
     46  1.14    andvar __RCSID("$NetBSD: aicasm.c,v 1.14 2023/09/01 11:23:39 andvar Exp $");
     47   1.5     lukem 
     48   1.1      fvdl #include <sys/types.h>
     49   1.1      fvdl #include <sys/mman.h>
     50   1.1      fvdl 
     51   1.1      fvdl #include <ctype.h>
     52   1.4      fvdl #include <inttypes.h>
     53   1.4      fvdl #include <regex.h>
     54   1.1      fvdl #include <stdio.h>
     55   1.1      fvdl #include <stdlib.h>
     56   1.1      fvdl #include <string.h>
     57   1.1      fvdl #include <sysexits.h>
     58   1.1      fvdl #include <unistd.h>
     59   1.1      fvdl 
     60   1.4      fvdl #if linux
     61   1.4      fvdl #include <endian.h>
     62   1.4      fvdl #else
     63   1.4      fvdl #include <machine/endian.h>
     64   1.4      fvdl #endif
     65   1.4      fvdl 
     66   1.1      fvdl #include "aicasm.h"
     67   1.1      fvdl #include "aicasm_symbol.h"
     68   1.4      fvdl #include "aicasm_insformat.h"
     69   1.1      fvdl 
     70   1.1      fvdl typedef struct patch {
     71   1.1      fvdl 	STAILQ_ENTRY(patch) links;
     72   1.1      fvdl 	int		patch_func;
     73   1.1      fvdl 	u_int		begin;
     74   1.1      fvdl 	u_int		skip_instr;
     75   1.1      fvdl 	u_int		skip_patch;
     76   1.1      fvdl } patch_t;
     77   1.1      fvdl 
     78   1.1      fvdl STAILQ_HEAD(patch_list, patch) patches;
     79   1.1      fvdl 
     80   1.1      fvdl static void usage(void);
     81   1.1      fvdl static void back_patch(void);
     82   1.4      fvdl static void output_code(void);
     83   1.4      fvdl static void output_listing(char *ifilename);
     84   1.1      fvdl static void dump_scope(scope_t *scope);
     85   1.1      fvdl static void emit_patch(scope_t *scope, int patch);
     86   1.1      fvdl static int check_patch(patch_t **start_patch, int start_instr,
     87   1.1      fvdl 		       int *skip_addr, int *func_vals);
     88   1.1      fvdl 
     89   1.1      fvdl struct path_list search_path;
     90   1.1      fvdl int includes_search_curdir;
     91   1.1      fvdl char *appname;
     92   1.4      fvdl char *stock_include_file;
     93   1.1      fvdl FILE *ofile;
     94   1.1      fvdl char *ofilename;
     95   1.1      fvdl char *regfilename;
     96   1.1      fvdl FILE *regfile;
     97   1.1      fvdl char *listfilename;
     98   1.1      fvdl FILE *listfile;
     99   1.4      fvdl char *regdiagfilename;
    100   1.4      fvdl FILE *regdiagfile;
    101   1.4      fvdl int   src_mode;
    102   1.4      fvdl int   dst_mode;
    103   1.1      fvdl 
    104   1.1      fvdl static STAILQ_HEAD(,instruction) seq_program;
    105   1.4      fvdl struct cs_tailq cs_tailq;
    106   1.1      fvdl struct scope_list scope_stack;
    107   1.1      fvdl symlist_t patch_functions;
    108   1.1      fvdl 
    109   1.1      fvdl #if DEBUG
    110   1.1      fvdl extern int yy_flex_debug;
    111   1.4      fvdl extern int mm_flex_debug;
    112   1.1      fvdl extern int yydebug;
    113   1.4      fvdl extern int mmdebug;
    114   1.1      fvdl #endif
    115   1.1      fvdl extern FILE *yyin;
    116   1.4      fvdl extern int yyparse(void);
    117   1.4      fvdl 
    118   1.4      fvdl int main(int argc, char *argv[]);
    119   1.1      fvdl 
    120   1.1      fvdl int
    121   1.4      fvdl main(int argc, char *argv[])
    122   1.1      fvdl {
    123   1.1      fvdl 	extern char *optarg;
    124   1.1      fvdl 	extern int optind;
    125   1.1      fvdl 	int  ch;
    126   1.1      fvdl 	int  retval;
    127   1.1      fvdl 	char *inputfilename;
    128   1.1      fvdl 	scope_t *sentinal;
    129   1.1      fvdl 
    130   1.1      fvdl 	STAILQ_INIT(&patches);
    131   1.1      fvdl 	SLIST_INIT(&search_path);
    132   1.1      fvdl 	STAILQ_INIT(&seq_program);
    133   1.4      fvdl 	TAILQ_INIT(&cs_tailq);
    134   1.1      fvdl 	SLIST_INIT(&scope_stack);
    135   1.1      fvdl 
    136   1.1      fvdl 	/* Set Sentinal scope node */
    137   1.1      fvdl 	sentinal = scope_alloc();
    138   1.1      fvdl 	sentinal->type = SCOPE_ROOT;
    139   1.1      fvdl 
    140   1.1      fvdl 	includes_search_curdir = 1;
    141   1.1      fvdl 	appname = *argv;
    142   1.1      fvdl 	regfile = NULL;
    143   1.1      fvdl 	listfile = NULL;
    144   1.1      fvdl #if DEBUG
    145   1.1      fvdl 	yy_flex_debug = 0;
    146   1.4      fvdl 	mm_flex_debug = 0;
    147   1.1      fvdl 	yydebug = 0;
    148   1.4      fvdl 	mmdebug = 0;
    149   1.1      fvdl #endif
    150   1.4      fvdl 	while ((ch = getopt(argc, argv, "d:i:l:n:o:p:r:I:")) != -1) {
    151   1.1      fvdl 		switch(ch) {
    152   1.1      fvdl 		case 'd':
    153   1.1      fvdl #if DEBUG
    154   1.1      fvdl 			if (strcmp(optarg, "s") == 0) {
    155   1.1      fvdl 				yy_flex_debug = 1;
    156   1.4      fvdl 				mm_flex_debug = 1;
    157   1.1      fvdl 			} else if (strcmp(optarg, "p") == 0) {
    158   1.1      fvdl 				yydebug = 1;
    159   1.4      fvdl 				mmdebug = 1;
    160   1.1      fvdl 			} else {
    161   1.1      fvdl 				fprintf(stderr, "%s: -d Requires either an "
    162   1.1      fvdl 					"'s' or 'p' argument\n", appname);
    163   1.1      fvdl 				usage();
    164   1.1      fvdl 			}
    165   1.1      fvdl #else
    166   1.1      fvdl 			stop("-d: Assembler not built with debugging "
    167   1.1      fvdl 			     "information", EX_SOFTWARE);
    168   1.1      fvdl #endif
    169   1.1      fvdl 			break;
    170   1.4      fvdl 		case 'i':
    171   1.4      fvdl 			stock_include_file = optarg;
    172   1.4      fvdl 			break;
    173   1.1      fvdl 		case 'l':
    174   1.1      fvdl 			/* Create a program listing */
    175   1.1      fvdl 			if ((listfile = fopen(optarg, "w")) == NULL) {
    176   1.1      fvdl 				perror(optarg);
    177   1.1      fvdl 				stop(NULL, EX_CANTCREAT);
    178   1.1      fvdl 			}
    179   1.1      fvdl 			listfilename = optarg;
    180   1.1      fvdl 			break;
    181   1.1      fvdl 		case 'n':
    182  1.13    andvar 			/* Don't complain about the -nostdinc directive */
    183   1.1      fvdl 			if (strcmp(optarg, "ostdinc")) {
    184   1.1      fvdl 				fprintf(stderr, "%s: Unknown option -%c%s\n",
    185   1.1      fvdl 					appname, ch, optarg);
    186   1.1      fvdl 				usage();
    187   1.1      fvdl 				/* NOTREACHED */
    188   1.1      fvdl 			}
    189   1.1      fvdl 			break;
    190   1.1      fvdl 		case 'o':
    191   1.1      fvdl 			if ((ofile = fopen(optarg, "w")) == NULL) {
    192   1.1      fvdl 				perror(optarg);
    193   1.1      fvdl 				stop(NULL, EX_CANTCREAT);
    194   1.1      fvdl 			}
    195   1.1      fvdl 			ofilename = optarg;
    196   1.1      fvdl 			break;
    197   1.4      fvdl 		case 'p':
    198   1.4      fvdl 			/* Create Register Diagnostic "printing" Functions */
    199   1.4      fvdl 			if ((regdiagfile = fopen(optarg, "w")) == NULL) {
    200   1.4      fvdl 				perror(optarg);
    201   1.4      fvdl 				stop(NULL, EX_CANTCREAT);
    202   1.4      fvdl 			}
    203   1.4      fvdl 			regdiagfilename = optarg;
    204   1.4      fvdl 			break;
    205   1.1      fvdl 		case 'r':
    206   1.1      fvdl 			if ((regfile = fopen(optarg, "w")) == NULL) {
    207   1.1      fvdl 				perror(optarg);
    208   1.1      fvdl 				stop(NULL, EX_CANTCREAT);
    209   1.1      fvdl 			}
    210   1.1      fvdl 			regfilename = optarg;
    211   1.1      fvdl 			break;
    212   1.1      fvdl 		case 'I':
    213   1.1      fvdl 		{
    214   1.1      fvdl 			path_entry_t include_dir;
    215   1.1      fvdl 
    216   1.1      fvdl 			if (strcmp(optarg, "-") == 0) {
    217   1.1      fvdl 				if (includes_search_curdir == 0) {
    218   1.1      fvdl 					fprintf(stderr, "%s: Warning - '-I-' "
    219   1.1      fvdl 							"specified multiple "
    220   1.1      fvdl 							"times\n", appname);
    221   1.1      fvdl 				}
    222   1.1      fvdl 				includes_search_curdir = 0;
    223   1.1      fvdl 				for (include_dir = SLIST_FIRST(&search_path);
    224   1.1      fvdl 				     include_dir != NULL;
    225   1.4      fvdl 				     include_dir = SLIST_NEXT(include_dir,
    226   1.4      fvdl 							      links))
    227   1.1      fvdl 					/*
    228   1.1      fvdl 					 * All entries before a '-I-' only
    229   1.1      fvdl 					 * apply to includes specified with
    230   1.1      fvdl 					 * quotes instead of "<>".
    231   1.1      fvdl 					 */
    232   1.1      fvdl 					include_dir->quoted_includes_only = 1;
    233   1.1      fvdl 			} else {
    234   1.1      fvdl 				include_dir =
    235   1.1      fvdl 				    (path_entry_t)malloc(sizeof(*include_dir));
    236   1.1      fvdl 				if (include_dir == NULL) {
    237   1.1      fvdl 					perror(optarg);
    238   1.1      fvdl 					stop(NULL, EX_OSERR);
    239   1.1      fvdl 				}
    240   1.1      fvdl 				include_dir->directory = strdup(optarg);
    241   1.1      fvdl 				if (include_dir->directory == NULL) {
    242   1.1      fvdl 					perror(optarg);
    243   1.1      fvdl 					stop(NULL, EX_OSERR);
    244   1.1      fvdl 				}
    245   1.1      fvdl 				include_dir->quoted_includes_only = 0;
    246   1.1      fvdl 				SLIST_INSERT_HEAD(&search_path, include_dir,
    247   1.1      fvdl 						  links);
    248   1.1      fvdl 			}
    249   1.1      fvdl 			break;
    250   1.1      fvdl 		}
    251   1.1      fvdl 		case '?':
    252   1.1      fvdl 		default:
    253   1.1      fvdl 			usage();
    254   1.1      fvdl 			/* NOTREACHED */
    255   1.1      fvdl 		}
    256   1.1      fvdl 	}
    257   1.1      fvdl 	argc -= optind;
    258   1.1      fvdl 	argv += optind;
    259   1.1      fvdl 
    260   1.1      fvdl 	if (argc != 1) {
    261  1.13    andvar 		fprintf(stderr, "%s: No input file specified\n", appname);
    262   1.1      fvdl 		usage();
    263   1.1      fvdl 		/* NOTREACHED */
    264   1.1      fvdl 	}
    265   1.1      fvdl 
    266   1.4      fvdl 	if (regdiagfile != NULL
    267   1.4      fvdl 	 && (regfile == NULL || stock_include_file == NULL)) {
    268   1.4      fvdl 		fprintf(stderr,
    269   1.4      fvdl 			"%s: The -p option requires the -r and -i options.\n",
    270   1.4      fvdl 			appname);
    271   1.4      fvdl 		usage();
    272   1.4      fvdl 		/* NOTREACHED */
    273   1.4      fvdl 	}
    274   1.1      fvdl 	symtable_open();
    275   1.1      fvdl 	inputfilename = *argv;
    276   1.1      fvdl 	include_file(*argv, SOURCE_FILE);
    277   1.1      fvdl 	retval = yyparse();
    278   1.1      fvdl 	if (retval == 0) {
    279   1.1      fvdl 		if (SLIST_FIRST(&scope_stack) == NULL
    280   1.1      fvdl 		 || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
    281   1.4      fvdl 			stop("Unterminated conditional expression", EX_DATAERR);
    282   1.1      fvdl 			/* NOTREACHED */
    283   1.1      fvdl 		}
    284   1.1      fvdl 
    285   1.1      fvdl 		/* Process outmost scope */
    286   1.1      fvdl 		process_scope(SLIST_FIRST(&scope_stack));
    287   1.1      fvdl 		/*
    288  1.13    andvar 		 * Descend the tree of scopes and insert/emit
    289   1.1      fvdl 		 * patches as appropriate.  We perform a depth first
    290  1.13    andvar 		 * transversal, recursively handling each scope.
    291   1.1      fvdl 		 */
    292   1.1      fvdl 		/* start at the root scope */
    293   1.1      fvdl 		dump_scope(SLIST_FIRST(&scope_stack));
    294   1.1      fvdl 
    295   1.1      fvdl 		/* Patch up forward jump addresses */
    296   1.1      fvdl 		back_patch();
    297   1.1      fvdl 
    298   1.1      fvdl 		if (ofile != NULL)
    299   1.4      fvdl 			output_code();
    300   1.4      fvdl 		if (regfile != NULL)
    301   1.4      fvdl 			symtable_dump(regfile, regdiagfile);
    302   1.1      fvdl 		if (listfile != NULL)
    303   1.4      fvdl 			output_listing(inputfilename);
    304   1.1      fvdl 	}
    305   1.1      fvdl 
    306   1.1      fvdl 	stop(NULL, 0);
    307   1.1      fvdl 	/* NOTREACHED */
    308   1.1      fvdl 	return (0);
    309   1.1      fvdl }
    310   1.1      fvdl 
    311   1.1      fvdl static void
    312   1.7    cegger usage(void)
    313   1.1      fvdl {
    314   1.1      fvdl 
    315   1.1      fvdl 	(void)fprintf(stderr,
    316   1.4      fvdl "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]\n"
    317   1.4      fvdl "	[-r register_output_file [-p register_diag_file -i includefile]]\n"
    318   1.4      fvdl "	[-l program_list_file]\n"
    319   1.4      fvdl "	input_file\n", appname);
    320   1.1      fvdl 	exit(EX_USAGE);
    321   1.1      fvdl }
    322   1.1      fvdl 
    323   1.1      fvdl static void
    324   1.7    cegger back_patch(void)
    325   1.1      fvdl {
    326   1.1      fvdl 	struct instruction *cur_instr;
    327   1.1      fvdl 
    328   1.4      fvdl 	for (cur_instr = STAILQ_FIRST(&seq_program);
    329   1.4      fvdl 	     cur_instr != NULL;
    330   1.4      fvdl 	     cur_instr = STAILQ_NEXT(cur_instr, links)) {
    331   1.1      fvdl 		if (cur_instr->patch_label != NULL) {
    332   1.1      fvdl 			struct ins_format3 *f3_instr;
    333   1.1      fvdl 			u_int address;
    334   1.1      fvdl 
    335   1.1      fvdl 			if (cur_instr->patch_label->type != LABEL) {
    336   1.1      fvdl 				char buf[255];
    337   1.1      fvdl 
    338   1.1      fvdl 				snprintf(buf, sizeof(buf),
    339   1.1      fvdl 					 "Undefined label %s",
    340   1.1      fvdl 					 cur_instr->patch_label->name);
    341   1.1      fvdl 				stop(buf, EX_DATAERR);
    342   1.1      fvdl 				/* NOTREACHED */
    343   1.1      fvdl 			}
    344   1.1      fvdl 			f3_instr = &cur_instr->format.format3;
    345   1.1      fvdl 			address = f3_instr->address;
    346   1.1      fvdl 			address += cur_instr->patch_label->info.linfo->address;
    347   1.1      fvdl 			f3_instr->address = address;
    348   1.1      fvdl 		}
    349   1.1      fvdl 	}
    350   1.1      fvdl }
    351   1.1      fvdl 
    352   1.1      fvdl static void
    353   1.7    cegger output_code(void)
    354   1.1      fvdl {
    355   1.1      fvdl 	struct instruction *cur_instr;
    356   1.1      fvdl 	patch_t *cur_patch;
    357   1.4      fvdl 	critical_section_t *cs;
    358   1.1      fvdl 	symbol_node_t *cur_node;
    359   1.1      fvdl 	int instrcount;
    360   1.1      fvdl 
    361   1.1      fvdl 	instrcount = 0;
    362   1.1      fvdl 	fprintf(ofile,
    363   1.4      fvdl "/*\n"
    364   1.4      fvdl " * DO NOT EDIT - This file is automatically generated\n"
    365   1.4      fvdl " *		 from the following source files:\n"
    366   1.4      fvdl " *\n"
    367   1.4      fvdl "%s */\n", versions);
    368   1.4      fvdl 
    369  1.10  jdolecek 	fprintf(ofile, "static const uint8_t seqprog[] = {\n");
    370   1.4      fvdl 	for (cur_instr = STAILQ_FIRST(&seq_program);
    371   1.4      fvdl 	     cur_instr != NULL;
    372   1.4      fvdl 	     cur_instr = STAILQ_NEXT(cur_instr, links)) {
    373   1.4      fvdl 
    374   1.4      fvdl 		fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x",
    375   1.4      fvdl 			cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n",
    376   1.4      fvdl #if BYTE_ORDER == LITTLE_ENDIAN
    377   1.4      fvdl 			cur_instr->format.bytes[0],
    378   1.4      fvdl 			cur_instr->format.bytes[1],
    379   1.4      fvdl 			cur_instr->format.bytes[2],
    380   1.4      fvdl 			cur_instr->format.bytes[3]);
    381   1.4      fvdl #else
    382   1.1      fvdl 			cur_instr->format.bytes[3],
    383   1.1      fvdl 			cur_instr->format.bytes[2],
    384   1.1      fvdl 			cur_instr->format.bytes[1],
    385   1.1      fvdl 			cur_instr->format.bytes[0]);
    386   1.1      fvdl #endif
    387   1.1      fvdl 		instrcount++;
    388   1.1      fvdl 	}
    389   1.4      fvdl 	fprintf(ofile, "\n};\n\n");
    390   1.4      fvdl 
    391   1.4      fvdl 	if (patch_arg_list == NULL)
    392   1.4      fvdl 		stop("Patch argument list not defined",
    393   1.4      fvdl 		     EX_DATAERR);
    394   1.1      fvdl 
    395   1.1      fvdl 	/*
    396   1.1      fvdl 	 *  Output patch information.  Patch functions first.
    397   1.1      fvdl 	 */
    398   1.4      fvdl 	fprintf(ofile,
    399   1.4      fvdl "typedef int %spatch_func_t (%s);\n", prefix, patch_arg_list);
    400   1.4      fvdl 
    401   1.4      fvdl 	for (cur_node = SLIST_FIRST(&patch_functions);
    402   1.4      fvdl 	     cur_node != NULL;
    403   1.4      fvdl 	     cur_node = SLIST_NEXT(cur_node,links)) {
    404   1.1      fvdl 		fprintf(ofile,
    405   1.4      fvdl "static %spatch_func_t %spatch%d_func;\n"
    406   1.4      fvdl "\n"
    407   1.4      fvdl "static int\n"
    408   1.4      fvdl "%spatch%d_func(%s)\n"
    409   1.4      fvdl "{\n"
    410   1.4      fvdl "	return (%s);\n"
    411   1.4      fvdl "}\n\n",
    412   1.4      fvdl 			prefix,
    413   1.4      fvdl 			prefix,
    414   1.1      fvdl 			cur_node->symbol->info.condinfo->func_num,
    415   1.4      fvdl 			prefix,
    416   1.1      fvdl 			cur_node->symbol->info.condinfo->func_num,
    417   1.4      fvdl 			patch_arg_list,
    418   1.1      fvdl 			cur_node->symbol->name);
    419   1.1      fvdl 	}
    420   1.1      fvdl 
    421   1.1      fvdl 	fprintf(ofile,
    422  1.10  jdolecek "static const struct patch {\n"
    423   1.4      fvdl "	%spatch_func_t		*patch_func;\n"
    424   1.4      fvdl "	uint32_t		 begin		:10,\n"
    425   1.4      fvdl "				 skip_instr	:10,\n"
    426   1.4      fvdl "				 skip_patch	:12;\n"
    427   1.4      fvdl "} patches[] = {\n", prefix);
    428   1.4      fvdl 
    429   1.4      fvdl 	for (cur_patch = STAILQ_FIRST(&patches);
    430   1.4      fvdl 	     cur_patch != NULL;
    431   1.4      fvdl 	     cur_patch = STAILQ_NEXT(cur_patch,links)) {
    432   1.4      fvdl 		fprintf(ofile, "%s\t{ %spatch%d_func, %d, %d, %d }",
    433   1.4      fvdl 			cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n",
    434   1.4      fvdl 			prefix,
    435   1.1      fvdl 			cur_patch->patch_func, cur_patch->begin,
    436   1.1      fvdl 			cur_patch->skip_instr, cur_patch->skip_patch);
    437   1.1      fvdl 	}
    438   1.1      fvdl 
    439   1.4      fvdl 	fprintf(ofile, "\n};\n\n");
    440   1.4      fvdl 
    441   1.4      fvdl 	fprintf(ofile,
    442  1.10  jdolecek "static const struct cs {\n"
    443   1.4      fvdl "	uint16_t	begin;\n"
    444   1.4      fvdl "	uint16_t	end;\n"
    445   1.4      fvdl "} critical_sections[] = {\n");
    446   1.4      fvdl 
    447   1.4      fvdl 	for (cs = TAILQ_FIRST(&cs_tailq);
    448   1.4      fvdl 	     cs != NULL;
    449   1.4      fvdl 	     cs = TAILQ_NEXT(cs, links)) {
    450   1.4      fvdl 		fprintf(ofile, "%s\t{ %d, %d }",
    451   1.4      fvdl 			cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n",
    452   1.4      fvdl 			cs->begin_addr, cs->end_addr);
    453   1.4      fvdl 	}
    454   1.4      fvdl 
    455   1.4      fvdl 	fprintf(ofile, "\n};\n\n");
    456   1.4      fvdl 
    457   1.4      fvdl 	fprintf(ofile,
    458  1.12       ryo "#define NUM_CRITICAL_SECTIONS	\\\n"
    459  1.12       ryo "    (sizeof(critical_sections) / sizeof(*critical_sections))\n");
    460  1.12       ryo 	fprintf(ofile,
    461  1.12       ryo "static const int num_critical_sections = NUM_CRITICAL_SECTIONS;\n");
    462   1.1      fvdl 
    463   1.1      fvdl 	fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
    464   1.1      fvdl }
    465   1.1      fvdl 
    466   1.1      fvdl static void
    467   1.1      fvdl dump_scope(scope_t *scope)
    468   1.1      fvdl {
    469   1.1      fvdl 	scope_t *cur_scope;
    470   1.1      fvdl 
    471   1.1      fvdl 	/*
    472   1.1      fvdl 	 * Emit the first patch for this scope
    473   1.1      fvdl 	 */
    474   1.1      fvdl 	emit_patch(scope, 0);
    475   1.1      fvdl 
    476   1.1      fvdl 	/*
    477   1.1      fvdl 	 * Dump each scope within this one.
    478   1.1      fvdl 	 */
    479   1.1      fvdl 	cur_scope = TAILQ_FIRST(&scope->inner_scope);
    480   1.1      fvdl 
    481   1.1      fvdl 	while (cur_scope != NULL) {
    482   1.1      fvdl 
    483   1.1      fvdl 		dump_scope(cur_scope);
    484   1.1      fvdl 
    485   1.1      fvdl 		cur_scope = TAILQ_NEXT(cur_scope, scope_links);
    486   1.1      fvdl 	}
    487   1.1      fvdl 
    488   1.1      fvdl 	/*
    489   1.1      fvdl 	 * Emit the second, closing, patch for this scope
    490   1.1      fvdl 	 */
    491   1.1      fvdl 	emit_patch(scope, 1);
    492   1.1      fvdl }
    493   1.1      fvdl 
    494   1.1      fvdl void
    495   1.1      fvdl emit_patch(scope_t *scope, int patch)
    496   1.1      fvdl {
    497   1.1      fvdl 	patch_info_t *pinfo;
    498   1.1      fvdl 	patch_t *new_patch;
    499   1.1      fvdl 
    500   1.1      fvdl 	pinfo = &scope->patches[patch];
    501   1.1      fvdl 
    502   1.1      fvdl 	if (pinfo->skip_instr == 0)
    503   1.1      fvdl 		/* No-Op patch */
    504   1.1      fvdl 		return;
    505   1.1      fvdl 
    506   1.1      fvdl 	new_patch = (patch_t *)malloc(sizeof(*new_patch));
    507   1.1      fvdl 
    508   1.1      fvdl 	if (new_patch == NULL)
    509   1.1      fvdl 		stop("Could not malloc patch structure", EX_OSERR);
    510   1.1      fvdl 
    511   1.1      fvdl 	memset(new_patch, 0, sizeof(*new_patch));
    512   1.1      fvdl 
    513   1.1      fvdl 	if (patch == 0) {
    514   1.1      fvdl 		new_patch->patch_func = scope->func_num;
    515   1.1      fvdl 		new_patch->begin = scope->begin_addr;
    516   1.1      fvdl 	} else {
    517   1.1      fvdl 		new_patch->patch_func = 0;
    518   1.1      fvdl 		new_patch->begin = scope->end_addr;
    519   1.1      fvdl 	}
    520   1.1      fvdl 	new_patch->skip_instr = pinfo->skip_instr;
    521   1.1      fvdl 	new_patch->skip_patch = pinfo->skip_patch;
    522   1.1      fvdl 	STAILQ_INSERT_TAIL(&patches, new_patch, links);
    523   1.1      fvdl }
    524   1.1      fvdl 
    525   1.1      fvdl void
    526   1.4      fvdl output_listing(char *ifilename)
    527   1.1      fvdl {
    528   1.1      fvdl 	char buf[1024];
    529   1.1      fvdl 	FILE *ifile;
    530   1.1      fvdl 	struct instruction *cur_instr;
    531   1.1      fvdl 	patch_t *cur_patch;
    532   1.1      fvdl 	symbol_node_t *cur_func;
    533   1.1      fvdl 	int *func_values;
    534   1.1      fvdl 	int instrcount;
    535   1.1      fvdl 	int instrptr;
    536   1.1      fvdl 	int line;
    537   1.1      fvdl 	int func_count;
    538   1.1      fvdl 	int skip_addr;
    539   1.1      fvdl 
    540   1.1      fvdl 	instrcount = 0;
    541   1.1      fvdl 	instrptr = 0;
    542   1.1      fvdl 	line = 1;
    543   1.1      fvdl 	skip_addr = 0;
    544   1.1      fvdl 	if ((ifile = fopen(ifilename, "r")) == NULL) {
    545   1.1      fvdl 		perror(ifilename);
    546   1.1      fvdl 		stop(NULL, EX_DATAERR);
    547   1.1      fvdl 	}
    548   1.1      fvdl 
    549   1.1      fvdl 	/*
    550   1.1      fvdl 	 * Determine which options to apply to this listing.
    551   1.1      fvdl 	 */
    552   1.1      fvdl 	for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
    553   1.1      fvdl 	    cur_func != NULL;
    554   1.1      fvdl 	    cur_func = SLIST_NEXT(cur_func, links))
    555   1.1      fvdl 		func_count++;
    556   1.1      fvdl 
    557   1.4      fvdl 	func_values = NULL;
    558   1.1      fvdl 	if (func_count != 0) {
    559   1.1      fvdl 		func_values = (int *)malloc(func_count * sizeof(int));
    560   1.1      fvdl 
    561   1.1      fvdl 		if (func_values == NULL)
    562   1.1      fvdl 			stop("Could not malloc", EX_OSERR);
    563   1.1      fvdl 
    564   1.1      fvdl 		func_values[0] = 0; /* FALSE func */
    565   1.1      fvdl 		func_count--;
    566   1.1      fvdl 
    567   1.1      fvdl 		/*
    568   1.1      fvdl 		 * Ask the user to fill in the return values for
    569   1.1      fvdl 		 * the rest of the functions.
    570   1.1      fvdl 		 */
    571   1.1      fvdl 
    572   1.1      fvdl 
    573   1.1      fvdl 		for (cur_func = SLIST_FIRST(&patch_functions);
    574   1.1      fvdl 		     cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
    575   1.1      fvdl 		     cur_func = SLIST_NEXT(cur_func, links), func_count--) {
    576   1.1      fvdl 			int input;
    577   1.1      fvdl 
    578   1.1      fvdl 			fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
    579   1.1      fvdl 			fprintf(stdout,
    580   1.1      fvdl 				"Enter the return value for "
    581   1.1      fvdl 				"this expression[T/F]:");
    582   1.1      fvdl 
    583   1.1      fvdl 			while (1) {
    584   1.1      fvdl 
    585   1.1      fvdl 				input = getchar();
    586   1.1      fvdl 				input = toupper(input);
    587   1.1      fvdl 
    588   1.1      fvdl 				if (input == 'T') {
    589   1.1      fvdl 					func_values[func_count] = 1;
    590   1.1      fvdl 					break;
    591   1.1      fvdl 				} else if (input == 'F') {
    592   1.1      fvdl 					func_values[func_count] = 0;
    593   1.1      fvdl 					break;
    594   1.1      fvdl 				}
    595   1.1      fvdl 			}
    596   1.1      fvdl 			if (isatty(fileno(stdin)) == 0)
    597   1.1      fvdl 				putchar(input);
    598   1.1      fvdl 		}
    599   1.8  jakllsch 		free(func_values);
    600   1.9      maxv 		func_values = NULL;
    601   1.1      fvdl 		fprintf(stdout, "\nThanks!\n");
    602   1.1      fvdl 	}
    603   1.1      fvdl 
    604   1.1      fvdl 	/* Now output the listing */
    605   1.1      fvdl 	cur_patch = STAILQ_FIRST(&patches);
    606   1.4      fvdl 	for (cur_instr = STAILQ_FIRST(&seq_program);
    607   1.4      fvdl 	     cur_instr != NULL;
    608   1.4      fvdl 	     cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
    609   1.1      fvdl 
    610   1.9      maxv 		/*
    611   1.9      maxv 		 * XXX XXX XXX: What exactly are we trying to do here?
    612   1.9      maxv 		 * 'func_values' is always NULL, so check_patch will
    613   1.9      maxv 		 * necessarily crash.
    614   1.9      maxv 		 */
    615   1.1      fvdl 		if (check_patch(&cur_patch, instrcount,
    616   1.1      fvdl 				&skip_addr, func_values) == 0) {
    617   1.1      fvdl 			/* Don't count this instruction as it is in a patch
    618   1.1      fvdl 			 * that was removed.
    619   1.1      fvdl 			 */
    620   1.1      fvdl                         continue;
    621   1.1      fvdl 		}
    622   1.1      fvdl 
    623   1.1      fvdl 		while (line < cur_instr->srcline) {
    624   1.1      fvdl 			fgets(buf, sizeof(buf), ifile);
    625   1.1      fvdl 				fprintf(listfile, "\t\t%s", buf);
    626   1.1      fvdl 				line++;
    627   1.1      fvdl 		}
    628   1.1      fvdl 		fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
    629   1.4      fvdl #if BYTE_ORDER == LITTLE_ENDIAN
    630   1.1      fvdl 			cur_instr->format.bytes[0],
    631   1.1      fvdl 			cur_instr->format.bytes[1],
    632   1.1      fvdl 			cur_instr->format.bytes[2],
    633   1.1      fvdl 			cur_instr->format.bytes[3]);
    634   1.4      fvdl #else
    635   1.4      fvdl 			cur_instr->format.bytes[3],
    636   1.4      fvdl 			cur_instr->format.bytes[2],
    637   1.4      fvdl 			cur_instr->format.bytes[1],
    638   1.4      fvdl 			cur_instr->format.bytes[0]);
    639   1.4      fvdl #endif
    640   1.1      fvdl 		fgets(buf, sizeof(buf), ifile);
    641   1.1      fvdl 		fprintf(listfile, "\t%s", buf);
    642   1.1      fvdl 		line++;
    643   1.1      fvdl 		instrptr++;
    644   1.1      fvdl 	}
    645   1.1      fvdl 	/* Dump the remainder of the file */
    646   1.1      fvdl 	while(fgets(buf, sizeof(buf), ifile) != NULL)
    647   1.1      fvdl 		fprintf(listfile, "\t\t%s", buf);
    648   1.1      fvdl 
    649   1.1      fvdl 	fclose(ifile);
    650   1.1      fvdl }
    651   1.1      fvdl 
    652   1.1      fvdl static int
    653   1.1      fvdl check_patch(patch_t **start_patch, int start_instr,
    654   1.1      fvdl 	    int *skip_addr, int *func_vals)
    655   1.1      fvdl {
    656   1.1      fvdl 	patch_t *cur_patch;
    657   1.1      fvdl 
    658   1.1      fvdl 	cur_patch = *start_patch;
    659   1.1      fvdl 
    660   1.1      fvdl 	while (cur_patch != NULL && start_instr == cur_patch->begin) {
    661   1.1      fvdl 		if (func_vals[cur_patch->patch_func] == 0) {
    662   1.1      fvdl 			int skip;
    663   1.1      fvdl 
    664   1.1      fvdl 			/* Start rejecting code */
    665   1.1      fvdl 			*skip_addr = start_instr + cur_patch->skip_instr;
    666   1.1      fvdl 			for (skip = cur_patch->skip_patch;
    667   1.1      fvdl 			     skip > 0 && cur_patch != NULL;
    668   1.1      fvdl 			     skip--)
    669   1.1      fvdl 				cur_patch = STAILQ_NEXT(cur_patch, links);
    670   1.1      fvdl 		} else {
    671   1.1      fvdl 			/* Accepted this patch.  Advance to the next
    672  1.11    andvar 			 * one and wait for our instruction pointer to
    673   1.1      fvdl 			 * hit this point.
    674   1.1      fvdl 			 */
    675   1.1      fvdl 			cur_patch = STAILQ_NEXT(cur_patch, links);
    676   1.1      fvdl 		}
    677   1.1      fvdl 	}
    678   1.1      fvdl 
    679   1.1      fvdl 	*start_patch = cur_patch;
    680   1.1      fvdl 	if (start_instr < *skip_addr)
    681   1.1      fvdl 		/* Still skipping */
    682   1.1      fvdl 		return (0);
    683   1.1      fvdl 
    684   1.1      fvdl 	return (1);
    685   1.1      fvdl }
    686   1.1      fvdl 
    687   1.1      fvdl /*
    688   1.1      fvdl  * Print out error information if appropriate, and clean up before
    689   1.1      fvdl  * terminating the program.
    690   1.1      fvdl  */
    691   1.1      fvdl void
    692   1.4      fvdl stop(const char *string, int err_code)
    693   1.1      fvdl {
    694   1.1      fvdl 	if (string != NULL) {
    695   1.1      fvdl 		fprintf(stderr, "%s: ", appname);
    696   1.1      fvdl 		if (yyfilename != NULL) {
    697   1.1      fvdl 			fprintf(stderr, "Stopped at file %s, line %d - ",
    698   1.1      fvdl 				yyfilename, yylineno);
    699   1.1      fvdl 		}
    700   1.1      fvdl 		fprintf(stderr, "%s\n", string);
    701   1.1      fvdl 	}
    702   1.1      fvdl 
    703   1.1      fvdl 	if (ofile != NULL) {
    704   1.1      fvdl 		fclose(ofile);
    705   1.1      fvdl 		if (err_code != 0) {
    706   1.1      fvdl 			fprintf(stderr, "%s: Removing %s due to error\n",
    707   1.1      fvdl 				appname, ofilename);
    708   1.1      fvdl 			unlink(ofilename);
    709   1.1      fvdl 		}
    710   1.1      fvdl 	}
    711   1.1      fvdl 
    712   1.1      fvdl 	if (regfile != NULL) {
    713   1.1      fvdl 		fclose(regfile);
    714   1.1      fvdl 		if (err_code != 0) {
    715   1.1      fvdl 			fprintf(stderr, "%s: Removing %s due to error\n",
    716   1.1      fvdl 				appname, regfilename);
    717   1.1      fvdl 			unlink(regfilename);
    718   1.1      fvdl 		}
    719   1.1      fvdl 	}
    720   1.1      fvdl 
    721   1.1      fvdl 	if (listfile != NULL) {
    722   1.1      fvdl 		fclose(listfile);
    723   1.1      fvdl 		if (err_code != 0) {
    724   1.1      fvdl 			fprintf(stderr, "%s: Removing %s due to error\n",
    725   1.1      fvdl 				appname, listfilename);
    726   1.1      fvdl 			unlink(listfilename);
    727   1.1      fvdl 		}
    728   1.1      fvdl 	}
    729   1.1      fvdl 
    730   1.1      fvdl 	symlist_free(&patch_functions);
    731   1.1      fvdl 	symtable_close();
    732   1.1      fvdl 
    733   1.1      fvdl 	exit(err_code);
    734   1.1      fvdl }
    735   1.1      fvdl 
    736   1.1      fvdl struct instruction *
    737   1.7    cegger seq_alloc(void)
    738   1.1      fvdl {
    739   1.1      fvdl 	struct instruction *new_instr;
    740   1.1      fvdl 
    741   1.1      fvdl 	new_instr = (struct instruction *)malloc(sizeof(struct instruction));
    742   1.1      fvdl 	if (new_instr == NULL)
    743   1.1      fvdl 		stop("Unable to malloc instruction object", EX_SOFTWARE);
    744   1.1      fvdl 	memset(new_instr, 0, sizeof(*new_instr));
    745   1.1      fvdl 	STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
    746   1.1      fvdl 	new_instr->srcline = yylineno;
    747   1.1      fvdl 	return new_instr;
    748   1.4      fvdl }
    749   1.4      fvdl 
    750   1.4      fvdl critical_section_t *
    751   1.7    cegger cs_alloc(void)
    752   1.4      fvdl {
    753   1.4      fvdl 	critical_section_t *new_cs;
    754   1.4      fvdl 
    755   1.4      fvdl 	new_cs= (critical_section_t *)malloc(sizeof(critical_section_t));
    756   1.4      fvdl 	if (new_cs == NULL)
    757   1.4      fvdl 		stop("Unable to malloc critical_section object", EX_SOFTWARE);
    758   1.4      fvdl 	memset(new_cs, 0, sizeof(*new_cs));
    759   1.4      fvdl 
    760   1.4      fvdl 	TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links);
    761   1.4      fvdl 	return new_cs;
    762   1.1      fvdl }
    763   1.1      fvdl 
    764   1.1      fvdl scope_t *
    765   1.7    cegger scope_alloc(void)
    766   1.1      fvdl {
    767   1.1      fvdl 	scope_t *new_scope;
    768   1.1      fvdl 
    769   1.1      fvdl 	new_scope = (scope_t *)malloc(sizeof(scope_t));
    770   1.1      fvdl 	if (new_scope == NULL)
    771   1.1      fvdl 		stop("Unable to malloc scope object", EX_SOFTWARE);
    772   1.1      fvdl 	memset(new_scope, 0, sizeof(*new_scope));
    773   1.1      fvdl 	TAILQ_INIT(&new_scope->inner_scope);
    774   1.1      fvdl 
    775   1.1      fvdl 	if (SLIST_FIRST(&scope_stack) != NULL) {
    776   1.1      fvdl 		TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
    777   1.1      fvdl 				  new_scope, scope_links);
    778   1.1      fvdl 	}
    779   1.1      fvdl 	/* This patch is now the current scope */
    780   1.1      fvdl 	SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
    781   1.1      fvdl 	return new_scope;
    782   1.1      fvdl }
    783   1.1      fvdl 
    784   1.1      fvdl void
    785   1.1      fvdl process_scope(scope_t *scope)
    786   1.1      fvdl {
    787   1.1      fvdl 	/*
    788   1.1      fvdl 	 * We are "leaving" this scope.  We should now have
    789   1.1      fvdl 	 * enough information to process the lists of scopes
    790   1.1      fvdl 	 * we encapsulate.
    791   1.1      fvdl 	 */
    792   1.1      fvdl 	scope_t *cur_scope;
    793   1.1      fvdl 	u_int skip_patch_count;
    794   1.1      fvdl 	u_int skip_instr_count;
    795   1.1      fvdl 
    796   1.1      fvdl 	cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
    797   1.1      fvdl 	skip_patch_count = 0;
    798   1.1      fvdl 	skip_instr_count = 0;
    799   1.1      fvdl 	while (cur_scope != NULL) {
    800   1.1      fvdl 		u_int patch0_patch_skip;
    801   1.1      fvdl 
    802   1.1      fvdl 		patch0_patch_skip = 0;
    803   1.1      fvdl 		switch (cur_scope->type) {
    804   1.1      fvdl 		case SCOPE_IF:
    805   1.1      fvdl 		case SCOPE_ELSE_IF:
    806   1.1      fvdl 			if (skip_instr_count != 0) {
    807   1.1      fvdl 				/* Create a tail patch */
    808   1.1      fvdl 				patch0_patch_skip++;
    809   1.1      fvdl 				cur_scope->patches[1].skip_patch =
    810   1.1      fvdl 				    skip_patch_count + 1;
    811   1.1      fvdl 				cur_scope->patches[1].skip_instr =
    812   1.1      fvdl 				    skip_instr_count;
    813   1.1      fvdl 			}
    814   1.1      fvdl 
    815   1.1      fvdl 			/* Count Head patch */
    816   1.1      fvdl 			patch0_patch_skip++;
    817   1.1      fvdl 
    818   1.1      fvdl 			/* Count any patches contained in our inner scope */
    819   1.1      fvdl 			patch0_patch_skip += cur_scope->inner_scope_patches;
    820   1.1      fvdl 
    821   1.1      fvdl 			cur_scope->patches[0].skip_patch = patch0_patch_skip;
    822   1.1      fvdl 			cur_scope->patches[0].skip_instr =
    823   1.1      fvdl 			    cur_scope->end_addr - cur_scope->begin_addr;
    824   1.1      fvdl 
    825   1.1      fvdl 			skip_instr_count += cur_scope->patches[0].skip_instr;
    826   1.1      fvdl 
    827   1.1      fvdl 			skip_patch_count += patch0_patch_skip;
    828   1.1      fvdl 			if (cur_scope->type == SCOPE_IF) {
    829   1.1      fvdl 				scope->inner_scope_patches += skip_patch_count;
    830   1.1      fvdl 				skip_patch_count = 0;
    831   1.1      fvdl 			        skip_instr_count = 0;
    832   1.1      fvdl 			}
    833   1.1      fvdl 			break;
    834   1.1      fvdl 		case SCOPE_ELSE:
    835  1.14    andvar 			/* Count any patches contained in our inner scope */
    836   1.1      fvdl 			skip_patch_count += cur_scope->inner_scope_patches;
    837   1.1      fvdl 
    838   1.1      fvdl 			skip_instr_count += cur_scope->end_addr
    839   1.1      fvdl 					  - cur_scope->begin_addr;
    840   1.1      fvdl 			break;
    841   1.1      fvdl 		case SCOPE_ROOT:
    842   1.1      fvdl 			stop("Unexpected scope type encountered", EX_SOFTWARE);
    843   1.1      fvdl 			/* NOTREACHED */
    844   1.1      fvdl 		}
    845   1.1      fvdl 
    846   1.1      fvdl 		cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
    847   1.1      fvdl 	}
    848   1.1      fvdl }
    849