Annotation of qemu/roms/openbios/libopenbios/elf_load.c, revision 1.1

1.1     ! root        1: /* ELF Boot loader
        !             2:  * As we have seek, this implementation can be straightforward.
        !             3:  * 2003-07 by SONE Takeshi
        !             4:  */
        !             5: 
        !             6: #include "config.h"
        !             7: #include "kernel/kernel.h"
        !             8: #include "libc/diskio.h"
        !             9: #include "arch/common/elf_boot.h"
        !            10: #include "libopenbios/elf_load.h"
        !            11: #include "libopenbios/sys_info.h"
        !            12: #include "libopenbios/ipchecksum.h"
        !            13: #include "libopenbios/bindings.h"
        !            14: #include "libopenbios/ofmem.h"
        !            15: #define printf printk
        !            16: #define debug printk
        !            17: 
        !            18: #define DEBUG          0
        !            19: 
        !            20: #define MAX_HEADERS    0x20
        !            21: #define BS             0x100   /* smallest step used when looking for the ELF header */
        !            22: 
        !            23: #ifdef CONFIG_PPC
        !            24: extern void             flush_icache_range( char *start, char *stop );
        !            25: #endif
        !            26: 
        !            27: /* FreeBSD and possibly others mask the high 8 bits */
        !            28: #define addr_fixup(addr) ((addr) & 0x00ffffff)
        !            29: 
        !            30: static char *image_name, *image_version;
        !            31: static int fd;
        !            32: 
        !            33: /* Note: avoid name collision with platforms which have their own version of calloc() */
        !            34: static void *ob_calloc(size_t nmemb, size_t size)
        !            35: {
        !            36:     size_t alloc_size = nmemb * size;
        !            37:     void *mem;
        !            38: 
        !            39:     if (alloc_size < nmemb || alloc_size < size) {
        !            40:         printf("calloc overflow: %u, %u\n", nmemb, size);
        !            41:         return NULL;
        !            42:     }
        !            43: 
        !            44:     mem = malloc(alloc_size);
        !            45:     memset(mem, 0, alloc_size);
        !            46: 
        !            47:     return mem;
        !            48: }
        !            49: 
        !            50: static int check_mem_ranges(struct sys_info *info,
        !            51:        Elf_phdr *phdr, int phnum)
        !            52: {
        !            53:     int i, j;
        !            54:     unsigned long start, end;
        !            55:     unsigned long prog_start, prog_end;
        !            56:     struct memrange *mem;
        !            57: 
        !            58:     prog_start = virt_to_phys(&_start);
        !            59:     prog_end = virt_to_phys(&_end);
        !            60: 
        !            61:     for (i = 0; i < phnum; i++) {
        !            62:        if (phdr[i].p_type != PT_LOAD)
        !            63:            continue;
        !            64:        start = addr_fixup(phdr[i].p_paddr);
        !            65:        end = start + phdr[i].p_memsz;
        !            66:        if (start < prog_start && end > prog_start)
        !            67:            goto conflict;
        !            68:        if (start < prog_end && end > prog_end)
        !            69:            goto conflict;
        !            70:        mem=info->memrange;
        !            71:        for (j = 0; j < info->n_memranges; j++) {
        !            72:            if (mem[j].base <= start && mem[j].base + mem[j].size >= end)
        !            73:                break;
        !            74:        }
        !            75:        if (j >= info->n_memranges)
        !            76:            goto badseg;
        !            77:     }
        !            78:     return 1;
        !            79: 
        !            80: conflict:
        !            81:     printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
        !            82: 
        !            83: badseg:
        !            84:     printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1);
        !            85:     return 0;
        !            86: }
        !            87: 
        !            88: static unsigned long process_image_notes(Elf_phdr *phdr, int phnum,
        !            89:                                          unsigned short *sum_ptr,
        !            90:                                          unsigned int offset)
        !            91: {
        !            92:     int i;
        !            93:     char *buf = NULL;
        !            94:     int retval = 0;
        !            95:     unsigned long addr, end;
        !            96:     Elf_Nhdr *nhdr;
        !            97:     const char *name;
        !            98:     void *desc;
        !            99: 
        !           100:     for (i = 0; i < phnum; i++) {
        !           101:        if (phdr[i].p_type != PT_NOTE)
        !           102:            continue;
        !           103:        buf = malloc(phdr[i].p_filesz);
        !           104:        seek_io(fd, offset + phdr[i].p_offset);
        !           105:        if ((size_t)read_io(fd, buf, phdr[i].p_filesz) != phdr[i].p_filesz) {
        !           106:            printf("Can't read note segment\n");
        !           107:            goto out;
        !           108:        }
        !           109:        addr = (unsigned long) buf;
        !           110:        end = addr + phdr[i].p_filesz;
        !           111:        while (addr < end) {
        !           112:            nhdr = (Elf_Nhdr *) addr;
        !           113:            addr += sizeof(Elf_Nhdr);
        !           114:            name = (const char *) addr;
        !           115:            addr += (nhdr->n_namesz+3) & ~3;
        !           116:            desc = (void *) addr;
        !           117:            addr += (nhdr->n_descsz+3) & ~3;
        !           118: 
        !           119:            if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT)
        !           120:                    && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) {
        !           121:                if (nhdr->n_type == EIN_PROGRAM_NAME) {
        !           122:                    image_name = ob_calloc(1, nhdr->n_descsz + 1);
        !           123:                    memcpy(image_name, desc, nhdr->n_descsz);
        !           124:                }
        !           125:                if (nhdr->n_type == EIN_PROGRAM_VERSION) {
        !           126:                    image_version = ob_calloc(1, nhdr->n_descsz + 1);
        !           127:                    memcpy(image_version, desc, nhdr->n_descsz);
        !           128:                }
        !           129:                if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) {
        !           130:                    *sum_ptr = *(unsigned short *) desc;
        !           131:                    debug("Image checksum: %#04x\n", *sum_ptr);
        !           132:                    /* Where in the file */
        !           133:                    retval = phdr[i].p_offset
        !           134:                        + (unsigned long) desc - (unsigned long) buf;
        !           135:                }
        !           136:            }
        !           137:        }
        !           138:     }
        !           139: out:
        !           140:     close_io(fd);
        !           141:     if (buf)
        !           142:        free(buf);
        !           143:     return retval;
        !           144: }
        !           145: 
        !           146: static int load_segments(Elf_phdr *phdr, int phnum,
        !           147:                          unsigned long checksum_offset,
        !           148:                          unsigned int offset, unsigned long *bytes)
        !           149: {
        !           150:     //unsigned int start_time, time;
        !           151:     int i;
        !           152: 
        !           153:     *bytes = 0;
        !           154:     // start_time = currticks();
        !           155:     for (i = 0; i < phnum; i++) {
        !           156:        if (phdr[i].p_type != PT_LOAD)
        !           157:            continue;
        !           158:        debug("segment %d addr:" FMT_elf " file:" FMT_elf " mem:" FMT_elf " ",
        !           159:               i, addr_fixup(phdr[i].p_paddr), phdr[i].p_filesz, phdr[i].p_memsz);
        !           160:        seek_io(fd, offset + phdr[i].p_offset);
        !           161:        debug("loading... ");
        !           162:        if ((size_t)read_io(fd, phys_to_virt(addr_fixup(phdr[i].p_paddr)), phdr[i].p_filesz)
        !           163:                != phdr[i].p_filesz) {
        !           164:            printf("Can't read program segment %d\n", i);
        !           165:            return 0;
        !           166:        }
        !           167:        bytes += phdr[i].p_filesz;
        !           168:        debug("clearing... ");
        !           169:        memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + phdr[i].p_filesz), 0,
        !           170:                phdr[i].p_memsz - phdr[i].p_filesz);
        !           171:        if (phdr[i].p_offset <= checksum_offset
        !           172:                && phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) {
        !           173:            debug("clearing checksum... ");
        !           174:            memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + checksum_offset
        !           175:                        - phdr[i].p_offset), 0, 2);
        !           176:        }
        !           177:        debug("ok\n");
        !           178: 
        !           179:     }
        !           180:     // time = currticks() - start_time;
        !           181:     //debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time,
        !           182:     //     time? bytes/time : 0);
        !           183:     debug("Loaded %lu bytes \n", *bytes);
        !           184: 
        !           185:     return 1;
        !           186: }
        !           187: 
        !           188: static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum,
        !           189:        unsigned short image_sum)
        !           190: {
        !           191:     unsigned short sum, part_sum;
        !           192:     unsigned long offset;
        !           193:     int i;
        !           194: 
        !           195:     sum = 0;
        !           196:     offset = 0;
        !           197: 
        !           198:     part_sum = ipchksum(ehdr, sizeof *ehdr);
        !           199:     sum = add_ipchksums(offset, sum, part_sum);
        !           200:     offset += sizeof *ehdr;
        !           201: 
        !           202:     part_sum = ipchksum(phdr, phnum * sizeof(*phdr));
        !           203:     sum = add_ipchksums(offset, sum, part_sum);
        !           204:     offset += phnum * sizeof(*phdr);
        !           205: 
        !           206:     for (i = 0; i < phnum; i++) {
        !           207:        if (phdr[i].p_type != PT_LOAD)
        !           208:            continue;
        !           209:        part_sum = ipchksum(phys_to_virt(addr_fixup(phdr[i].p_paddr)), phdr[i].p_memsz);
        !           210:        sum = add_ipchksums(offset, sum, part_sum);
        !           211:        offset += phdr[i].p_memsz;
        !           212:     }
        !           213: 
        !           214:     if (sum != image_sum) {
        !           215:        printf("Verify FAILED (image:%#04x vs computed:%#04x)\n",
        !           216:                image_sum, sum);
        !           217:        return 0;
        !           218:     }
        !           219:     return 1;
        !           220: }
        !           221: 
        !           222: static inline unsigned padded(unsigned s)
        !           223: {
        !           224:     return (s + 3) & ~3;
        !           225: }
        !           226: 
        !           227: static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name,
        !           228:        unsigned type, const char *desc, unsigned descsz)
        !           229: {
        !           230:     Elf_Nhdr nhdr;
        !           231:     unsigned ent_size, new_size, pad;
        !           232:     char *addr;
        !           233: 
        !           234:     if (!bhdr)
        !           235:        return NULL;
        !           236: 
        !           237:     nhdr.n_namesz = name? strlen(name)+1 : 0;
        !           238:     nhdr.n_descsz = descsz;
        !           239:     nhdr.n_type = type;
        !           240:     ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz);
        !           241:     if (bhdr->b_size + ent_size > 0xffff) {
        !           242:        printf("Boot notes too big\n");
        !           243:        free(bhdr);
        !           244:        return NULL;
        !           245:     }
        !           246:     if (bhdr->b_size + ent_size > bhdr->b_checksum) {
        !           247:        do {
        !           248:            new_size = bhdr->b_checksum * 2;
        !           249:        } while (new_size < bhdr->b_size + ent_size);
        !           250:        if (new_size > 0xffff)
        !           251:            new_size = 0xffff;
        !           252:        debug("expanding boot note size to %u\n", new_size);
        !           253: #ifdef HAVE_REALLOC
        !           254:        bhdr = realloc(bhdr, new_size);
        !           255:        bhdr->b_checksum = new_size;
        !           256: #else
        !           257:        printf("Boot notes too big\n");
        !           258:        free(bhdr);
        !           259:        return NULL;
        !           260: #endif
        !           261:     }
        !           262: 
        !           263:     addr = (char *) bhdr;
        !           264:     addr += bhdr->b_size;
        !           265:     memcpy(addr, &nhdr, sizeof(nhdr));
        !           266:     addr += sizeof(nhdr);
        !           267: 
        !           268:     if (name && nhdr.n_namesz) {
        !           269:         memcpy(addr, name, nhdr.n_namesz);
        !           270:         addr += nhdr.n_namesz;
        !           271:         pad = padded(nhdr.n_namesz) - nhdr.n_namesz;
        !           272:         memset(addr, 0, pad);
        !           273:         addr += pad;
        !           274:     }
        !           275: 
        !           276:     memcpy(addr, desc, nhdr.n_descsz);
        !           277:     addr += nhdr.n_descsz;
        !           278:     pad = padded(nhdr.n_descsz) - nhdr.n_descsz;
        !           279:     memset(addr, 0, pad);
        !           280: 
        !           281:     bhdr->b_size += ent_size;
        !           282:     bhdr->b_records++;
        !           283:     return bhdr;
        !           284: }
        !           285: 
        !           286: static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name,
        !           287:        unsigned type, const char *desc)
        !           288: {
        !           289:     return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1);
        !           290: }
        !           291: 
        !           292: static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline)
        !           293: {
        !           294:     Elf_Bhdr *bhdr;
        !           295: 
        !           296:     bhdr = malloc(256);
        !           297:     bhdr->b_signature = ELF_BHDR_MAGIC;
        !           298:     bhdr->b_size = sizeof *bhdr;
        !           299:     bhdr->b_checksum = 256; /* XXX cache the current buffer size here */
        !           300:     bhdr->b_records = 0;
        !           301: 
        !           302:     if (info->firmware)
        !           303:        bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, info->firmware);
        !           304:     bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name);
        !           305:     bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version);
        !           306:     if (cmdline)
        !           307:        bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline);
        !           308:     if (!bhdr)
        !           309:        return bhdr;
        !           310:     bhdr->b_checksum = 0;
        !           311:     bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size);
        !           312:     return bhdr;
        !           313: }
        !           314: 
        !           315: int
        !           316: is_elf(Elf_ehdr *ehdr)
        !           317: {
        !           318:     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
        !           319:         && ehdr->e_ident[EI_MAG1] == ELFMAG1
        !           320:         && ehdr->e_ident[EI_MAG2] == ELFMAG2
        !           321:         && ehdr->e_ident[EI_MAG3] == ELFMAG3
        !           322:         && ehdr->e_ident[EI_CLASS] == ARCH_ELF_CLASS
        !           323:         && ehdr->e_ident[EI_DATA] == ARCH_ELF_DATA
        !           324:         && ehdr->e_ident[EI_VERSION] == EV_CURRENT
        !           325:         && ehdr->e_type == ET_EXEC
        !           326:         && ARCH_ELF_MACHINE_OK(ehdr->e_machine)
        !           327:         && ehdr->e_version == EV_CURRENT
        !           328:         && ehdr->e_phentsize == sizeof(Elf_phdr));
        !           329: }
        !           330: 
        !           331: int
        !           332: find_elf(Elf_ehdr *ehdr)
        !           333: {
        !           334:    int offset;
        !           335: 
        !           336:    for (offset = 0; offset < MAX_HEADERS * BS; offset += BS) {
        !           337:         if ((size_t)read_io(fd, ehdr, sizeof ehdr) != sizeof ehdr) {
        !           338:             debug("Can't read ELF header\n");
        !           339:             return 0;
        !           340:         }
        !           341: 
        !           342:         if (is_elf(ehdr)) {
        !           343:             debug("Found ELF header at offset %d\n", offset);
        !           344:            return offset;
        !           345:         }
        !           346: 
        !           347:         seek_io(fd, offset);
        !           348:     }
        !           349: 
        !           350:     debug("Not a bootable ELF image\n");
        !           351:     return 0;
        !           352: }
        !           353: 
        !           354: Elf_phdr *
        !           355: elf_readhdrs(int offset, Elf_ehdr *ehdr)
        !           356: {
        !           357:     unsigned long phdr_size;
        !           358:     Elf_phdr *phdr;
        !           359: 
        !           360:     phdr_size = ehdr->e_phnum * sizeof(Elf_phdr);
        !           361:     phdr = malloc(phdr_size);
        !           362:     seek_io(fd, offset + ehdr->e_phoff);
        !           363:     if ((size_t)read_io(fd, phdr, phdr_size) != phdr_size) {
        !           364:        printf("Can't read program header\n");
        !           365:        return NULL;
        !           366:     }
        !           367: 
        !           368:     return phdr;
        !           369: }
        !           370: 
        !           371: int 
        !           372: elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_notes)
        !           373: {
        !           374:     Elf_ehdr ehdr;
        !           375:     Elf_phdr *phdr = NULL;
        !           376:     unsigned long checksum_offset, file_size;
        !           377:     unsigned short checksum = 0;
        !           378:     int retval = -1;
        !           379:     unsigned int offset;
        !           380: 
        !           381:     image_name = image_version = NULL;
        !           382: 
        !           383:     /* Mark the saved-program-state as invalid */
        !           384:     feval("0 state-valid !");
        !           385: 
        !           386:     fd = open_ih(dev);
        !           387:     if (fd == -1) {
        !           388:        goto out;
        !           389:     }
        !           390: 
        !           391:     offset = find_elf(&ehdr);
        !           392:     if (!offset) {
        !           393:        retval = LOADER_NOT_SUPPORT;
        !           394:         goto out;
        !           395:     }
        !           396: 
        !           397: #if DEBUG
        !           398:        printk("ELF header:\n");
        !           399:        printk(" ehdr.e_type    = %d\n", (int)ehdr.e_type);
        !           400:        printk(" ehdr.e_machine = %d\n", (int)ehdr.e_machine);
        !           401:        printk(" ehdr.e_version = %d\n", (int)ehdr.e_version);
        !           402:        printk(" ehdr.e_entry   = 0x%08x\n", (int)ehdr.e_entry);
        !           403:        printk(" ehdr.e_phoff   = 0x%08x\n", (int)ehdr.e_phoff);
        !           404:        printk(" ehdr.e_shoff   = 0x%08x\n", (int)ehdr.e_shoff);
        !           405:        printk(" ehdr.e_flags   = %d\n", (int)ehdr.e_flags);
        !           406:        printk(" ehdr.e_ehsize  = 0x%08x\n", (int)ehdr.e_ehsize);
        !           407:        printk(" ehdr.e_phentsize = 0x%08x\n", (int)ehdr.e_phentsize);
        !           408:        printk(" ehdr.e_phnum   = %d\n", (int)ehdr.e_phnum);
        !           409: #endif
        !           410: 
        !           411:     if (ehdr.e_phnum > MAX_HEADERS) {
        !           412:         printk ("elfload: too many program headers (MAX_HEADERS)\n");
        !           413:         retval = 0;
        !           414:        goto out;
        !           415:     }
        !           416: 
        !           417:     phdr = elf_readhdrs(offset, &ehdr);
        !           418:     if (!phdr)
        !           419:         goto out;
        !           420: 
        !           421:     if (!check_mem_ranges(info, phdr, ehdr.e_phnum))
        !           422:        goto out;
        !           423: 
        !           424:     checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum, offset);
        !           425: 
        !           426:     printf("Loading %s", image_name ? image_name : "image");
        !           427:     if (image_version)
        !           428:        printf(" version %s", image_version);
        !           429:     printf("...\n");
        !           430: 
        !           431:     if (!load_segments(phdr, ehdr.e_phnum, checksum_offset, offset, &file_size))
        !           432:        goto out;
        !           433: 
        !           434:     if (checksum_offset) {
        !           435:        if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum))
        !           436:            goto out;
        !           437:     }
        !           438: 
        !           439:     /* If we are attempting an ELF boot image, we pass a non-NULL pointer
        !           440:        into boot_notes and mark the image as elf-boot rather than standard
        !           441:        ELF */
        !           442:     if (boot_notes) {
        !           443:         *boot_notes = (void *)virt_to_phys(build_boot_notes(info, cmdline));
        !           444:         feval("elf-boot saved-program-state >sps.file-type !");
        !           445:     } else {
        !           446:         feval("elf saved-program-state >sps.file-type !");
        !           447:     }
        !           448: 
        !           449:     //debug("current time: %lu\n", currticks());
        !           450: 
        !           451:     debug("entry point is " FMT_elf "\n", addr_fixup(ehdr.e_entry));
        !           452: 
        !           453:     // Initialise saved-program-state
        !           454:     PUSH(addr_fixup(ehdr.e_entry));
        !           455:     feval("saved-program-state >sps.entry !");
        !           456:     PUSH(file_size);
        !           457:     feval("saved-program-state >sps.file-size !");
        !           458: 
        !           459:     feval("-1 state-valid !");
        !           460: 
        !           461: out:
        !           462:     close_io(fd);
        !           463:     if (phdr)
        !           464:        free(phdr);
        !           465:     if (image_name)
        !           466:        free(image_name);
        !           467:     if (image_version)
        !           468:        free(image_version);
        !           469:     return retval;
        !           470: }
        !           471: 
        !           472: void 
        !           473: elf_init_program(void)
        !           474: {
        !           475:        char *base;
        !           476:        int i;
        !           477:        Elf_ehdr *ehdr;
        !           478:        Elf_phdr *phdr;
        !           479:        size_t size, total_size = 0;
        !           480:        char *addr;
        !           481:        uintptr_t tmp;
        !           482: 
        !           483:        /* TODO: manage ELF notes section */
        !           484:        feval("0 state-valid !");
        !           485:        feval("load-base");
        !           486:        base = (char*)cell2pointer(POP());
        !           487: 
        !           488:        ehdr = (Elf_ehdr *)base;
        !           489: 
        !           490:        if (!is_elf(ehdr)) {
        !           491:                debug("Not a valid ELF memory image\n");
        !           492:                return;
        !           493:        }
        !           494: 
        !           495:        phdr = (Elf_phdr *)(base + ehdr->e_phoff);
        !           496: 
        !           497:        for (i = 0; i < ehdr->e_phnum; i++) {
        !           498: 
        !           499: #if DEBUG
        !           500:                debug("filesz: %08lX memsz: %08lX p_offset: %08lX "
        !           501:                         "p_vaddr %08lX\n",
        !           502:                        (unsigned long)phdr[i].p_filesz, (unsigned long)phdr[i].p_memsz,
        !           503:                        (unsigned long)phdr[i].p_offset, (unsigned long)phdr[i].p_vaddr );
        !           504: #endif
        !           505: 
        !           506:                size = MIN(phdr[i].p_filesz, phdr[i].p_memsz);
        !           507:                if (!size)
        !           508:                        continue;
        !           509: #if !defined(CONFIG_SPARC32) && !defined(CONFIG_X86)
        !           510:                if( ofmem_claim( phdr[i].p_vaddr, phdr[i].p_memsz, 0 ) == -1 ) {
        !           511:                         printk("Ignoring failed claim for va %lx memsz %lx!\n",
        !           512:                                (unsigned long)phdr[i].p_vaddr,
        !           513:                                (unsigned long)phdr[i].p_memsz);
        !           514:                }
        !           515: #endif
        !           516:                /* Workaround for archs where sizeof(int) != pointer size */
        !           517:                tmp = phdr[i].p_vaddr;
        !           518:                addr = (char *)tmp;
        !           519: 
        !           520:                memcpy(addr, base + phdr[i].p_offset, size);
        !           521: 
        !           522:                total_size += size;
        !           523: 
        !           524: #ifdef CONFIG_PPC
        !           525:                flush_icache_range( addr, addr + size );
        !           526: #endif
        !           527:        }
        !           528: 
        !           529:        // Initialise saved-program-state
        !           530:        PUSH(ehdr->e_entry);
        !           531:        feval("saved-program-state >sps.entry !");
        !           532:        PUSH(total_size);
        !           533:        feval("saved-program-state >sps.file-size !");
        !           534:        feval("elf saved-program-state >sps.file-type !");
        !           535: 
        !           536:        feval("-1 state-valid !");
        !           537: }

unix.superglobalmegacorp.com

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