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