void seg_fault() { TrapDebug((dbg_file, "Apout - pid %d segmentation fault at PC 0%06o\n", (int)getpid(), regs[PC])); TrapDebug((dbg_file, "%06o ", ir)); TrapDebug((dbg_file, "%o %o %o %o %o %o %o %o ", regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7])); TrapDebug((dbg_file, "NZVC3 are %d%d%d%d\n",CC_N,CC_Z,CC_V,CC_C)); exit(EXIT_FAILURE); }
void bus_error(int signo) { TrapDebug((dbg_file, "Apout - pid %d bus error at PC 0%06o\n", (int)getpid(), regs[PC])); TrapDebug((dbg_file, "%06o ", ir)); TrapDebug((dbg_file, "%o %o %o %o %o %o %o %o ", regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7])); TrapDebug((dbg_file, "NZVC2 are %d%d%d%d\n",CC_N,CC_Z,CC_V,CC_C)); exit(EXIT_FAILURE); }
/* Run until told to stop. */ void run() { #ifdef DEBUG int i; if (trap_debug) { TrapDebug((dbg_file, "Just starting to run pid %d\n",(int)getpid())); TrapDebug((dbg_file, "Regs are ")); for (i=0;i<=PC;i++) TrapDebug((dbg_file, "%06o ",regs[i])); TrapDebug((dbg_file, "\n")); } #endif while (1) { /* Fetch and execute the instruction. */ #ifdef DEBUG lli_word(regs[PC], ir); if (inst_debug) { i= ir >> 6; switch (i) { case 0: name= iname0[ir & 077]; break; case 2: name= iname1[ir & 077]; break; default: name= iname[i]; } TrapDebug((dbg_file, "%06o %06o %4s ", regs[7], ir, name)); TrapDebug((dbg_file, "%06o %06o %06o %06o %06o %06o %06o ", regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6])); TrapDebug((dbg_file, "NZVC1 %d%d%d%d\n",CC_N,CC_Z,CC_V,CC_C)); fflush(dbg_file); } regs[PC] += 2; itab[ir >> 6] (); if ((Sighead!=NULL) && (sigrunner!=NULL)) (void) (*sigrunner)(); #else /* When not debugging, we can manually unroll this inner loop */ lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] (); if ((Sighead!=NULL) && (sigrunner!=NULL)) (void) (*sigrunner)(); #endif } }
/* This is the generic function which catches * a signal, and appends it to the queue. */ void sigcatcher(int sig) { struct our_siglist *this; this= (struct our_siglist *)malloc(sizeof(struct our_siglist)); if (this==NULL) return; TrapDebug((dbg_file, "Caught signal %d\n",sig)); this->sig=sig; this->next=NULL; if (Sighead==NULL) { Sighead=Sigtail=this; } else { Sigtail->next= this; Sigtail=this; } }
void bad_FP_reg() { TrapDebug((stderr, "Apout - pid %d bad FP register used at PC 0%o\n", (int)getpid(), regs[PC])); exit(EXIT_FAILURE); }
void trap() { TrapDebug((stderr, "Apout - pid %d trap instruction at PC 0%o\n", (int)getpid(), regs[PC])); exit(EXIT_FAILURE); }
void not_impl() { TrapDebug((stderr, "Apout - pid %d unimplemented instruction at PC 0%o\n", (int)getpid(), regs[PC])); exit(EXIT_FAILURE); }
void illegal() { TrapDebug((stderr, "Apout - pid %d illegal instruction %o at PC 0%o\n", (int)getpid(),ir, regs[PC])); exit(EXIT_FAILURE); }
/* Load the named PDP-11 executable file into the emulator's memory. * Returns 0 if ok, -1 if error. Also initialise the simulator and set * up the stack for the process with Argc, Argv, Envc, Envp. * origpath is the path to the executable as seen by the simulated * parent, or NULL if this is not known. */ int load_a_out(const char *file, const char *origpath, int want_env) { /* @globals errno,stdout,stderr; @ */ #define V12_MEMBASE 16384 /* Offset for V1/V2 binaries load */ FILE *zin; struct exec e; u_int8_t *ibase, *dbase, *bbase; /* Instruction, data, bss bases */ u_int16_t size; int i; #ifdef EMU211 int j; #endif #ifdef RUN_V1_RAW struct stat stb; #endif for (i = 0; i < Argc; i++) TrapDebug((dbg_file, "In load_a_out Argv[%d] is %s\n", i, Argv[i])); (void) signal(SIGBUS, bus_error); /* Catch all bus errors here */ if ((zin = fopen(file, "r")) == NULL) /* Open the file */ return (-1); Binary = load_aout_header(zin, &e); /* Determine a.out & Unix type */ if (e.a_magic == ANY_SCRIPT) { /* Shell script, run that */ return (load_script(file, origpath, zin, want_env)); } #ifndef EMU211 if (Binary == IS_211BSD) { (void) fprintf(stderr, "Apout not compiled to support 2.11BSD binaries\n"); (void) fclose(zin); return (-1); } #endif #ifndef EMUV1 if (Binary == IS_V1) { (void) fprintf(stderr, "Apout not compiled to support 1st Edition binaries\n"); (void) fclose(zin); return (-1); } if (Binary == IS_V2) { (void) fprintf(stderr, "Apout not compiled to support 2nd Edition binaries\n"); (void) fclose(zin); return (-1); } #endif #ifdef NATIVES /* Executable was not recognised. * Try to exec it as a native binary. * If it fails, doesn't matter. If it * succeeds, then great. This allows * us to have mixed native and PDP-11 * binaries in the same filespace. */ if (e.a_magic == UNKNOWN_AOUT) { #ifdef DEBUG TrapDebug((dbg_file, "About to try native exec on %s\n", file)); fflush(dbg_file); #endif (void) fclose(zin); execv(file, Argv); /* envp[] is the one Apout's main() got */ TrapDebug((dbg_file, "Nope, didn't work\n")); #endif #ifdef RUN_V1_RAW /* Try to run it as a V1 raw binary */ #ifdef DEBUG TrapDebug((dbg_file, "About to try PDP-11 raw exec on %s\n", file)); fflush(dbg_file); #endif /* DEBUG */ if ((zin = fopen(file, "r")) == NULL) /* reopen the file */ return (-1); e.a_magic = V1_RAW; Binary = IS_V1; #else (void) fprintf(stderr, "Apout - unknown a.out file %s\n", file); return (-1); #endif /* RUN_V1_RAW */ } /* Now we know what environment to * create, set up the memory areas * according to the magic numbers */ #ifdef DEBUG switch (Binary) { case IS_A68: TrapDebug((dbg_file, "A68 binary\n")); break; case IS_V1: TrapDebug((dbg_file, "V1 binary\n")); break; case IS_V2: TrapDebug((dbg_file, "V2 binary\n")); break; case IS_V5: TrapDebug((dbg_file, "V5 binary\n")); break; case IS_V6: TrapDebug((dbg_file, "V6 binary\n")); break; case IS_V7: TrapDebug((dbg_file, "V7 binary\n")); break; case IS_211BSD: TrapDebug((dbg_file, "2.11BSD binary\n")); break; } #endif switch (e.a_magic) { #ifdef RUN_V1_RAW case V1_RAW: if (fseek(zin, 0, SEEK_SET) != 0) { (void) fclose(zin); return (-1); } ispace = dspace = darray; ibase = &(ispace[V12_MEMBASE]); /* Load & run the binary starting */ dbase = ibase; /* at address 16384 (040000) */ dwrite_base = 0; e.a_entry = V12_MEMBASE; /* Reset the exec header fields to make loading code below * work properly */ if (stat(file, &stb)) { fprintf(stderr, "Apout - cannot stat %s\n", file); return -1; } e.a_text = stb.st_size; bbase = &(ispace[V12_MEMBASE + e.a_text]); e.a_data = 0; break; #endif #ifdef EMUV1 case V1_NORMAL: /* V1 a.out binary looks like */ e.a_bss = e.a_syms; /* 0405 */ e.a_syms = e.a_data; /* size of text */ e.a_data = 0; /* size of symbol table */ /* reloc bits */ /* size of data (i.e bss) */ /* unused and zeroed */ /* We must rearrange fields */ /* Move back to start of V1 header */ if (fseek(zin, 0, SEEK_SET) != 0) { (void) fclose(zin); return (-1); } ispace = dspace = darray; ibase = &(ispace[V12_MEMBASE]); /* Load & run the binary starting */ dbase = &(ispace[e.a_text]); /* at address 16384 (040000) */ bbase = &(ispace[e.a_text + e.a_data]); dwrite_base = 0; e.a_entry = V12_MEMBASE; break; #endif case A68_MAGIC: /* Algol 68 image */ if (fseek(zin, 0, SEEK_SET) != 0) { (void) fclose(zin); return (-1); } e.a_text = e.ov_siz[0] + 1; e.a_data = 0; e.a_bss = 0160000 - e.a_text; e.a_entry = e.a_flag; ibase = ispace = dspace = darray; dbase = ibase; dwrite_base = 0; bbase = &(ispace[e.a_text + e.a_data]); break; case ANY_NORMAL: /* Move back to end of V5/6/7 header */ if (fseek(zin, 16, SEEK_SET) != 0) { (void) fclose(zin); return (-1); } ibase = ispace = dspace = darray; #ifdef EMUV1 if (Binary == IS_V2) { ibase = &(ispace[V12_MEMBASE]); e.a_entry = V12_MEMBASE; dbase = &(ispace[e.a_text + V12_MEMBASE]); bbase = &(ispace[e.a_text + e.a_data + V12_MEMBASE]); } else #endif { dbase = &(ispace[e.a_text]); bbase = &(ispace[e.a_text + e.a_data]); } if ((Binary < IS_V7)) dwrite_base = 0; else dwrite_base = e.a_text; break; case ANY_ROTEXT: /* Move back to end of V5/6/7 header */ if (fseek(zin, 16, SEEK_SET) != 0) { (void) fclose(zin); return (-1); } /* @fallthrough@ */ case BSD_OVERLAY: /* Round up text area to next 8K boundary */ if (e.a_text % EIGHT_K) { size = EIGHT_K * (1 + e.a_text / EIGHT_K); } else size = e.a_text; /* And the next 8K boundary if overlays! */ if (e.a_magic == BSD_OVERLAY) { if (e.max_ovl % EIGHT_K) { size += EIGHT_K * (1 + e.max_ovl / EIGHT_K); } else size += e.max_ovl; } ibase = ispace = dspace = darray; dbase = &(ispace[size]); bbase = &(ispace[size + e.a_data]); dwrite_base = size; break; case ANY_SPLITID: /* Move back to end of V5/6/7 header */ if (fseek(zin, 16, SEEK_SET) != 0) { (void) fclose(zin); return (-1); } /* @fallthrough@ */ case BSD_ROVERLAY: ibase = ispace = iarray; dbase = dspace = darray; bbase = &(dspace[e.a_data]); /* Try to stop null refs */ if (Binary == IS_211BSD) dwrite_base = 0; else dwrite_base = 2; break; default: (void) fprintf(stderr, "Apout - unknown a.out format 0%o\n", e.a_magic); (void) fclose(zin); return (-1); } /* Initialise the instruction table for our environment */ switch (Binary) { #ifdef EMU211 case IS_211BSD: for (i = 548; i < 552; i++) itab[i] = bsdtrap; break; #endif #ifdef EMUV1 case IS_V1: case IS_V2: for (i = 544; i < 548; i++) itab[i] = rts; for (i = 548; i < 552; i++) itab[i] = v1trap; break; #endif case IS_A68: for (i = 544; i < 552; i++) itab[i] = v7trap; break; case IS_V5: case IS_V6: case IS_V7: for (i = 548; i < 552; i++) itab[i] = v7trap; break; default: fprintf(stderr, "Apout - unknown Unix version for %s\n", file); exit(EXIT_FAILURE); } #ifdef ZERO_MEMORY memset(darray, 0, PDP_MEM_SIZE); /* Clear all memory */ if (ispace != dspace) memset(iarray, 0, PDP_MEM_SIZE); #endif /* Now load the text into ibase */ for (size = e.a_text; size;) { i = (int) fread(ibase, 1, (size_t) size, zin); if (i == -1) { (void) fclose(zin); return (i); } size -= i; ibase += i; } #ifdef EMU211 /* Now deal with any overlays */ if (Binary == IS_211BSD) switch (e.a_magic) { case BSD_OVERLAY: case BSD_ROVERLAY: /* Round up text area to next 8K boundary */ if (e.a_text % EIGHT_K) { size = EIGHT_K * (1 + e.a_text / EIGHT_K); } else size = e.a_text; ovbase = &ispace[size]; for (i = 0; i < NOVL; i++) { if (e.ov_siz[i] == 0) { ovlist[i].size = 0; ovlist[i].ovlay = NULL; continue; } /* Create memory for the overlay */ ovlist[i].size = e.ov_siz[i]; if (ovlist[i].ovlay) free(ovlist[i].ovlay); ovlist[i].ovlay = (u_int8_t *) malloc(e.ov_siz[i]); if (ovlist[i].ovlay == NULL) { fprintf(stderr, "Apout - can't malloc overlay!\n"); exit(EXIT_FAILURE); } /* Load the overlay into memory */ for (size = ovlist[i].size, ibase = ovlist[i].ovlay; size;) { j = fread(ibase, 1, size, zin); if (j == -1) { fclose(zin); return (j); } size -= j; ibase += j; } } /* And deal with the emt instructions */ for (i = 544; i < 548; i++) itab[i] = do_bsd_overlay; } #endif /* Now load the data into dbase */ if (dbase) for (size = e.a_data; size;) { i = (int) fread(dbase, 1, (size_t) size, zin); if (i == -1) { (void) fclose(zin); return (i); } size -= i; dbase += i; } /* Now clear the bss */ if ((bbase != 0) && (e.a_bss != 0)) memset(bbase, 0, (size_t) e.a_bss); /* Set up the registers and flags, and the stack */ (void) fclose(zin); sim_init(); regs[PC] = e.a_entry; if (Binary == IS_A68) { regs[5] = e.max_ovl; regs[4] = 0160000; } set_arg_env(want_env); return (0); }
/* Read in the executable name and its arguments from the shell script, * and the re-call load_a_out to load in that binary. Returns 0 on * success, -1 on error. Input file is always closed by this routine. */ int load_script(const char *file, const char *origpath, FILE * zin, int want_env) { #define SCRIPT_LINESIZE 512 /* Max size of 1st line in script */ char *script_line; char *script_arg[MAX_ARGS]; int i, script_cnt = 0; char **ap; for (i = 0; i < Argc; i++) TrapDebug((dbg_file, "In load_script Argv[%d] is %s\n", i, Argv[i])); /* Get the first line of the file */ if (((script_line = (char *) malloc(SCRIPT_LINESIZE)) == NULL) || (fgets(script_line, SCRIPT_LINESIZE, zin) == NULL)) { (void) fprintf(stderr, "Apout - could not read 1st line of script\n"); (void) fclose(zin); return (-1); } /* Now break into separate words */ for (ap = script_arg; (*ap = strsep(&script_line, " \t\n")) != NULL;) if (**ap != '\0') { ap++; script_cnt++; if (script_cnt >= MAX_ARGS) break; } if (fclose(zin) != 0) { free(script_line); return (-1); } #ifdef DEBUG TrapDebug((dbg_file, "Script: extra args are is %d\n", script_cnt)); if (trap_debug) { for (i = 0; i < script_cnt; i++) fprintf(dbg_file, " script_arg[%d] is %s\n", i, script_arg[i]); } #endif /* Ensure we have room to shift the args */ if ((Argc + script_cnt) > MAX_ARGS) { (void) fprintf(stderr, "Apout - out of argv space in script\n"); free(script_line); return (-1); } /* Now shift the args up and insert new ones */ for (i = Argc - 1; i != 0; i--) Argv[i + script_cnt] = Argv[i]; for (i = 0; i < Argc; i++) TrapDebug((dbg_file, "Part A load_script Argv[%d] is %s\n", i, Argv[i])); for (i = 0; i < script_cnt; i++) Argv[i] = script_arg[i]; if (origpath != NULL) Argv[i] = strdup(origpath); else Argv[i] = strdup(file); Argc += script_cnt; for (i = 0; i < Argc; i++) TrapDebug((dbg_file, "Part B load_script Argv[%d] is %s\n", i, Argv[i])); file = xlate_filename(script_arg[0]); free(script_line); for (i = 0; i < Argc; i++) TrapDebug((dbg_file, "Leaving load_script Argv[%d] is %s\n", i, Argv[i])); return (load_a_out(file, origpath, want_env)); }