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