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#8 $ 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, 184 links)) 185 /* 186 * All entries before a '-I-' only 187 * apply to includes specified with 188 * quotes instead of "<>". 189 */ 190 include_dir->quoted_includes_only = 1; 191 } else { 192 include_dir = 193 (path_entry_t)malloc(sizeof(*include_dir)); 194 if (include_dir == NULL) { 195 perror(optarg); 196 stop(NULL, EX_OSERR); 197 } 198 include_dir->directory = strdup(optarg); 199 if (include_dir->directory == NULL) { 200 perror(optarg); 201 stop(NULL, EX_OSERR); 202 } 203 include_dir->quoted_includes_only = 0; 204 SLIST_INSERT_HEAD(&search_path, include_dir, 205 links); 206 } 207 break; 208 } 209 case '?': 210 default: 211 usage(); 212 /* NOTREACHED */ 213 } 214 } 215 argc -= optind; 216 argv += optind; 217 218 if (argc != 1) { 219 fprintf(stderr, "%s: No input file specifiled\n", appname); 220 usage(); 221 /* NOTREACHED */ 222 } 223 224 symtable_open(); 225 inputfilename = *argv; 226 include_file(*argv, SOURCE_FILE); 227 retval = yyparse(); 228 if (retval == 0) { 229 if (SLIST_FIRST(&scope_stack) == NULL 230 || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { 231 stop("Unterminated conditional expression", 232 EX_DATAERR); 233 /* NOTREACHED */ 234 } 235 236 /* Process outmost scope */ 237 process_scope(SLIST_FIRST(&scope_stack)); 238 /* 239 * Decend the tree of scopes and insert/emit 240 * patches as appropriate. We perform a depth first 241 * tranversal, recursively handling each scope. 242 */ 243 /* start at the root scope */ 244 dump_scope(SLIST_FIRST(&scope_stack)); 245 246 /* Patch up forward jump addresses */ 247 back_patch(); 248 249 if (ofile != NULL) 250 output_code(); 251 if (regfile != NULL) { 252 symtable_dump(regfile); 253 } 254 if (listfile != NULL) 255 output_listing(inputfilename); 256 } 257 258 stop(NULL, 0); 259 /* NOTREACHED */ 260 return (0); 261 } 262 263 static void 264 usage() 265 { 266 267 (void)fprintf(stderr, 268 "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file] 269 [-r register_output_file] [-l program_list_file] 270 input_file\n", 271 appname); 272 exit(EX_USAGE); 273 } 274 275 static void 276 back_patch() 277 { 278 struct instruction *cur_instr; 279 280 for (cur_instr = STAILQ_FIRST(&seq_program); 281 cur_instr != NULL; 282 cur_instr = STAILQ_NEXT(cur_instr, links)) { 283 if (cur_instr->patch_label != NULL) { 284 struct ins_format3 *f3_instr; 285 u_int address; 286 287 if (cur_instr->patch_label->type != LABEL) { 288 char buf[255]; 289 290 snprintf(buf, sizeof(buf), 291 "Undefined label %s", 292 cur_instr->patch_label->name); 293 stop(buf, EX_DATAERR); 294 /* NOTREACHED */ 295 } 296 f3_instr = &cur_instr->format.format3; 297 address = f3_instr->address; 298 address += cur_instr->patch_label->info.linfo->address; 299 f3_instr->address = address; 300 } 301 } 302 } 303 304 static void 305 output_code() 306 { 307 struct instruction *cur_instr; 308 patch_t *cur_patch; 309 critical_section_t *cs; 310 symbol_node_t *cur_node; 311 int instrcount; 312 313 instrcount = 0; 314 fprintf(ofile, 315 "/* 316 * DO NOT EDIT - This file is automatically generated 317 * from the following source files: 318 * 319 %s */\n", versions); 320 321 fprintf(ofile, "static uint8_t seqprog[] = {\n"); 322 for (cur_instr = STAILQ_FIRST(&seq_program); 323 cur_instr != NULL; 324 cur_instr = STAILQ_NEXT(cur_instr, links)) { 325 326 fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x", 327 cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n", 328 #if BYTE_ORDER == LITTLE_ENDIAN 329 cur_instr->format.bytes[0], 330 cur_instr->format.bytes[1], 331 cur_instr->format.bytes[2], 332 cur_instr->format.bytes[3]); 333 #else 334 cur_instr->format.bytes[3], 335 cur_instr->format.bytes[2], 336 cur_instr->format.bytes[1], 337 cur_instr->format.bytes[0]); 338 #endif 339 instrcount++; 340 } 341 fprintf(ofile, "\n};\n\n"); 342 343 /* 344 * Output patch information. Patch functions first. 345 */ 346 for (cur_node = SLIST_FIRST(&patch_functions); 347 cur_node != NULL; 348 cur_node = SLIST_NEXT(cur_node,links)) { 349 fprintf(ofile, 350 "static int ahc_patch%d_func(struct ahc_softc *ahc); 351 352 static int 353 ahc_patch%d_func(struct ahc_softc *ahc) 354 { 355 return (%s); 356 }\n\n", 357 cur_node->symbol->info.condinfo->func_num, 358 cur_node->symbol->info.condinfo->func_num, 359 cur_node->symbol->name); 360 } 361 362 fprintf(ofile, 363 "typedef int patch_func_t (struct ahc_softc *); 364 struct patch { 365 patch_func_t *patch_func; 366 uint32_t begin :10, 367 skip_instr :10, 368 skip_patch :12; 369 } patches[] = {\n"); 370 371 for(cur_patch = STAILQ_FIRST(&patches); 372 cur_patch != NULL; 373 cur_patch = STAILQ_NEXT(cur_patch,links)) { 374 fprintf(ofile, "%s\t{ ahc_patch%d_func, %d, %d, %d }", 375 cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n", 376 cur_patch->patch_func, cur_patch->begin, 377 cur_patch->skip_instr, cur_patch->skip_patch); 378 } 379 380 fprintf(ofile, "\n};\n"); 381 382 fprintf(ofile, 383 "struct cs { 384 u_int16_t begin; 385 u_int16_t end; 386 } critical_sections[] = {\n"); 387 388 for(cs = TAILQ_FIRST(&cs_tailq); 389 cs != NULL; 390 cs = TAILQ_NEXT(cs, links)) { 391 fprintf(ofile, "%s\t{ %d, %d }", 392 cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n", 393 cs->begin_addr, cs->end_addr); 394 } 395 396 fprintf(ofile, "\n};\n"); 397 398 fprintf(ofile, 399 "const int num_critical_sections = sizeof(critical_sections) 400 / sizeof(*critical_sections);\n"); 401 402 fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); 403 } 404 405 static void 406 dump_scope(scope_t *scope) 407 { 408 scope_t *cur_scope; 409 410 /* 411 * Emit the first patch for this scope 412 */ 413 emit_patch(scope, 0); 414 415 /* 416 * Dump each scope within this one. 417 */ 418 cur_scope = TAILQ_FIRST(&scope->inner_scope); 419 420 while (cur_scope != NULL) { 421 422 dump_scope(cur_scope); 423 424 cur_scope = TAILQ_NEXT(cur_scope, scope_links); 425 } 426 427 /* 428 * Emit the second, closing, patch for this scope 429 */ 430 emit_patch(scope, 1); 431 } 432 433 void 434 emit_patch(scope_t *scope, int patch) 435 { 436 patch_info_t *pinfo; 437 patch_t *new_patch; 438 439 pinfo = &scope->patches[patch]; 440 441 if (pinfo->skip_instr == 0) 442 /* No-Op patch */ 443 return; 444 445 new_patch = (patch_t *)malloc(sizeof(*new_patch)); 446 447 if (new_patch == NULL) 448 stop("Could not malloc patch structure", EX_OSERR); 449 450 memset(new_patch, 0, sizeof(*new_patch)); 451 452 if (patch == 0) { 453 new_patch->patch_func = scope->func_num; 454 new_patch->begin = scope->begin_addr; 455 } else { 456 new_patch->patch_func = 0; 457 new_patch->begin = scope->end_addr; 458 } 459 new_patch->skip_instr = pinfo->skip_instr; 460 new_patch->skip_patch = pinfo->skip_patch; 461 STAILQ_INSERT_TAIL(&patches, new_patch, links); 462 } 463 464 void 465 output_listing(char *ifilename) 466 { 467 char buf[1024]; 468 FILE *ifile; 469 struct instruction *cur_instr; 470 patch_t *cur_patch; 471 symbol_node_t *cur_func; 472 int *func_values; 473 int instrcount; 474 int instrptr; 475 int line; 476 int func_count; 477 int skip_addr; 478 479 instrcount = 0; 480 instrptr = 0; 481 line = 1; 482 skip_addr = 0; 483 if ((ifile = fopen(ifilename, "r")) == NULL) { 484 perror(ifilename); 485 stop(NULL, EX_DATAERR); 486 } 487 488 /* 489 * Determine which options to apply to this listing. 490 */ 491 for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); 492 cur_func != NULL; 493 cur_func = SLIST_NEXT(cur_func, links)) 494 func_count++; 495 496 func_values = NULL; 497 if (func_count != 0) { 498 func_values = (int *)malloc(func_count * sizeof(int)); 499 500 if (func_values == NULL) 501 stop("Could not malloc", EX_OSERR); 502 503 func_values[0] = 0; /* FALSE func */ 504 func_count--; 505 506 /* 507 * Ask the user to fill in the return values for 508 * the rest of the functions. 509 */ 510 511 512 for (cur_func = SLIST_FIRST(&patch_functions); 513 cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; 514 cur_func = SLIST_NEXT(cur_func, links), func_count--) { 515 int input; 516 517 fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); 518 fprintf(stdout, 519 "Enter the return value for " 520 "this expression[T/F]:"); 521 522 while (1) { 523 524 input = getchar(); 525 input = toupper(input); 526 527 if (input == 'T') { 528 func_values[func_count] = 1; 529 break; 530 } else if (input == 'F') { 531 func_values[func_count] = 0; 532 break; 533 } 534 } 535 if (isatty(fileno(stdin)) == 0) 536 putchar(input); 537 } 538 fprintf(stdout, "\nThanks!\n"); 539 } 540 541 /* Now output the listing */ 542 cur_patch = STAILQ_FIRST(&patches); 543 for(cur_instr = STAILQ_FIRST(&seq_program); 544 cur_instr != NULL; 545 cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) { 546 547 if (check_patch(&cur_patch, instrcount, 548 &skip_addr, func_values) == 0) { 549 /* Don't count this instruction as it is in a patch 550 * that was removed. 551 */ 552 continue; 553 } 554 555 while (line < cur_instr->srcline) { 556 fgets(buf, sizeof(buf), ifile); 557 fprintf(listfile, "\t\t%s", buf); 558 line++; 559 } 560 fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, 561 #if BYTE_ORDER == LITTLE_ENDIAN 562 cur_instr->format.bytes[0], 563 cur_instr->format.bytes[1], 564 cur_instr->format.bytes[2], 565 cur_instr->format.bytes[3]); 566 #else 567 cur_instr->format.bytes[3], 568 cur_instr->format.bytes[2], 569 cur_instr->format.bytes[1], 570 cur_instr->format.bytes[0]); 571 #endif 572 fgets(buf, sizeof(buf), ifile); 573 fprintf(listfile, "\t%s", buf); 574 line++; 575 instrptr++; 576 } 577 /* Dump the remainder of the file */ 578 while(fgets(buf, sizeof(buf), ifile) != NULL) 579 fprintf(listfile, "\t\t%s", buf); 580 581 fclose(ifile); 582 } 583 584 static int 585 check_patch(patch_t **start_patch, int start_instr, 586 int *skip_addr, int *func_vals) 587 { 588 patch_t *cur_patch; 589 590 cur_patch = *start_patch; 591 592 while (cur_patch != NULL && start_instr == cur_patch->begin) { 593 if (func_vals[cur_patch->patch_func] == 0) { 594 int skip; 595 596 /* Start rejecting code */ 597 *skip_addr = start_instr + cur_patch->skip_instr; 598 for (skip = cur_patch->skip_patch; 599 skip > 0 && cur_patch != NULL; 600 skip--) 601 cur_patch = STAILQ_NEXT(cur_patch, links); 602 } else { 603 /* Accepted this patch. Advance to the next 604 * one and wait for our intruction pointer to 605 * hit this point. 606 */ 607 cur_patch = STAILQ_NEXT(cur_patch, links); 608 } 609 } 610 611 *start_patch = cur_patch; 612 if (start_instr < *skip_addr) 613 /* Still skipping */ 614 return (0); 615 616 return (1); 617 } 618 619 /* 620 * Print out error information if appropriate, and clean up before 621 * terminating the program. 622 */ 623 void 624 stop(const char *string, int err_code) 625 { 626 if (string != NULL) { 627 fprintf(stderr, "%s: ", appname); 628 if (yyfilename != NULL) { 629 fprintf(stderr, "Stopped at file %s, line %d - ", 630 yyfilename, yylineno); 631 } 632 fprintf(stderr, "%s\n", string); 633 } 634 635 if (ofile != NULL) { 636 fclose(ofile); 637 if (err_code != 0) { 638 fprintf(stderr, "%s: Removing %s due to error\n", 639 appname, ofilename); 640 unlink(ofilename); 641 } 642 } 643 644 if (regfile != NULL) { 645 fclose(regfile); 646 if (err_code != 0) { 647 fprintf(stderr, "%s: Removing %s due to error\n", 648 appname, regfilename); 649 unlink(regfilename); 650 } 651 } 652 653 if (listfile != NULL) { 654 fclose(listfile); 655 if (err_code != 0) { 656 fprintf(stderr, "%s: Removing %s due to error\n", 657 appname, listfilename); 658 unlink(listfilename); 659 } 660 } 661 662 symlist_free(&patch_functions); 663 symtable_close(); 664 665 exit(err_code); 666 } 667 668 struct instruction * 669 seq_alloc() 670 { 671 struct instruction *new_instr; 672 673 new_instr = (struct instruction *)malloc(sizeof(struct instruction)); 674 if (new_instr == NULL) 675 stop("Unable to malloc instruction object", EX_SOFTWARE); 676 memset(new_instr, 0, sizeof(*new_instr)); 677 STAILQ_INSERT_TAIL(&seq_program, new_instr, links); 678 new_instr->srcline = yylineno; 679 return new_instr; 680 } 681 682 critical_section_t * 683 cs_alloc() 684 { 685 critical_section_t *new_cs; 686 687 new_cs= (critical_section_t *)malloc(sizeof(critical_section_t)); 688 if (new_cs == NULL) 689 stop("Unable to malloc critical_section object", EX_SOFTWARE); 690 memset(new_cs, 0, sizeof(*new_cs)); 691 692 TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links); 693 return new_cs; 694 } 695 696 scope_t * 697 scope_alloc() 698 { 699 scope_t *new_scope; 700 701 new_scope = (scope_t *)malloc(sizeof(scope_t)); 702 if (new_scope == NULL) 703 stop("Unable to malloc scope object", EX_SOFTWARE); 704 memset(new_scope, 0, sizeof(*new_scope)); 705 TAILQ_INIT(&new_scope->inner_scope); 706 707 if (SLIST_FIRST(&scope_stack) != NULL) { 708 TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, 709 new_scope, scope_links); 710 } 711 /* This patch is now the current scope */ 712 SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); 713 return new_scope; 714 } 715 716 void 717 process_scope(scope_t *scope) 718 { 719 /* 720 * We are "leaving" this scope. We should now have 721 * enough information to process the lists of scopes 722 * we encapsulate. 723 */ 724 scope_t *cur_scope; 725 u_int skip_patch_count; 726 u_int skip_instr_count; 727 728 cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); 729 skip_patch_count = 0; 730 skip_instr_count = 0; 731 while (cur_scope != NULL) { 732 u_int patch0_patch_skip; 733 734 patch0_patch_skip = 0; 735 switch (cur_scope->type) { 736 case SCOPE_IF: 737 case SCOPE_ELSE_IF: 738 if (skip_instr_count != 0) { 739 /* Create a tail patch */ 740 patch0_patch_skip++; 741 cur_scope->patches[1].skip_patch = 742 skip_patch_count + 1; 743 cur_scope->patches[1].skip_instr = 744 skip_instr_count; 745 } 746 747 /* Count Head patch */ 748 patch0_patch_skip++; 749 750 /* Count any patches contained in our inner scope */ 751 patch0_patch_skip += cur_scope->inner_scope_patches; 752 753 cur_scope->patches[0].skip_patch = patch0_patch_skip; 754 cur_scope->patches[0].skip_instr = 755 cur_scope->end_addr - cur_scope->begin_addr; 756 757 skip_instr_count += cur_scope->patches[0].skip_instr; 758 759 skip_patch_count += patch0_patch_skip; 760 if (cur_scope->type == SCOPE_IF) { 761 scope->inner_scope_patches += skip_patch_count; 762 skip_patch_count = 0; 763 skip_instr_count = 0; 764 } 765 break; 766 case SCOPE_ELSE: 767 /* Count any patches contained in our innter scope */ 768 skip_patch_count += cur_scope->inner_scope_patches; 769 770 skip_instr_count += cur_scope->end_addr 771 - cur_scope->begin_addr; 772 break; 773 case SCOPE_ROOT: 774 stop("Unexpected scope type encountered", EX_SOFTWARE); 775 /* NOTREACHED */ 776 } 777 778 cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); 779 } 780 } 781