Annotation of nono/util/runx/runx.cpp, revision 1.1

1.1     ! root        1: // vi:set ts=4:
        !             2: 
        !             3: //
        !             4: // nono
        !             5: // Copyright (C) 2024 nono project
        !             6: // Licensed under nono-license.txt
        !             7: //
        !             8: 
        !             9: //
        !            10: // Human68k の実行ファイルを NetBSD/m68k 上で実行する。
        !            11: //
        !            12: 
        !            13: // メモリマップ
        !            14: // 0000'0000 ベクタ
        !            15: // 0000'1000 (4KB/ページの時の mmap 開始アドレス)
        !            16: // 0000'2000 (8KB/ページの時の mmap 開始アドレス)
        !            17: // 0000'2000 初期 A7 保存 (func_t から戻るため)
        !            18: // 0000'2200 エントリポイント
        !            19: // 0000'c000 コマンドライン引数
        !            20: // 0001'ff00 SSP 初期値
        !            21: // 0001'ff00 PSP (プロセスエントリ)
        !            22: // 0002'0000 ロードアドレス
        !            23: 
        !            24: #include "runx.h"
        !            25: #include <fcntl.h>
        !            26: #include <inttypes.h>
        !            27: #include <libgen.h>
        !            28: #include <limits.h>
        !            29: #include <signal.h>
        !            30: #include <stdlib.h>
        !            31: #include <string.h>
        !            32: #include <sys/mman.h>
        !            33: #include <sys/stat.h>
        !            34: #include <sys/wait.h>
        !            35: 
        !            36: // ぽかよけ
        !            37: #if !defined(__m68k__)
        !            38: #error "This file must be compiled on m68k!"
        !            39: #endif
        !            40: 
        !            41: #define LOAD_ADDR  (0x20000)
        !            42: 
        !            43: typedef int (*func_t)();
        !            44: 
        !            45: // .X ファイルのヘッダ構造
        !            46: struct XFileHeader {
        !            47:    uint8  magic[2];        // +00 識別子 'HU'
        !            48:    uint8  unused1;
        !            49:    uint8  loadmode;        // +03 ロードモード
        !            50:    uint32 base_addr;       // +04 ベースアドレス
        !            51:    uint32 exec_addr;       // +08 実行開始アドレス
        !            52:    uint32 text_size;       // +0c テキストサイズ
        !            53:    uint32 data_size;       // +10 データサイズ
        !            54:    uint32 bss_size;        // +14 BSS サイズ
        !            55:    uint32 reloc_size;      // +18 再配置テーブルサイズ
        !            56:    uint32 symbol_size;     // +1c シンボルサイズ
        !            57:    uint32 scdline_size;    // +20 SCD 行番号テーブルサイズ
        !            58:    uint32 scdsym_size;     // +24 SCD シンボルテーブルサイズ
        !            59:    uint32 scdstr_size;     // +28 SCD 文字列テーブルサイズ
        !            60:    uint32 unused2[4];
        !            61:    uint32 module_offset;   // +3c モジュールリストの位置
        !            62: } __packed;
        !            63: 
        !            64: static void usage();
        !            65: static void init_mem();
        !            66: static uint32 loadfile();
        !            67: static uint32 loadfileX();
        !            68: static uint32 loadfileR();
        !            69: static void dumpwait(int);
        !            70: static void dumpreg(const struct reg *);
        !            71: static int  run(uint32);
        !            72: 
        !            73: int opt_debug;
        !            74: int opt_trace;
        !            75: struct reg_emul emul;
        !            76: 
        !            77: static const char *filename;
        !            78: static uint32 last_addr;
        !            79: static uint8 *mem;
        !            80: static uint8 *page0;
        !            81: static uint32 pgsize;
        !            82: static uint32 ret_addr;
        !            83: static char human68k_arg[255];
        !            84: 
        !            85: int
        !            86: main(int ac, char *av[])
        !            87: {
        !            88:    int c;
        !            89: 
        !            90:    while ((c = getopt(ac, av, "dt")) != -1) {
        !            91:        switch (c) {
        !            92:         case 'd':
        !            93:            opt_debug++;
        !            94:            break;
        !            95:         case 't':
        !            96:            opt_trace = 1;
        !            97:            break;
        !            98:         default:
        !            99:            usage();
        !           100:        }
        !           101:    }
        !           102:    ac -= optind;
        !           103:    av += optind;
        !           104: 
        !           105:    if (ac < 1) {
        !           106:        usage();
        !           107:    }
        !           108: 
        !           109:    // Human68k コマンド名と引数。
        !           110:    filename = av[0];
        !           111:    human68k_arg[0] = '\0';
        !           112:    for (int i = 1; i < ac; i++) {
        !           113:        if (i != 1) {
        !           114:            strlcat(human68k_arg, " ", sizeof(human68k_arg));
        !           115:        }
        !           116:        strlcat(human68k_arg, av[i], sizeof(human68k_arg));
        !           117:    }
        !           118:    DEBUG(1, "human68k_arg=\"%s\"", human68k_arg);
        !           119: 
        !           120:    // 0番地を含む1ページは mmap(2) とかでも割り当て出来ないようなので
        !           121:    // 仕方ないので自前で用意する。
        !           122:    pgsize = getpgsize();
        !           123:    page0 = (uint8 *)calloc(1, pgsize);
        !           124:    if (page0 == NULL) {
        !           125:        err(1, "calloc failed");
        !           126:    }
        !           127: 
        !           128:    // mem は pgsize 番地以降 12MB までを確保しておく。
        !           129:    // このためにこの実行ファイル自身は 16MB 以降にロードしてある。
        !           130:    mem = (uint8 *)mmap((void *)pgsize, 12*1024*1024 - pgsize,
        !           131:        PROT_READ | PROT_WRITE,
        !           132:        MAP_FIXED | MAP_ANON | MAP_SHARED | MAP_INHERIT, -1, 0);
        !           133:    if (mem == MAP_FAILED) {
        !           134:        err(1, "mmap");
        !           135:    }
        !           136:    DEBUG(2, "mem=%p", mem);
        !           137:    init_mem();
        !           138:    init_doscall();
        !           139: 
        !           140:    // ロード。
        !           141:    uint32 exec_addr = loadfile();
        !           142:    if (exec_addr == (uint32)-1) {
        !           143:        exit(1);
        !           144:    }
        !           145: 
        !           146:    // 実行。
        !           147:    if (run(exec_addr) < 0) {
        !           148:        exit(1);
        !           149:    }
        !           150: 
        !           151:    return 0;
        !           152: }
        !           153: 
        !           154: static void
        !           155: usage()
        !           156: {
        !           157:    fprintf(stderr, "%s <Human68k executable> [<argument...>]\n",
        !           158:        getprogname());
        !           159:    exit(1);
        !           160: }
        !           161: 
        !           162: // メモリの初期化。何をどこまでやるか。
        !           163: static void
        !           164: init_mem()
        !           165: {
        !           166:    writemem1(0xcbc, 3);    // とりあえず
        !           167:    writemem1(0xcbd, 0xff);
        !           168: }
        !           169: 
        !           170: // 実行ファイルをロードする。
        !           171: static uint32
        !           172: loadfile()
        !           173: {
        !           174:    const char *e;
        !           175: 
        !           176:    // Support only .X and .R executable for now.
        !           177:    e = strrchr(filename, '.');
        !           178:    if (e != NULL && strcasecmp(e, ".x") == 0) {
        !           179:        return loadfileX();
        !           180:    } else {
        !           181:        return loadfileR();
        !           182:    }
        !           183: }
        !           184: 
        !           185: // .X ファイルを読み込んで、リロケートまで行う。
        !           186: static uint32
        !           187: loadfileX()
        !           188: {
        !           189:    struct stat st;
        !           190:    struct XFileHeader *xhdr;
        !           191:    uint8 *file;
        !           192:    int fd;
        !           193: 
        !           194:    fd = open(filename, O_RDONLY);
        !           195:    if (fd < 0) {
        !           196:        err(1, "%s", filename);
        !           197:    }
        !           198: 
        !           199:    if (fstat(fd, &st) < 0) {
        !           200:        err(1, "%s: stat failed", filename);
        !           201:    }
        !           202:    DEBUG(1, "loading %s %u bytes", filename, (uint)st.st_size);
        !           203: 
        !           204:    file = (uint8 *)mmap(NULL, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
        !           205:        fd, 0);
        !           206:    if (file == MAP_FAILED) {
        !           207:        err(1, "%s: mmap failed", filename);
        !           208:    }
        !           209: 
        !           210:    xhdr = (struct XFileHeader *)file;
        !           211:    if (xhdr->magic[0] != 'H' || xhdr->magic[1] != 'U') {
        !           212:        errx(1, "%s: is not .X file", filename);
        !           213:    }
        !           214: 
        !           215:    uint32 base_addr = be32toh(xhdr->base_addr);
        !           216:    uint32 exec_addr = be32toh(xhdr->exec_addr);
        !           217:    uint32 text_size = be32toh(xhdr->text_size);
        !           218:    uint32 data_size = be32toh(xhdr->data_size);
        !           219:    uint32 bss_size  = be32toh(xhdr->bss_size);
        !           220:    DEBUG(1, "base=$%x exec=$%x (text=$%x data=$%x bss=$%x)",
        !           221:        base_addr, exec_addr, text_size, data_size, bss_size);
        !           222: 
        !           223:    uint32 reloc_size = be32toh(xhdr->reloc_size);
        !           224: 
        !           225:    uint32 load_addr = LOAD_ADDR;
        !           226:    uint32 load_size = text_size + data_size;
        !           227:    last_addr = load_addr + load_size + bss_size;
        !           228: 
        !           229:    if (load_addr < pgsize) {
        !           230:        for (int i = 0; i < load_size; i++) {
        !           231:            writemem1(load_addr + i, file[sizeof(XFileHeader) + i]);
        !           232:        }
        !           233:    } else {
        !           234:        memcpy((void *)load_addr, &file[sizeof(XFileHeader)], load_size);
        !           235:    }
        !           236: 
        !           237:    // 再配置テーブルの file での位置。
        !           238:    uint32 reloc_pos = sizeof(XFileHeader) + load_size;
        !           239: 
        !           240:    // 再配置。
        !           241:    uint32 offset = load_addr - base_addr;
        !           242:    uint32 reloc_end = reloc_pos + reloc_size;
        !           243:    uint32 A = load_addr;
        !           244:    uint32 B = base_addr;
        !           245:    uint32 C = A - B;
        !           246:    while (reloc_pos < reloc_end) {
        !           247:        uint32 D;
        !           248:        D = be16toh(*(const uint16 *)&file[reloc_pos]);
        !           249:        DEBUG(2, "D=%x", D);
        !           250:        reloc_pos += 2;
        !           251:        if (D == 1) {
        !           252:            D = be32toh(*(const uint32 *)&file[reloc_pos]);
        !           253:            DEBUG(2, " odd, D=%x", D);
        !           254:            reloc_pos += 4;
        !           255:        }
        !           256:        if ((D & 1) == 0) {
        !           257:            A += D;
        !           258:            uint32 old = readmem4(A);
        !           259:            writemem4(A, old + C);
        !           260:            DEBUG(2, " Write_L A=%x, old=%x new=%x", A, old, old + C);
        !           261:        } else {
        !           262:            A += D - 1;
        !           263:            uint32 old = readmem2(A);
        !           264:            writemem2(A, old + C);
        !           265:            DEBUG(2, " Write_W A=%x, old=%x new=%x", A, old, old + C);
        !           266:        }
        !           267:    }
        !           268:    munmap(file, st.st_size);
        !           269:    close(fd);
        !           270: 
        !           271:    exec_addr += offset;
        !           272:    DEBUG(1, ".x format, base_addr=%08x, exec_addr=%08x", base_addr, exec_addr);
        !           273:    return exec_addr;
        !           274: }
        !           275: 
        !           276: // .R ファイルを読み込む。
        !           277: static uint32
        !           278: loadfileR()
        !           279: {
        !           280:    struct stat st;
        !           281:    int fd;
        !           282: 
        !           283:    fd = open(filename, O_RDONLY);
        !           284:    if (fd < 0) {
        !           285:        err(1, "%s", filename);
        !           286:    }
        !           287: 
        !           288:    if (fstat(fd, &st) < 0) {
        !           289:        err(1, "%s: stat failed", filename);
        !           290:    }
        !           291:    DEBUG(1, "loading %s %u bytes", filename, (uint)st.st_size);
        !           292: 
        !           293:    // XXX TODO
        !           294:    uint32 load_addr = LOAD_ADDR;
        !           295:    int n = read(fd, mem + load_addr, st.st_size);
        !           296:    if (n < 0) {
        !           297:        err(1, "%s", filename);
        !           298:    }
        !           299:    if (n < st.st_size) {
        !           300:        errx(1, "%s: read too short", filename);
        !           301:    }
        !           302:    close(fd);
        !           303: 
        !           304:    DEBUG(1, ".r format, exec_addr=%08x", load_addr);
        !           305:    return load_addr;
        !           306: }
        !           307: 
        !           308: uint32
        !           309: readmem1(uint32 addr)
        !           310: {
        !           311:    if (addr < pgsize) {
        !           312:        return page0[addr];
        !           313:    } else {
        !           314:        return mem[addr - pgsize];
        !           315:    }
        !           316: }
        !           317: 
        !           318: uint32
        !           319: readmem2(uint32 addr)
        !           320: {
        !           321:    uint32 data = (readmem1(addr) << 8) | readmem1(addr + 1);
        !           322:    return data;
        !           323: }
        !           324: 
        !           325: uint32
        !           326: readmem4(uint32 addr)
        !           327: {
        !           328:    uint32 data = (readmem2(addr) << 16) | readmem2(addr + 2);
        !           329:    return data;
        !           330: }
        !           331: 
        !           332: void
        !           333: writemem1(uint32 addr, uint32 data)
        !           334: {
        !           335:    if (addr < pgsize) {
        !           336:        page0[addr] = data;
        !           337:    } else {
        !           338:        mem[addr - pgsize] = data;
        !           339:    }
        !           340: }
        !           341: 
        !           342: void
        !           343: writemem2(uint32 addr, uint32 data)
        !           344: {
        !           345:    writemem1(addr,     data >> 8);
        !           346:    writemem1(addr + 1, data);
        !           347: }
        !           348: 
        !           349: void
        !           350: writemem4(uint32 addr, uint32 data)
        !           351: {
        !           352:    writemem2(addr,     data >> 16);
        !           353:    writemem2(addr + 2, data);
        !           354: }
        !           355: 
        !           356: // wait(2) status のダンプ表示。
        !           357: static void
        !           358: dumpwait(int status)
        !           359: {
        !           360:    printf("wait status=0x%x", status);
        !           361:    if (WIFEXITED(status)) {
        !           362:        printf(" EXITED status=0x%x\n", WEXITSTATUS(status));
        !           363:    }
        !           364:    if (WIFSIGNALED(status)) {
        !           365:        printf(" SIGNAL %d", WTERMSIG(status));
        !           366:        if (WCOREDUMP(status)) {
        !           367:            printf(" coredump");
        !           368:        }
        !           369:        printf("\n");
        !           370:    }
        !           371:    if (WIFSTOPPED(status)) {
        !           372:        int signo = WSTOPSIG(status);
        !           373:        printf(" STOPPED by %s\n", signame(signo));
        !           374:    }
        !           375: }
        !           376: 
        !           377: static void
        !           378: dumpreg(const struct reg *reg)
        !           379: {
        !           380:    printf("D0:%08x D4:%08x  A0:%08x A4:%08x  SR:%04x\n",
        !           381:        RegD(0), RegD(4), RegA(0), RegA(4), GetSR);
        !           382:    printf("D1:%08x D5:%08x  A1:%08x A5:%08x\n",
        !           383:        RegD(1), RegD(5), RegA(1), RegA(5));
        !           384:    printf("D2:%08x D6:%08x  A2:%08x A6:%08x\n",
        !           385:        RegD(2), RegD(6), RegA(2), RegA(6));
        !           386:    printf("D3:%08x D7:%08x  A3:%08x A7:%08x\n",
        !           387:        RegD(3), RegD(7), RegA(3), RegA(7));
        !           388: }
        !           389: 
        !           390: static int
        !           391: run(uint32 exec_addr)
        !           392: {
        !           393:    int fd[2];
        !           394:    int r;
        !           395:    pid_t pid;
        !           396:    uint32 addr;
        !           397: 
        !           398: #define Write2(d)  do {    \
        !           399:    writemem2(addr, (d));   \
        !           400:    addr += 2;  \
        !           401: } while (0)
        !           402: #define Write4(d)  do {    \
        !           403:    writemem4(addr, (d));   \
        !           404:    addr += 4;  \
        !           405: } while (0)
        !           406: 
        !           407:    // コマンドライン文字列を書き込む。LASCII 形式。
        !           408:    addr = 0xc001;
        !           409:    for (int i = 0; i < 255; i++) {
        !           410:        uint8 c = (uint8)human68k_arg[i];
        !           411:        writemem1(addr++, c);
        !           412:        if (c == '\0') {
        !           413:            writemem1(0xc000, i);
        !           414:            break;
        !           415:        }
        !           416:    }
        !           417: 
        !           418:    // PSP (Process Entry) を書き込む。
        !           419:    // PSP はロードアドレス-256 の位置でなければならないようだ。
        !           420:    uint32 psp_base = LOAD_ADDR - 0x100;
        !           421:    uint32 ram_size = 10 * 1024 * 1024;
        !           422:    uint32 sp_backup = 0x2000;
        !           423:    uint32 boot_addr = 0x2200;
        !           424:    addr = psp_base;
        !           425:    Write4(-1); // 1つ前のメモリ管理ポインタ
        !           426:    Write4(-1); // このメモリを確保したプロセスのメモリ管理ポインタ
        !           427:    Write4(ram_size - 4 + 1);   // このメモリブロックの終わり+1のアドレス
        !           428:    Write4(-1); // 次のメモリ管理ポインタ
        !           429: 
        !           430:    addr = psp_base + 0x20;
        !           431:    Write4(0xc000); // コマンドライン
        !           432: 
        !           433:    addr = boot_addr;
        !           434:    Write2(0x23cf);     // move.l   a7,sp_backup    // スタックを保存
        !           435:    Write4(sp_backup);
        !           436:    Write2(0x2e7c);     // move.l   psp_base,a7
        !           437:    Write4(psp_base);
        !           438:    Write2(0x207c);     // move.l   psp_base,a0
        !           439:    Write4(psp_base);
        !           440:    Write2(0x227c);     // move.l   last_addr,a1
        !           441:    Write4(last_addr);
        !           442:    Write2(0x247c);     // move.l   #$c000,a2
        !           443:    Write4(0xc000);
        !           444:    Write2(0x267c);     // move.l   #$e000,a3
        !           445:    Write4(0xe000);
        !           446:    Write2(0x287c);     // move.l   exec_addr,a4
        !           447:    Write4(exec_addr);
        !           448:    Write2(0x2c49);     // move.l   a1,a6
        !           449:    Write2(0x4eb9);     // jsr.l    exec_addr
        !           450:    Write4(exec_addr);
        !           451:    ret_addr = addr;
        !           452:    Write2(0x2e79);     // movea.l  sp_backup,a7    // スタックを戻して
        !           453:    Write4(sp_backup);
        !           454:    Write2(0x4e75);     // rts
        !           455: 
        !           456:    // READY 通知用パイプ。
        !           457:    if (pipe2(fd, O_NOSIGPIPE) < 0) {
        !           458:        err(1, "pipe");
        !           459:    }
        !           460: 
        !           461:    pid = fork();
        !           462:    if (pid < 0) {
        !           463:        err(1, "fork");
        !           464:    }
        !           465:    if (pid == 0) {
        !           466:        /* child */
        !           467: 
        !           468:        // 親の準備が出来るのを待つ。
        !           469:        char dummy[1];
        !           470:        if (read(fd[0], dummy, 1) < 0) {
        !           471:            err(1, "child: read failed");
        !           472:        }
        !           473: 
        !           474:        func_t p = (func_t)boot_addr;
        !           475:        r = p();
        !           476:        exit(r);
        !           477:    } else {
        !           478:        /* parent */
        !           479:        int status;
        !           480:        uint32 nextpc;
        !           481: 
        !           482:        DEBUG(1, "child pid=%u", pid);
        !           483: 
        !           484:        if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) {
        !           485:            err(1, "ptrace(PT_ATTACH)");
        !           486:        }
        !           487: 
        !           488:        // nextpc==1 は STOP した直後から再開、の意。
        !           489:        nextpc = 1;
        !           490: 
        !           491:        for (;;) {
        !           492:            r = wait(&status);
        !           493:            if (opt_debug >= 2) {
        !           494:                dumpwait(status);
        !           495:            }
        !           496:            if (WIFEXITED(status)) {
        !           497:                break;
        !           498:            }
        !           499: 
        !           500:            if (WIFSTOPPED(status)) {
        !           501:                struct reg regbuf;
        !           502:                struct reg *reg = &regbuf;
        !           503: 
        !           504:                if (ptrace(PT_GETREGS, pid, reg, 0) < 0) {
        !           505:                    err(1, "ptrace(PT_GETREGS)");
        !           506:                }
        !           507: 
        !           508:                int signo = WSTOPSIG(status);
        !           509: 
        !           510:                // PT_ATTACH が効くと SIGSTOP が来る。
        !           511:                if (signo == SIGSTOP) {
        !           512:                    // 準備が出来たので通知 (同期)。
        !           513:                    write(fd[1], "", 1);
        !           514:                    DEBUG(1, "STOP -> Continue");
        !           515:                } else if (signo == SIGILL || signo == SIGSEGV) {
        !           516:                    // 特権違反命令や未実装命令は SIGILL、
        !           517:                    // メモリアクセス違反は SIGSEGV が飛んでくるが、
        !           518:                    // どちらも命令コードを調べて再実行するところは同じ。
        !           519:                    uint32 inst32;
        !           520:                    errno = 0;
        !           521:                    inst32 = ptrace(PT_READ_I, pid, (void *)RegPC, 0);
        !           522:                    if (errno != 0) {
        !           523:                        err(1, "ptrace(PT_READ_I)");
        !           524:                    }
        !           525:                    if (opt_debug >= 2) {
        !           526:                        dumpreg(reg);
        !           527:                    }
        !           528:                    DEBUG(2, "pc=%08x inst32=%08x", RegPC, inst32);
        !           529:                    uint16 inst = inst32 >> 16;
        !           530: 
        !           531:                    if ((inst & 0xff00) == 0xff00) {
        !           532:                        r = doscall(pid, (inst & 0xff), reg);
        !           533:                        if (r == 1) {
        !           534:                            nextpc = ret_addr;
        !           535:                            goto next;
        !           536:                        }
        !           537:                        nextpc = RegPC + 2;
        !           538:                    } else {
        !           539:                        nextpc = exec_op(pid, reg, signo, inst);
        !           540:                        if (nextpc == (uint32)-1) {
        !           541:                            break;
        !           542:                        }
        !           543:                    }
        !           544: 
        !           545:                } else if (signo == SIGTRAP || signo == SIGFPE) {
        !           546:                    // TRAP15 は SIGTRAP、CHK* 命令やゼロ除算は SIGFPE、と
        !           547:                    // 本来別のシグナルが飛んで来るが
        !           548:                    // どちらも同じ形式で処理できるのでまとめてある。
        !           549:                    struct ptrace_siginfo psi;
        !           550:                    if (ptrace(PT_GET_SIGINFO, pid, &psi, sizeof(psi)) < 0) {
        !           551:                        err(1, "ptrace(PT_GET_SIGINFO)");
        !           552:                    }
        !           553:                    if (signo == SIGTRAP
        !           554:                     && psi.psi_siginfo.si_code == TRAP_CHLD) {
        !           555:                        // 子プロセス起動時にこちらが来る場合がある。
        !           556:                        // see kern_sig.c eventswitch()
        !           557:                        DEBUG(1, "TRAP_CHLD");
        !           558:                        goto next;
        !           559:                    }
        !           560:                    switch (psi.psi_siginfo.si_trap) {
        !           561:                     case T_ZERODIV:
        !           562:                        TRACE(RegPC, "previous op issued T_ZERODIV");
        !           563:                        nextpc = exception_format2(reg, 5);
        !           564:                        break;
        !           565:                     case T_CHKINST:
        !           566:                        TRACE(RegPC, "previous op issued T_CHKINST");
        !           567:                        nextpc = exception_format2(reg, 6);
        !           568:                        break;
        !           569:                     case T_TRAPVINST:
        !           570:                        TRACE(RegPC, "previous op issued T_TRAPVINST");
        !           571:                        nextpc = exception_format2(reg, 7);
        !           572:                        break;
        !           573:                     case T_TRAP15:
        !           574:                        iocscall(pid, reg);
        !           575:                        // nextpc は更新されている。
        !           576:                        break;
        !           577:                     default:
        !           578:                        errx(1, "%06x: Not implemented si_trap %d",
        !           579:                            RegPC, psi.psi_siginfo.si_trap);
        !           580:                    }
        !           581: 
        !           582:                } else {
        !           583:                    errx(1, "%06x: Unknown signal %d", RegPC, signo);
        !           584:                }
        !           585: 
        !           586:  next:
        !           587:                if (ptrace(PT_SETREGS, pid, reg, 0) < 0) {
        !           588:                    err(1, "ptrace(PT_SETREGS)");
        !           589:                }
        !           590: 
        !           591:                // 実行を再開し、次に何か起きるまで待つ。
        !           592:                if (ptrace(PT_CONTINUE, pid, (void *)nextpc, 0) < 0) {
        !           593:                    err(1, "PT_CONTINUE");
        !           594:                }
        !           595:                nextpc = 1;
        !           596:            }
        !           597:        }
        !           598:    }
        !           599: 
        !           600:    kill(pid, SIGKILL);
        !           601:    return 0;
        !           602: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.