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