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