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

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

unix.superglobalmegacorp.com

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