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