Repository: jart/blink Branch: master Commit: f006a4fc6f9b Files: 2096 Total size: 3.7 MB Directory structure: gitextract_w4mbx906/ ├── .clang-format ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ └── cygwin.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── blink/ │ ├── abort.c │ ├── address.c │ ├── alu.c │ ├── alu.h │ ├── alu1.c │ ├── alu2.c │ ├── alui.c │ ├── ancillary.c │ ├── ancillary.h │ ├── argv.c │ ├── assert.c │ ├── assert.h │ ├── atomic.h │ ├── bcd.c │ ├── bda.h │ ├── bios.c │ ├── biosrom.c │ ├── biosrom.h │ ├── bit.c │ ├── bitscan.c │ ├── bitscan.h │ ├── blink-shell.html │ ├── blink.1 │ ├── blink.c │ ├── blink.mk │ ├── blinkenlights.1 │ ├── blinkenlights.c │ ├── blinkenlights.h │ ├── bmi2.c │ ├── breakpoint.c │ ├── breakpoint.h │ ├── breg.c │ ├── buffer.c │ ├── buffer.h │ ├── builtin.h │ ├── bus.c │ ├── bus.h │ ├── case.h │ ├── cga.c │ ├── cga.h │ ├── checked.h │ ├── clmul.c │ ├── close.c │ ├── cmpxchg.c │ ├── commandv.c │ ├── compress.c │ ├── cp437.c │ ├── cpucount.c │ ├── cpuid.c │ ├── crc32.c │ ├── cvt.c │ ├── debug.c │ ├── debug.h │ ├── debug2.c │ ├── demangle.c │ ├── deps.c │ ├── describeflags.c │ ├── describeflags.h │ ├── describehosterrno.c │ ├── describeprot.c │ ├── describesignal.c │ ├── devfs.c │ ├── devfs.h │ ├── dis.c │ ├── dis.h │ ├── disarg.c │ ├── diself.c │ ├── disfree.c │ ├── disinst.c │ ├── disspec.c │ ├── divmul.c │ ├── dll.c │ ├── dll.h │ ├── doublenul.c │ ├── elf.c │ ├── elf.h │ ├── end.h │ ├── endian.h │ ├── endswith.c │ ├── errfd.c │ ├── errno.c │ ├── errno.h │ ├── fds.c │ ├── fds.h │ ├── flag.c │ ├── flag.h │ ├── flags.c │ ├── flags.h │ ├── formatint64.c │ ├── formatint64thousands.c │ ├── formatsize.c │ ├── fpu.c │ ├── fpu.h │ ├── fspath.c │ ├── fspath.h │ ├── fusion.c │ ├── getopt.c │ ├── hex.c │ ├── high.c │ ├── high.h │ ├── hostfs.c │ ├── hostfs.h │ ├── instruction.c │ ├── intrin.h │ ├── ioctl.c │ ├── ioports.c │ ├── iovs.c │ ├── iovs.h │ ├── jit.c │ ├── jit.h │ ├── jitflush.c │ ├── ldbl.c │ ├── ldbl.h │ ├── legacy.c │ ├── likely.h │ ├── limits.h │ ├── lines.c │ ├── lines.h │ ├── linux.h │ ├── loader.c │ ├── loader.h │ ├── log.c │ ├── log.h │ ├── logcpu.c │ ├── machine.c │ ├── machine.h │ ├── macros.h │ ├── magikarp.c │ ├── map.c │ ├── map.h │ ├── mda.c │ ├── mda.h │ ├── memccpy.c │ ├── memcpy.h │ ├── memory.c │ ├── memorymalloc.c │ ├── message.c │ ├── metal.c │ ├── mkfifo.c │ ├── mkfifoat.c │ ├── mmx.c │ ├── modrm.c │ ├── modrm.h │ ├── msr.h │ ├── name.c │ ├── ndelay.h │ ├── oneoff.c │ ├── op101.c │ ├── open.c │ ├── overlays.c │ ├── overlays.h │ ├── panel.c │ ├── panel.h │ ├── path.c │ ├── pipe.c │ ├── pml4t.c │ ├── pml4t.h │ ├── pml4tfmt.c │ ├── popcount.c │ ├── ppc.c │ ├── preadv.c │ ├── preadv.h │ ├── procfs.c │ ├── procfs.h │ ├── prog.c │ ├── pte32.c │ ├── pty.c │ ├── pty.h │ ├── pun.h │ ├── random.c │ ├── random.h │ ├── rde.h │ ├── rdrand.c │ ├── readansi.c │ ├── realpath.c │ ├── reset.c │ ├── signal.c │ ├── signal.h │ ├── sigwinch.h │ ├── smc.c │ ├── sse.c │ ├── sse.h │ ├── sse2.c │ ├── ssefloat.c │ ├── ssemov.c │ ├── stack.c │ ├── startdir.c │ ├── startswith.c │ ├── statfs.c │ ├── stats.c │ ├── stats.h │ ├── stats.inc │ ├── strace.c │ ├── strace.h │ ├── strchrnul.c │ ├── string.c │ ├── string.h │ ├── strwidth.c │ ├── strwidth.h │ ├── swap.h │ ├── syscall.c │ ├── syscall.h │ ├── sysinfo.c │ ├── tainted.c │ ├── thompike.h │ ├── thread.h │ ├── throw.c │ ├── time.c │ ├── time.h │ ├── timespec.c │ ├── timespec.h │ ├── tpenc.c │ ├── tsan.h │ ├── tunables.h │ ├── types.h │ ├── uart.h │ ├── uop.c │ ├── util.h │ ├── vasprintf.c │ ├── vfs.c │ ├── vfs.h │ ├── vigna.c │ ├── watch.c │ ├── watch.h │ ├── wcwidth.c │ ├── web.h │ ├── x86.c │ ├── x86.h │ ├── x86error.c │ ├── xadd.c │ ├── xchg.c │ ├── xlat.c │ ├── xlat.h │ ├── xmm.h │ ├── xmmtype.c │ ├── xmmtype.h │ └── xnu.c ├── build/ │ ├── bootstrap/ │ │ ├── make.com │ │ └── mkdeps.com │ ├── config.mk │ ├── htags │ ├── objdump │ └── rules.mk ├── config.h.in ├── configure ├── test/ │ ├── asm/ │ │ ├── README.md │ │ ├── add.S │ │ ├── adx.S │ │ ├── asm.mk │ │ ├── bzhi.S │ │ ├── cmc.S │ │ ├── cmov.S │ │ ├── cmp.S │ │ ├── cmpxchg.S │ │ ├── cmpxchg16b.S │ │ ├── enter.S │ │ ├── exit.S │ │ ├── lahf.S │ │ ├── lock.S │ │ ├── mac.inc │ │ ├── movi.S │ │ ├── movmskpd.S │ │ ├── movntdq.S │ │ ├── movsreg.S │ │ ├── movsxd.S │ │ ├── movz.S │ │ ├── mulx.S │ │ ├── nop.S │ │ ├── overflow.S │ │ ├── page.S │ │ ├── push.S │ │ ├── repmovsb.S │ │ ├── rol.S │ │ ├── rorx.S │ │ ├── setcc.S │ │ ├── shufpd.S │ │ ├── shx.S │ │ ├── ssemov.S │ │ ├── write.S │ │ └── xchg.S │ ├── blink/ │ │ ├── disinst_test.c │ │ ├── divmul_imul64_test.inc │ │ ├── divmul_mul64_test.inc │ │ ├── divmul_mul8_test.inc │ │ ├── divmul_test.c │ │ ├── ldbl_test.c │ │ ├── modrm_test.c │ │ ├── test.mk │ │ └── x86_test.c │ ├── flat/ │ │ ├── flat.S │ │ ├── flat.lds │ │ └── flat.mk │ ├── func/ │ │ ├── README.md │ │ ├── busted_test.c │ │ ├── cycle2_test.c │ │ ├── cycle_test.c │ │ ├── eintr_test.c │ │ ├── fstatat_at_empty_path.c │ │ ├── func.mk │ │ ├── futex_multiprocess_test.c │ │ ├── getrandom_test.c │ │ ├── largefile_test.c │ │ ├── lock_test.c │ │ ├── mem64_test.c │ │ ├── mmap_test.c │ │ ├── munmap_test.c │ │ ├── noexec2_test.c │ │ ├── noexec3_test.c │ │ ├── noexec_test.c │ │ ├── norestart_test.c │ │ ├── preadv_test.c │ │ ├── readonly_test.c │ │ ├── restart_test.c │ │ ├── robust_exit_test.c │ │ ├── robust_kill_test.c │ │ ├── select_timeout_test.c │ │ ├── shared_test.c │ │ ├── sigprocmask_test.c │ │ ├── smc1_test.c │ │ ├── smc2_test.c │ │ ├── smc3_test.c │ │ ├── socket_test.c │ │ ├── trap_cpuid_test.c │ │ ├── trap_rdtsc_test.c │ │ └── trap_test.c │ ├── metal/ │ │ ├── biosdisk.S │ │ ├── biostime.S │ │ ├── enter.S │ │ ├── gdt-idt-32.S │ │ ├── hello.S │ │ ├── int3.S │ │ ├── iret.S │ │ ├── lds-les.S │ │ ├── ljmp-lcall.S │ │ ├── mac.inc │ │ ├── metal.lds │ │ ├── metal.mk │ │ ├── pusha-popa.S │ │ ├── ssemov.S │ │ └── string.S │ ├── metalrom/ │ │ ├── hello.S │ │ ├── metalrom.lds │ │ └── metalrom.mk │ ├── test.h │ └── test.mk ├── third_party/ │ ├── .clang-format │ ├── coi-serviceworker/ │ │ ├── LICENSE │ │ ├── README.md │ │ └── coi-serviceworker.js │ ├── cosmo/ │ │ ├── 2/ │ │ │ ├── _timespec_test.com.dbg.gz.sha256 │ │ │ ├── _timespec_test.com.gz.sha256 │ │ │ ├── a64l_test.com.dbg.gz.sha256 │ │ │ ├── a64l_test.com.gz.sha256 │ │ │ ├── abort_test.com.dbg.gz.sha256 │ │ │ ├── abort_test.com.gz.sha256 │ │ │ ├── access_test.com.dbg.gz.sha256 │ │ │ ├── access_test.com.gz.sha256 │ │ │ ├── acos_test.com.dbg.gz.sha256 │ │ │ ├── acos_test.com.gz.sha256 │ │ │ ├── acosh_test.com.dbg.gz.sha256 │ │ │ ├── acosh_test.com.gz.sha256 │ │ │ ├── alaw_test.com.dbg.gz.sha256 │ │ │ ├── alaw_test.com.gz.sha256 │ │ │ ├── alu_test.com.dbg.gz.sha256 │ │ │ ├── alu_test.com.gz.sha256 │ │ │ ├── appendresourcereport_test.com.dbg.gz.sha256 │ │ │ ├── appendresourcereport_test.com.gz.sha256 │ │ │ ├── arch_prctl_test.com.dbg.gz.sha256 │ │ │ ├── arch_prctl_test.com.gz.sha256 │ │ │ ├── arena_test.com.dbg.gz.sha256 │ │ │ ├── arena_test.com.gz.sha256 │ │ │ ├── argon2_test.com.dbg.gz.sha256 │ │ │ ├── argon2_test.com.gz.sha256 │ │ │ ├── args_test.com.dbg.gz.sha256 │ │ │ ├── args_test.com.gz.sha256 │ │ │ ├── arraylist_test.com.dbg.gz.sha256 │ │ │ ├── arraylist_test.com.gz.sha256 │ │ │ ├── asan_test.com.dbg.gz.sha256 │ │ │ ├── asan_test.com.gz.sha256 │ │ │ ├── asin_test.com.dbg.gz.sha256 │ │ │ ├── asin_test.com.gz.sha256 │ │ │ ├── asinh_test.com.dbg.gz.sha256 │ │ │ ├── asinh_test.com.gz.sha256 │ │ │ ├── asmdown_test.com.dbg.gz.sha256 │ │ │ ├── asmdown_test.com.gz.sha256 │ │ │ ├── atan2_test.com.dbg.gz.sha256 │ │ │ ├── atan2_test.com.gz.sha256 │ │ │ ├── atan2l_test.com.dbg.gz.sha256 │ │ │ ├── atan2l_test.com.gz.sha256 │ │ │ ├── atan_test.com.dbg.gz.sha256 │ │ │ ├── atan_test.com.gz.sha256 │ │ │ ├── atanh_test.com.dbg.gz.sha256 │ │ │ ├── atanh_test.com.gz.sha256 │ │ │ ├── atanl_test.com.dbg.gz.sha256 │ │ │ ├── atanl_test.com.gz.sha256 │ │ │ ├── atoi_test.com.dbg.gz.sha256 │ │ │ ├── atoi_test.com.gz.sha256 │ │ │ ├── backtrace_test.com.dbg.gz.sha256 │ │ │ ├── backtrace_test.com.gz.sha256 │ │ │ ├── basename_test.com.dbg.gz.sha256 │ │ │ ├── basename_test.com.gz.sha256 │ │ │ ├── bextra_test.com.dbg.gz.sha256 │ │ │ ├── bextra_test.com.gz.sha256 │ │ │ ├── bilinearscale_test.com.dbg.gz.sha256 │ │ │ ├── bilinearscale_test.com.gz.sha256 │ │ │ ├── bisectcarleft_test.com.dbg.gz.sha256 │ │ │ ├── bisectcarleft_test.com.gz.sha256 │ │ │ ├── bitreverse_test.com.dbg.gz.sha256 │ │ │ ├── bitreverse_test.com.gz.sha256 │ │ │ ├── bitscan_test.com.dbg.gz.sha256 │ │ │ ├── bitscan_test.com.gz.sha256 │ │ │ ├── blake2_test.com.dbg.gz.sha256 │ │ │ ├── blake2_test.com.gz.sha256 │ │ │ ├── brk_test.com.dbg.gz.sha256 │ │ │ ├── brk_test.com.gz.sha256 │ │ │ ├── bsr_test.com.dbg.gz.sha256 │ │ │ ├── bsr_test.com.gz.sha256 │ │ │ ├── bsu_test.com.dbg.gz.sha256 │ │ │ ├── bsu_test.com.gz.sha256 │ │ │ ├── bzero_test.com.dbg.gz.sha256 │ │ │ ├── bzero_test.com.gz.sha256 │ │ │ ├── cas_test.com.dbg.gz.sha256 │ │ │ ├── cas_test.com.gz.sha256 │ │ │ ├── cbrt_test.com.dbg.gz.sha256 │ │ │ ├── cbrt_test.com.gz.sha256 │ │ │ ├── ceil_test.com.dbg.gz.sha256 │ │ │ ├── ceil_test.com.gz.sha256 │ │ │ ├── cescapec_test.com.dbg.gz.sha256 │ │ │ ├── cescapec_test.com.gz.sha256 │ │ │ ├── chdir_test.com.dbg.gz.sha256 │ │ │ ├── chdir_test.com.gz.sha256 │ │ │ ├── classifypath_test.com.dbg.gz.sha256 │ │ │ ├── classifypath_test.com.gz.sha256 │ │ │ ├── clock_getres_test.com.dbg.gz.sha256 │ │ │ ├── clock_getres_test.com.gz.sha256 │ │ │ ├── clock_gettime_test.com.dbg.gz.sha256 │ │ │ ├── clock_gettime_test.com.gz.sha256 │ │ │ ├── clock_nanosleep_test.com.dbg.gz.sha256 │ │ │ ├── clock_nanosleep_test.com.gz.sha256 │ │ │ ├── clone_test.com.dbg.gz.sha256 │ │ │ ├── clone_test.com.gz.sha256 │ │ │ ├── closefrom_test.com.dbg.gz.sha256 │ │ │ ├── closefrom_test.com.gz.sha256 │ │ │ ├── commandv_test.com.dbg.gz.sha256 │ │ │ ├── commandv_test.com.gz.sha256 │ │ │ ├── comparednsnames_test.com.dbg.gz.sha256 │ │ │ ├── comparednsnames_test.com.gz.sha256 │ │ │ ├── complex_test.com.dbg.gz.sha256 │ │ │ ├── complex_test.com.gz.sha256 │ │ │ ├── convoindex_test.com.dbg.gz.sha256 │ │ │ ├── convoindex_test.com.gz.sha256 │ │ │ ├── copy_file_range_test.com.dbg.gz.sha256 │ │ │ ├── copy_file_range_test.com.gz.sha256 │ │ │ ├── copysign_test.com.dbg.gz.sha256 │ │ │ ├── copysign_test.com.gz.sha256 │ │ │ ├── cos_test.com.dbg.gz.sha256 │ │ │ ├── cos_test.com.gz.sha256 │ │ │ ├── cosh_test.com.dbg.gz.sha256 │ │ │ ├── cosh_test.com.gz.sha256 │ │ │ ├── countbits_test.com.dbg.gz.sha256 │ │ │ ├── countbits_test.com.gz.sha256 │ │ │ ├── counter_test.com.dbg.gz.sha256 │ │ │ ├── counter_test.com.gz.sha256 │ │ │ ├── crc32_test.com.dbg.gz.sha256 │ │ │ ├── crc32_test.com.gz.sha256 │ │ │ ├── crc32c_test.com.dbg.gz.sha256 │ │ │ ├── crc32c_test.com.gz.sha256 │ │ │ ├── crc32z_test.com.dbg.gz.sha256 │ │ │ ├── crc32z_test.com.gz.sha256 │ │ │ ├── critbit0_test.com.dbg.gz.sha256 │ │ │ ├── critbit0_test.com.gz.sha256 │ │ │ ├── crypt_test.com.dbg.gz.sha256 │ │ │ ├── crypt_test.com.gz.sha256 │ │ │ ├── csqrt_test.com.dbg.gz.sha256 │ │ │ ├── csqrt_test.com.gz.sha256 │ │ │ ├── cv_test.com.dbg.gz.sha256 │ │ │ ├── cv_test.com.gz.sha256 │ │ │ ├── cv_wait_example_test.com.dbg.gz.sha256 │ │ │ ├── cv_wait_example_test.com.gz.sha256 │ │ │ ├── daemon_test.com.dbg.gz.sha256 │ │ │ ├── daemon_test.com.gz.sha256 │ │ │ ├── decodebase64_test.com.dbg.gz.sha256 │ │ │ ├── decodebase64_test.com.gz.sha256 │ │ │ ├── decodelatin1_test.com.dbg.gz.sha256 │ │ │ ├── decodelatin1_test.com.gz.sha256 │ │ │ ├── describeflags_test.com.dbg.gz.sha256 │ │ │ ├── describeflags_test.com.gz.sha256 │ │ │ ├── describegidlist_test.com.dbg.gz.sha256 │ │ │ ├── describegidlist_test.com.gz.sha256 │ │ │ ├── describesigset_test.com.dbg.gz.sha256 │ │ │ ├── describesigset_test.com.gz.sha256 │ │ │ ├── describesyn_test.com.dbg.gz.sha256 │ │ │ ├── describesyn_test.com.gz.sha256 │ │ │ ├── devrand_test.com.dbg.gz.sha256 │ │ │ ├── devrand_test.com.gz.sha256 │ │ │ ├── diagnose_syscall_test.com.dbg.gz.sha256 │ │ │ ├── diagnose_syscall_test.com.gz.sha256 │ │ │ ├── dirname_test.com.dbg.gz.sha256 │ │ │ ├── dirname_test.com.gz.sha256 │ │ │ ├── dirstream_test.com.dbg.gz.sha256 │ │ │ ├── dirstream_test.com.gz.sha256 │ │ │ ├── disinst_test.com.dbg.gz.sha256 │ │ │ ├── disinst_test.com.gz.sha256 │ │ │ ├── division_test.com.dbg.gz.sha256 │ │ │ ├── division_test.com.gz.sha256 │ │ │ ├── divmul_test.com.dbg.gz.sha256 │ │ │ ├── divmul_test.com.gz.sha256 │ │ │ ├── djbsort_test.com.dbg.gz.sha256 │ │ │ ├── djbsort_test.com.gz.sha256 │ │ │ ├── dll_test.com.dbg.gz.sha256 │ │ │ ├── dll_test.com.gz.sha256 │ │ │ ├── dnsheader_test.com.dbg.gz.sha256 │ │ │ ├── dnsheader_test.com.gz.sha256 │ │ │ ├── dnsquestion_test.com.dbg.gz.sha256 │ │ │ ├── dnsquestion_test.com.gz.sha256 │ │ │ ├── dos2errno_test.com.dbg.gz.sha256 │ │ │ ├── dos2errno_test.com.gz.sha256 │ │ │ ├── dumphexc_test.com.dbg.gz.sha256 │ │ │ ├── dumphexc_test.com.gz.sha256 │ │ │ ├── dup_test.com.dbg.gz.sha256 │ │ │ ├── dup_test.com.gz.sha256 │ │ │ ├── ecvt_test.com.dbg.gz.sha256 │ │ │ ├── ecvt_test.com.gz.sha256 │ │ │ ├── encodebase64_test.com.dbg.gz.sha256 │ │ │ ├── encodebase64_test.com.gz.sha256 │ │ │ ├── encodehttpheadervalue_test.com.dbg.gz.sha256 │ │ │ ├── encodehttpheadervalue_test.com.gz.sha256 │ │ │ ├── encodenf32_test.com.dbg.gz.sha256 │ │ │ ├── encodenf32_test.com.gz.sha256 │ │ │ ├── erf_test.com.dbg.gz.sha256 │ │ │ ├── erf_test.com.gz.sha256 │ │ │ ├── escapehtml_test.com.dbg.gz.sha256 │ │ │ ├── escapehtml_test.com.gz.sha256 │ │ │ ├── escapejsstringliteral_test.com.dbg.gz.sha256 │ │ │ ├── escapejsstringliteral_test.com.gz.sha256 │ │ │ ├── escapeurlparam_test.com.dbg.gz.sha256 │ │ │ ├── escapeurlparam_test.com.gz.sha256 │ │ │ ├── everest_test.com.dbg.gz.sha256 │ │ │ ├── everest_test.com.gz.sha256 │ │ │ ├── execve_test.com.dbg.gz.sha256 │ │ │ ├── execve_test.com.gz.sha256 │ │ │ ├── exit_test.com.dbg.gz.sha256 │ │ │ ├── exit_test.com.gz.sha256 │ │ │ ├── exp10_test.com.dbg.gz.sha256 │ │ │ ├── exp10_test.com.gz.sha256 │ │ │ ├── exp2_test.com.dbg.gz.sha256 │ │ │ ├── exp2_test.com.gz.sha256 │ │ │ ├── exp2l_test.com.dbg.gz.sha256 │ │ │ ├── exp2l_test.com.gz.sha256 │ │ │ ├── exp_test.com.dbg.gz.sha256 │ │ │ ├── exp_test.com.gz.sha256 │ │ │ ├── expm1_test.com.dbg.gz.sha256 │ │ │ ├── expm1_test.com.gz.sha256 │ │ │ ├── fabs_test.com.dbg.gz.sha256 │ │ │ ├── fabs_test.com.gz.sha256 │ │ │ ├── fcntl_test.com.dbg.gz.sha256 │ │ │ ├── fcntl_test.com.gz.sha256 │ │ │ ├── fexecve_test.com.dbg.gz.sha256 │ │ │ ├── fexecve_test.com.gz.sha256 │ │ │ ├── ffs_test.com.dbg.gz.sha256 │ │ │ ├── ffs_test.com.gz.sha256 │ │ │ ├── fgetln_test.com.dbg.gz.sha256 │ │ │ ├── fgetln_test.com.gz.sha256 │ │ │ ├── fgets_test.com.dbg.gz.sha256 │ │ │ ├── fgets_test.com.gz.sha256 │ │ │ ├── fgetwc_test.com.dbg.gz.sha256 │ │ │ ├── fgetwc_test.com.gz.sha256 │ │ │ ├── fileexists_test.com.dbg.gz.sha256 │ │ │ ├── fileexists_test.com.gz.sha256 │ │ │ ├── findcontenttype_test.com.dbg.gz.sha256 │ │ │ ├── findcontenttype_test.com.gz.sha256 │ │ │ ├── fingersyn_test.com.dbg.gz.sha256 │ │ │ ├── fingersyn_test.com.gz.sha256 │ │ │ ├── floor_test.com.dbg.gz.sha256 │ │ │ ├── floor_test.com.gz.sha256 │ │ │ ├── fmemopen_test.com.dbg.gz.sha256 │ │ │ ├── fmemopen_test.com.gz.sha256 │ │ │ ├── fmod_test.com.dbg.gz.sha256 │ │ │ ├── fmod_test.com.gz.sha256 │ │ │ ├── fmt_test.com.dbg.gz.sha256 │ │ │ ├── fmt_test.com.gz.sha256 │ │ │ ├── fork_test.com.dbg.gz.sha256 │ │ │ ├── fork_test.com.gz.sha256 │ │ │ ├── formatbinary64_test.com.dbg.gz.sha256 │ │ │ ├── formatbinary64_test.com.gz.sha256 │ │ │ ├── formatflex64_test.com.dbg.gz.sha256 │ │ │ ├── formatflex64_test.com.gz.sha256 │ │ │ ├── formathex64_test.com.dbg.gz.sha256 │ │ │ ├── formathex64_test.com.gz.sha256 │ │ │ ├── formathttpdatetime_test.com.dbg.gz.sha256 │ │ │ ├── formathttpdatetime_test.com.gz.sha256 │ │ │ ├── formatint32_test.com.dbg.gz.sha256 │ │ │ ├── formatint32_test.com.gz.sha256 │ │ │ ├── formatint64_test.com.dbg.gz.sha256 │ │ │ ├── formatint64_test.com.gz.sha256 │ │ │ ├── formatint64thousands_test.com.dbg.gz.sha256 │ │ │ ├── formatint64thousands_test.com.gz.sha256 │ │ │ ├── formatoctal32_test.com.dbg.gz.sha256 │ │ │ ├── formatoctal32_test.com.gz.sha256 │ │ │ ├── formatoctal64_test.com.dbg.gz.sha256 │ │ │ ├── formatoctal64_test.com.gz.sha256 │ │ │ ├── fputc_test.com.dbg.gz.sha256 │ │ │ ├── fputc_test.com.gz.sha256 │ │ │ ├── fputs_test.com.dbg.gz.sha256 │ │ │ ├── fputs_test.com.gz.sha256 │ │ │ ├── fread_test.com.dbg.gz.sha256 │ │ │ ├── fread_test.com.gz.sha256 │ │ │ ├── freopen_test.com.dbg.gz.sha256 │ │ │ ├── freopen_test.com.gz.sha256 │ │ │ ├── fseeko_test.com.dbg.gz.sha256 │ │ │ ├── fseeko_test.com.gz.sha256 │ │ │ ├── fsum_test.com.dbg.gz.sha256 │ │ │ ├── fsum_test.com.gz.sha256 │ │ │ ├── ftell_test.com.dbg.gz.sha256 │ │ │ ├── ftell_test.com.gz.sha256 │ │ │ ├── fun_test.com.dbg.gz.sha256 │ │ │ ├── fun_test.com.gz.sha256 │ │ │ ├── fwrite_test.com.dbg.gz.sha256 │ │ │ ├── fwrite_test.com.gz.sha256 │ │ │ ├── gamma_test.com.dbg.gz.sha256 │ │ │ ├── gamma_test.com.gz.sha256 │ │ │ ├── gclongjmp_test.com.dbg.gz.sha256 │ │ │ ├── gclongjmp_test.com.gz.sha256 │ │ │ ├── getargs_test.com.dbg.gz.sha256 │ │ │ ├── getargs_test.com.gz.sha256 │ │ │ ├── getciphersuite_test.com.dbg.gz.sha256 │ │ │ ├── getciphersuite_test.com.gz.sha256 │ │ │ ├── getcontext_test.com.dbg.gz.sha256 │ │ │ ├── getcontext_test.com.gz.sha256 │ │ │ ├── getcwd_test.com.dbg.gz.sha256 │ │ │ ├── getcwd_test.com.gz.sha256 │ │ │ ├── getdelim_test.com.dbg.gz.sha256 │ │ │ ├── getdelim_test.com.gz.sha256 │ │ │ ├── getdosargv_test.com.dbg.gz.sha256 │ │ │ ├── getdosargv_test.com.gz.sha256 │ │ │ ├── getdosenviron_test.com.dbg.gz.sha256 │ │ │ ├── getdosenviron_test.com.gz.sha256 │ │ │ ├── getentropy_test.com.dbg.gz.sha256 │ │ │ ├── getentropy_test.com.gz.sha256 │ │ │ ├── getenv_test.com.dbg.gz.sha256 │ │ │ ├── getenv_test.com.gz.sha256 │ │ │ ├── getgroups_test.com.dbg.gz.sha256 │ │ │ ├── getgroups_test.com.gz.sha256 │ │ │ ├── getintegercoefficients8_test.com.dbg.gz.sha256 │ │ │ ├── getintegercoefficients8_test.com.gz.sha256 │ │ │ ├── getintegercoefficients_test.com.dbg.gz.sha256 │ │ │ ├── getintegercoefficients_test.com.gz.sha256 │ │ │ ├── getitimer_test.com.dbg.gz.sha256 │ │ │ ├── getitimer_test.com.gz.sha256 │ │ │ ├── getpriority_test.com.dbg.gz.sha256 │ │ │ ├── getpriority_test.com.gz.sha256 │ │ │ ├── getrandom_test.com.dbg.gz.sha256 │ │ │ ├── getrandom_test.com.gz.sha256 │ │ │ ├── grow_test.com.dbg.gz.sha256 │ │ │ ├── grow_test.com.gz.sha256 │ │ │ ├── gz_test.com.dbg.gz.sha256 │ │ │ ├── gz_test.com.gz.sha256 │ │ │ ├── halfblit_test.com.dbg.gz.sha256 │ │ │ ├── halfblit_test.com.gz.sha256 │ │ │ ├── hascontrolcodes_test.com.dbg.gz.sha256 │ │ │ ├── hascontrolcodes_test.com.gz.sha256 │ │ │ ├── hexpcpy_test.com.dbg.gz.sha256 │ │ │ ├── hexpcpy_test.com.gz.sha256 │ │ │ ├── highwayhash64_test.com.dbg.gz.sha256 │ │ │ ├── highwayhash64_test.com.gz.sha256 │ │ │ ├── hypot_test.com.dbg.gz.sha256 │ │ │ ├── hypot_test.com.gz.sha256 │ │ │ ├── iconv_test.com.dbg.gz.sha256 │ │ │ ├── iconv_test.com.gz.sha256 │ │ │ ├── illumination_test.com.dbg.gz.sha256 │ │ │ ├── illumination_test.com.gz.sha256 │ │ │ ├── ilogb_test.com.dbg.gz.sha256 │ │ │ ├── ilogb_test.com.gz.sha256 │ │ │ ├── imaxdiv_test.com.dbg.gz.sha256 │ │ │ ├── imaxdiv_test.com.gz.sha256 │ │ │ ├── indentlines_test.com.dbg.gz.sha256 │ │ │ ├── indentlines_test.com.gz.sha256 │ │ │ ├── inet_ntoa_test.com.dbg.gz.sha256 │ │ │ ├── inet_ntoa_test.com.gz.sha256 │ │ │ ├── inet_ntop_test.com.dbg.gz.sha256 │ │ │ ├── inet_ntop_test.com.gz.sha256 │ │ │ ├── inet_pton_test.com.dbg.gz.sha256 │ │ │ ├── inet_pton_test.com.gz.sha256 │ │ │ ├── integralarithmetic_test.com.dbg.gz.sha256 │ │ │ ├── integralarithmetic_test.com.gz.sha256 │ │ │ ├── interner_test.com.dbg.gz.sha256 │ │ │ ├── interner_test.com.gz.sha256 │ │ │ ├── inv3_test.com.dbg.gz.sha256 │ │ │ ├── inv3_test.com.gz.sha256 │ │ │ ├── ioctl_siocgifconf_test.com.dbg.gz.sha256 │ │ │ ├── ioctl_siocgifconf_test.com.gz.sha256 │ │ │ ├── iovs_test.com.dbg.gz.sha256 │ │ │ ├── iovs_test.com.gz.sha256 │ │ │ ├── isacceptablehost_test.com.dbg.gz.sha256 │ │ │ ├── isacceptablehost_test.com.gz.sha256 │ │ │ ├── isacceptablepath_test.com.dbg.gz.sha256 │ │ │ ├── isacceptablepath_test.com.gz.sha256 │ │ │ ├── ismimetype_test.com.dbg.gz.sha256 │ │ │ ├── ismimetype_test.com.gz.sha256 │ │ │ ├── isnocompressext_test.com.dbg.gz.sha256 │ │ │ ├── isnocompressext_test.com.gz.sha256 │ │ │ ├── iso8601_test.com.dbg.gz.sha256 │ │ │ ├── iso8601_test.com.gz.sha256 │ │ │ ├── isreasonablepath_test.com.dbg.gz.sha256 │ │ │ ├── isreasonablepath_test.com.gz.sha256 │ │ │ ├── isutf8_test.com.dbg.gz.sha256 │ │ │ ├── isutf8_test.com.gz.sha256 │ │ │ ├── itoa64radix16_test.com.dbg.gz.sha256 │ │ │ ├── itoa64radix16_test.com.gz.sha256 │ │ │ ├── itsatrap_test.com.dbg.gz.sha256 │ │ │ ├── itsatrap_test.com.gz.sha256 │ │ │ ├── javadown_test.com.dbg.gz.sha256 │ │ │ ├── javadown_test.com.gz.sha256 │ │ │ ├── joinpaths_test.com.dbg.gz.sha256 │ │ │ ├── joinpaths_test.com.gz.sha256 │ │ │ ├── joinstrlist_test.com.dbg.gz.sha256 │ │ │ ├── joinstrlist_test.com.gz.sha256 │ │ │ ├── kbase36_test.com.dbg.gz.sha256 │ │ │ ├── kbase36_test.com.gz.sha256 │ │ │ ├── kcp437_test.com.dbg.gz.sha256 │ │ │ ├── kcp437_test.com.gz.sha256 │ │ │ ├── kprintf_test.com.dbg.gz.sha256 │ │ │ ├── kprintf_test.com.gz.sha256 │ │ │ ├── ldexp_test.com.dbg.gz.sha256 │ │ │ ├── ldexp_test.com.gz.sha256 │ │ │ ├── lengthuint64_test.com.dbg.gz.sha256 │ │ │ ├── lengthuint64_test.com.gz.sha256 │ │ │ ├── lock2_test.com.dbg.gz.sha256 │ │ │ ├── lock2_test.com.gz.sha256 │ │ │ ├── lock_ofd_test.com.dbg.gz.sha256 │ │ │ ├── lock_ofd_test.com.gz.sha256 │ │ │ ├── lock_test.com.dbg.gz.sha256 │ │ │ ├── lock_test.com.gz.sha256 │ │ │ ├── lockipc_test.com.dbg.gz.sha256 │ │ │ ├── lockipc_test.com.gz.sha256 │ │ │ ├── lockscale_test.com.dbg.gz.sha256 │ │ │ ├── lockscale_test.com.gz.sha256 │ │ │ ├── log10_test.com.dbg.gz.sha256 │ │ │ ├── log10_test.com.gz.sha256 │ │ │ ├── log1p_test.com.dbg.gz.sha256 │ │ │ ├── log1p_test.com.gz.sha256 │ │ │ ├── log2_test.com.dbg.gz.sha256 │ │ │ ├── log2_test.com.gz.sha256 │ │ │ ├── log_test.com.dbg.gz.sha256 │ │ │ ├── log_test.com.gz.sha256 │ │ │ ├── logb_test.com.dbg.gz.sha256 │ │ │ ├── logb_test.com.gz.sha256 │ │ │ ├── longsort_test.com.dbg.gz.sha256 │ │ │ ├── longsort_test.com.gz.sha256 │ │ │ ├── lseek_test.com.dbg.gz.sha256 │ │ │ ├── lseek_test.com.gz.sha256 │ │ │ ├── lz4decode_test.com.dbg.gz.sha256 │ │ │ ├── lz4decode_test.com.gz.sha256 │ │ │ ├── machine_test.com.dbg.gz.sha256 │ │ │ ├── machine_test.com.gz.sha256 │ │ │ ├── magikarp_test.com.dbg.gz.sha256 │ │ │ ├── magikarp_test.com.gz.sha256 │ │ │ ├── makedirs_test.com.dbg.gz.sha256 │ │ │ ├── makedirs_test.com.gz.sha256 │ │ │ ├── malloc_test.com.dbg.gz.sha256 │ │ │ ├── malloc_test.com.gz.sha256 │ │ │ ├── mbedtls_test.com.dbg.gz.sha256 │ │ │ ├── mbedtls_test.com.gz.sha256 │ │ │ ├── measureentropy_test.com.dbg.gz.sha256 │ │ │ ├── measureentropy_test.com.gz.sha256 │ │ │ ├── memcasecmp_test.com.dbg.gz.sha256 │ │ │ ├── memcasecmp_test.com.gz.sha256 │ │ │ ├── memccpy_test.com.dbg.gz.sha256 │ │ │ ├── memccpy_test.com.gz.sha256 │ │ │ ├── memcmp_test.com.dbg.gz.sha256 │ │ │ ├── memcmp_test.com.gz.sha256 │ │ │ ├── memcpy_test.com.dbg.gz.sha256 │ │ │ ├── memcpy_test.com.gz.sha256 │ │ │ ├── memfrob_test.com.dbg.gz.sha256 │ │ │ ├── memfrob_test.com.gz.sha256 │ │ │ ├── memmem_test.com.dbg.gz.sha256 │ │ │ ├── memmem_test.com.gz.sha256 │ │ │ ├── memmove_test.com.dbg.gz.sha256 │ │ │ ├── memmove_test.com.gz.sha256 │ │ │ ├── memory_test.com.dbg.gz.sha256 │ │ │ ├── memory_test.com.gz.sha256 │ │ │ ├── memrchr16_test.com.dbg.gz.sha256 │ │ │ ├── memrchr16_test.com.gz.sha256 │ │ │ ├── memrchr_test.com.dbg.gz.sha256 │ │ │ ├── memrchr_test.com.gz.sha256 │ │ │ ├── memset_test.com.dbg.gz.sha256 │ │ │ ├── memset_test.com.gz.sha256 │ │ │ ├── memtrack_test.com.dbg.gz.sha256 │ │ │ ├── memtrack_test.com.gz.sha256 │ │ │ ├── mkdir_test.com.dbg.gz.sha256 │ │ │ ├── mkdir_test.com.gz.sha256 │ │ │ ├── mkntcmdline_test.com.dbg.gz.sha256 │ │ │ ├── mkntcmdline_test.com.gz.sha256 │ │ │ ├── mkntenvblock_test.com.dbg.gz.sha256 │ │ │ ├── mkntenvblock_test.com.gz.sha256 │ │ │ ├── mkntpath_test.com.dbg.gz.sha256 │ │ │ ├── mkntpath_test.com.gz.sha256 │ │ │ ├── mkostempsm_test.com.dbg.gz.sha256 │ │ │ ├── mkostempsm_test.com.gz.sha256 │ │ │ ├── mmap_test.com.dbg.gz.sha256 │ │ │ ├── mmap_test.com.gz.sha256 │ │ │ ├── modrm_test.com.dbg.gz.sha256 │ │ │ ├── modrm_test.com.gz.sha256 │ │ │ ├── morton_test.com.dbg.gz.sha256 │ │ │ ├── morton_test.com.gz.sha256 │ │ │ ├── mprotect_test.com.dbg.gz.sha256 │ │ │ ├── mprotect_test.com.gz.sha256 │ │ │ ├── mt19937_test.com.dbg.gz.sha256 │ │ │ ├── mt19937_test.com.gz.sha256 │ │ │ ├── mu_starvation_test.com.dbg.gz.sha256 │ │ │ ├── mu_starvation_test.com.gz.sha256 │ │ │ ├── mu_test.com.dbg.gz.sha256 │ │ │ ├── mu_test.com.gz.sha256 │ │ │ ├── mu_wait_example_test.com.dbg.gz.sha256 │ │ │ ├── mu_wait_example_test.com.gz.sha256 │ │ │ ├── mu_wait_test.com.dbg.gz.sha256 │ │ │ ├── mu_wait_test.com.gz.sha256 │ │ │ ├── mulaw_test.com.dbg.gz.sha256 │ │ │ ├── mulaw_test.com.gz.sha256 │ │ │ ├── nanosleep_test.com.dbg.gz.sha256 │ │ │ ├── nanosleep_test.com.gz.sha256 │ │ │ ├── nointernet_test.com.dbg.gz.sha256 │ │ │ ├── nointernet_test.com.gz.sha256 │ │ │ ├── note_test.com.dbg.gz.sha256 │ │ │ ├── note_test.com.gz.sha256 │ │ │ ├── nsync_test.com.dbg.gz.sha256 │ │ │ ├── nsync_test.com.gz.sha256 │ │ │ ├── omg_test.com.dbg.gz.sha256 │ │ │ ├── omg_test.com.gz.sha256 │ │ │ ├── once_test.com.dbg.gz.sha256 │ │ │ ├── once_test.com.gz.sha256 │ │ │ ├── open_test.com.dbg.gz.sha256 │ │ │ ├── open_test.com.gz.sha256 │ │ │ ├── openbsd_test.com.dbg.gz.sha256 │ │ │ ├── openbsd_test.com.gz.sha256 │ │ │ ├── palandprintf_test.com.dbg.gz.sha256 │ │ │ ├── palandprintf_test.com.gz.sha256 │ │ │ ├── palignr_test.com.dbg.gz.sha256 │ │ │ ├── palignr_test.com.gz.sha256 │ │ │ ├── parsecidr_test.com.dbg.gz.sha256 │ │ │ ├── parsecidr_test.com.gz.sha256 │ │ │ ├── parsecontentlength_test.com.dbg.gz.sha256 │ │ │ ├── parsecontentlength_test.com.gz.sha256 │ │ │ ├── parseforwarded_test.com.dbg.gz.sha256 │ │ │ ├── parseforwarded_test.com.gz.sha256 │ │ │ ├── parsehoststxt_test.com.dbg.gz.sha256 │ │ │ ├── parsehoststxt_test.com.gz.sha256 │ │ │ ├── parsehttpdatetime_test.com.dbg.gz.sha256 │ │ │ ├── parsehttpdatetime_test.com.gz.sha256 │ │ │ ├── parsehttpmessage_test.com.dbg.gz.sha256 │ │ │ ├── parsehttpmessage_test.com.gz.sha256 │ │ │ ├── parsehttprange_test.com.dbg.gz.sha256 │ │ │ ├── parsehttprange_test.com.gz.sha256 │ │ │ ├── parseip_test.com.dbg.gz.sha256 │ │ │ ├── parseip_test.com.gz.sha256 │ │ │ ├── parseresolvconf_test.com.dbg.gz.sha256 │ │ │ ├── parseresolvconf_test.com.gz.sha256 │ │ │ ├── parseurl_test.com.dbg.gz.sha256 │ │ │ ├── parseurl_test.com.gz.sha256 │ │ │ ├── pascalifydnsname_test.com.dbg.gz.sha256 │ │ │ ├── pascalifydnsname_test.com.gz.sha256 │ │ │ ├── pcmpstr_test.com.dbg.gz.sha256 │ │ │ ├── pcmpstr_test.com.gz.sha256 │ │ │ ├── pingpong_test.com.dbg.gz.sha256 │ │ │ ├── pingpong_test.com.gz.sha256 │ │ │ ├── pledge2_test.com.dbg.gz.sha256 │ │ │ ├── pledge2_test.com.gz.sha256 │ │ │ ├── pledge_test.com.dbg.gz.sha256 │ │ │ ├── pledge_test.com.gz.sha256 │ │ │ ├── plinko_test.com.dbg.gz.sha256 │ │ │ ├── plinko_test.com.gz.sha256 │ │ │ ├── pmulhrsw_test.com.dbg.gz.sha256 │ │ │ ├── pmulhrsw_test.com.gz.sha256 │ │ │ ├── poll_test.com.dbg.gz.sha256 │ │ │ ├── poll_test.com.gz.sha256 │ │ │ ├── popcnt_test.com.dbg.gz.sha256 │ │ │ ├── popcnt_test.com.gz.sha256 │ │ │ ├── popen_test.com.dbg.gz.sha256 │ │ │ ├── popen_test.com.gz.sha256 │ │ │ ├── posix_fadvise_test.com.dbg.gz.sha256 │ │ │ ├── posix_fadvise_test.com.gz.sha256 │ │ │ ├── posix_spawn_test.com.dbg.gz.sha256 │ │ │ ├── posix_spawn_test.com.gz.sha256 │ │ │ ├── pow10_test.com.dbg.gz.sha256 │ │ │ ├── pow10_test.com.gz.sha256 │ │ │ ├── powl_test.com.dbg.gz.sha256 │ │ │ ├── powl_test.com.gz.sha256 │ │ │ ├── pread_test.com.dbg.gz.sha256 │ │ │ ├── pread_test.com.gz.sha256 │ │ │ ├── preadv_test.com.dbg.gz.sha256 │ │ │ ├── preadv_test.com.gz.sha256 │ │ │ ├── printargs_test.com.dbg.gz.sha256 │ │ │ ├── printargs_test.com.gz.sha256 │ │ │ ├── prototxt_test.com.dbg.gz.sha256 │ │ │ ├── prototxt_test.com.gz.sha256 │ │ │ ├── pshuf_test.com.dbg.gz.sha256 │ │ │ ├── pshuf_test.com.gz.sha256 │ │ │ ├── pthread_atfork_test.com.dbg.gz.sha256 │ │ │ ├── pthread_atfork_test.com.gz.sha256 │ │ │ ├── pthread_barrier_wait_test.com.dbg.gz.sha256 │ │ │ ├── pthread_barrier_wait_test.com.gz.sha256 │ │ │ ├── pthread_cancel_test.com.dbg.gz.sha256 │ │ │ ├── pthread_cancel_test.com.gz.sha256 │ │ │ ├── pthread_cond_signal_test.com.dbg.gz.sha256 │ │ │ ├── pthread_cond_signal_test.com.gz.sha256 │ │ │ ├── pthread_create_test.com.dbg.gz.sha256 │ │ │ ├── pthread_create_test.com.gz.sha256 │ │ │ ├── pthread_detach_test.com.dbg.gz.sha256 │ │ │ ├── pthread_detach_test.com.gz.sha256 │ │ │ ├── pthread_exit_test.com.dbg.gz.sha256 │ │ │ ├── pthread_exit_test.com.gz.sha256 │ │ │ ├── pthread_key_create_test.com.dbg.gz.sha256 │ │ │ ├── pthread_key_create_test.com.gz.sha256 │ │ │ ├── pthread_kill_test.com.dbg.gz.sha256 │ │ │ ├── pthread_kill_test.com.gz.sha256 │ │ │ ├── pthread_mutex_lock2_test.com.dbg.gz.sha256 │ │ │ ├── pthread_mutex_lock2_test.com.gz.sha256 │ │ │ ├── pthread_mutex_lock_test.com.dbg.gz.sha256 │ │ │ ├── pthread_mutex_lock_test.com.gz.sha256 │ │ │ ├── pthread_once_test.com.dbg.gz.sha256 │ │ │ ├── pthread_once_test.com.gz.sha256 │ │ │ ├── pthread_rwlock_rdlock_test.com.dbg.gz.sha256 │ │ │ ├── pthread_rwlock_rdlock_test.com.gz.sha256 │ │ │ ├── pthread_setname_np_test.com.dbg.gz.sha256 │ │ │ ├── pthread_setname_np_test.com.gz.sha256 │ │ │ ├── pthread_spin_lock_test.com.dbg.gz.sha256 │ │ │ ├── pthread_spin_lock_test.com.gz.sha256 │ │ │ ├── ptrace_test.com.dbg.gz.sha256 │ │ │ ├── ptrace_test.com.gz.sha256 │ │ │ ├── pty_test.com.dbg.gz.sha256 │ │ │ ├── pty_test.com.gz.sha256 │ │ │ ├── putenv_test.com.dbg.gz.sha256 │ │ │ ├── putenv_test.com.gz.sha256 │ │ │ ├── pwrite_test.com.dbg.gz.sha256 │ │ │ ├── pwrite_test.com.gz.sha256 │ │ │ ├── qsort_test.com.dbg.gz.sha256 │ │ │ ├── qsort_test.com.gz.sha256 │ │ │ ├── raise_race_test.com.dbg.gz.sha256 │ │ │ ├── raise_race_test.com.gz.sha256 │ │ │ ├── raise_test.com.dbg.gz.sha256 │ │ │ ├── raise_test.com.gz.sha256 │ │ │ ├── rand64_test.com.dbg.gz.sha256 │ │ │ ├── rand64_test.com.gz.sha256 │ │ │ ├── rand_test.com.dbg.gz.sha256 │ │ │ ├── rand_test.com.gz.sha256 │ │ │ ├── read_test.com.dbg.gz.sha256 │ │ │ ├── read_test.com.gz.sha256 │ │ │ ├── readansi_test.com.dbg.gz.sha256 │ │ │ ├── readansi_test.com.gz.sha256 │ │ │ ├── readlinkat_test.com.dbg.gz.sha256 │ │ │ ├── readlinkat_test.com.gz.sha256 │ │ │ ├── realloc_in_place_test.com.dbg.gz.sha256 │ │ │ ├── realloc_in_place_test.com.gz.sha256 │ │ │ ├── redbean_test.com.dbg.gz.sha256 │ │ │ ├── redbean_test.com.gz.sha256 │ │ │ ├── regex_test.com.dbg.gz.sha256 │ │ │ ├── regex_test.com.gz.sha256 │ │ │ ├── renameat_test.com.dbg.gz.sha256 │ │ │ ├── renameat_test.com.gz.sha256 │ │ │ ├── replacestr_test.com.dbg.gz.sha256 │ │ │ ├── replacestr_test.com.gz.sha256 │ │ │ ├── reservefd_test.com.dbg.gz.sha256 │ │ │ ├── reservefd_test.com.gz.sha256 │ │ │ ├── resolvehostsreverse_test.com.dbg.gz.sha256 │ │ │ ├── resolvehostsreverse_test.com.gz.sha256 │ │ │ ├── resolvehoststxt_test.com.dbg.gz.sha256 │ │ │ ├── resolvehoststxt_test.com.gz.sha256 │ │ │ ├── reverse_test.com.dbg.gz.sha256 │ │ │ ├── reverse_test.com.gz.sha256 │ │ │ ├── rgb2ansi_test.com.dbg.gz.sha256 │ │ │ ├── rgb2ansi_test.com.gz.sha256 │ │ │ ├── rngset_test.com.dbg.gz.sha256 │ │ │ ├── rngset_test.com.gz.sha256 │ │ │ ├── round_test.com.dbg.gz.sha256 │ │ │ ├── round_test.com.gz.sha256 │ │ │ ├── rounddown2pow_test.com.dbg.gz.sha256 │ │ │ ├── rounddown2pow_test.com.gz.sha256 │ │ │ ├── roundup2log_test.com.dbg.gz.sha256 │ │ │ ├── roundup2log_test.com.gz.sha256 │ │ │ ├── roundup2pow_test.com.dbg.gz.sha256 │ │ │ ├── roundup2pow_test.com.gz.sha256 │ │ │ ├── sad16x8n_test.com.dbg.gz.sha256 │ │ │ ├── sad16x8n_test.com.gz.sha256 │ │ │ ├── scale_test.com.dbg.gz.sha256 │ │ │ ├── scale_test.com.gz.sha256 │ │ │ ├── scalevolume_test.com.dbg.gz.sha256 │ │ │ ├── scalevolume_test.com.gz.sha256 │ │ │ ├── sched_getaffinity_test.com.dbg.gz.sha256 │ │ │ ├── sched_getaffinity_test.com.gz.sha256 │ │ │ ├── sched_setscheduler_test.com.dbg.gz.sha256 │ │ │ ├── sched_setscheduler_test.com.gz.sha256 │ │ │ ├── sched_yield_test.com.dbg.gz.sha256 │ │ │ ├── sched_yield_test.com.gz.sha256 │ │ │ ├── seccomp_test.com.dbg.gz.sha256 │ │ │ ├── seccomp_test.com.gz.sha256 │ │ │ ├── secp384r1_test.com.dbg.gz.sha256 │ │ │ ├── secp384r1_test.com.gz.sha256 │ │ │ ├── select_test.com.dbg.gz.sha256 │ │ │ ├── select_test.com.gz.sha256 │ │ │ ├── sem_open_test.com.dbg.gz.sha256 │ │ │ ├── sem_open_test.com.gz.sha256 │ │ │ ├── sem_timedwait_test.com.dbg.gz.sha256 │ │ │ ├── sem_timedwait_test.com.gz.sha256 │ │ │ ├── sendfile_test.com.dbg.gz.sha256 │ │ │ ├── sendfile_test.com.gz.sha256 │ │ │ ├── sendrecvmsg_test.com.dbg.gz.sha256 │ │ │ ├── sendrecvmsg_test.com.gz.sha256 │ │ │ ├── servicestxt_test.com.dbg.gz.sha256 │ │ │ ├── servicestxt_test.com.gz.sha256 │ │ │ ├── setitimer_test.com.dbg.gz.sha256 │ │ │ ├── setitimer_test.com.gz.sha256 │ │ │ ├── setlocale_test.com.dbg.gz.sha256 │ │ │ ├── setlocale_test.com.gz.sha256 │ │ │ ├── setrlimit_test.com.dbg.gz.sha256 │ │ │ ├── setrlimit_test.com.gz.sha256 │ │ │ ├── setsockopt_test.com.dbg.gz.sha256 │ │ │ ├── setsockopt_test.com.gz.sha256 │ │ │ ├── signal_test.com.dbg.gz.sha256 │ │ │ ├── signal_test.com.gz.sha256 │ │ │ ├── sigpending_test.com.dbg.gz.sha256 │ │ │ ├── sigpending_test.com.gz.sha256 │ │ │ ├── sigprocmask_test.com.dbg.gz.sha256 │ │ │ ├── sigprocmask_test.com.gz.sha256 │ │ │ ├── sigsetjmp_test.com.dbg.gz.sha256 │ │ │ ├── sigsetjmp_test.com.gz.sha256 │ │ │ ├── sigsuspend_test.com.dbg.gz.sha256 │ │ │ ├── sigsuspend_test.com.gz.sha256 │ │ │ ├── sigtimedwait_test.com.dbg.gz.sha256 │ │ │ ├── sigtimedwait_test.com.gz.sha256 │ │ │ ├── sin_test.com.dbg.gz.sha256 │ │ │ ├── sin_test.com.gz.sha256 │ │ │ ├── sincos_test.com.dbg.gz.sha256 │ │ │ ├── sincos_test.com.gz.sha256 │ │ │ ├── sinh_test.com.dbg.gz.sha256 │ │ │ ├── sinh_test.com.gz.sha256 │ │ │ ├── sizetol_test.com.dbg.gz.sha256 │ │ │ ├── sizetol_test.com.gz.sha256 │ │ │ ├── sleb128_test.com.dbg.gz.sha256 │ │ │ ├── sleb128_test.com.gz.sha256 │ │ │ ├── snprintf_test.com.dbg.gz.sha256 │ │ │ ├── snprintf_test.com.gz.sha256 │ │ │ ├── socket_test.com.dbg.gz.sha256 │ │ │ ├── socket_test.com.gz.sha256 │ │ │ ├── socketpair_test.com.dbg.gz.sha256 │ │ │ ├── socketpair_test.com.gz.sha256 │ │ │ ├── sortedints_test.com.dbg.gz.sha256 │ │ │ ├── sortedints_test.com.gz.sha256 │ │ │ ├── spawn_test.com.dbg.gz.sha256 │ │ │ ├── spawn_test.com.gz.sha256 │ │ │ ├── splice_test.com.dbg.gz.sha256 │ │ │ ├── splice_test.com.gz.sha256 │ │ │ ├── sprintf_s_test.com.dbg.gz.sha256 │ │ │ ├── sprintf_s_test.com.gz.sha256 │ │ │ ├── sqrt_test.com.dbg.gz.sha256 │ │ │ ├── sqrt_test.com.gz.sha256 │ │ │ ├── sscanf_test.com.dbg.gz.sha256 │ │ │ ├── sscanf_test.com.gz.sha256 │ │ │ ├── stackrw_test.com.dbg.gz.sha256 │ │ │ ├── stackrw_test.com.gz.sha256 │ │ │ ├── stackrwx_test.com.dbg.gz.sha256 │ │ │ ├── stackrwx_test.com.gz.sha256 │ │ │ ├── stat_test.com.dbg.gz.sha256 │ │ │ ├── stat_test.com.gz.sha256 │ │ │ ├── statfs_test.com.dbg.gz.sha256 │ │ │ ├── statfs_test.com.gz.sha256 │ │ │ ├── str_test.com.dbg.gz.sha256 │ │ │ ├── str_test.com.gz.sha256 │ │ │ ├── strcasecmp_test.com.dbg.gz.sha256 │ │ │ ├── strcasecmp_test.com.gz.sha256 │ │ │ ├── strcaseconv_test.com.dbg.gz.sha256 │ │ │ ├── strcaseconv_test.com.gz.sha256 │ │ │ ├── strcasestr_test.com.dbg.gz.sha256 │ │ │ ├── strcasestr_test.com.gz.sha256 │ │ │ ├── strcat_test.com.dbg.gz.sha256 │ │ │ ├── strcat_test.com.gz.sha256 │ │ │ ├── strchr_test.com.dbg.gz.sha256 │ │ │ ├── strchr_test.com.gz.sha256 │ │ │ ├── strclen_test.com.dbg.gz.sha256 │ │ │ ├── strclen_test.com.gz.sha256 │ │ │ ├── strcmp_test.com.dbg.gz.sha256 │ │ │ ├── strcmp_test.com.gz.sha256 │ │ │ ├── strcpy_test.com.dbg.gz.sha256 │ │ │ ├── strcpy_test.com.gz.sha256 │ │ │ ├── strcspn_test.com.dbg.gz.sha256 │ │ │ ├── strcspn_test.com.gz.sha256 │ │ │ ├── strdup_test.com.dbg.gz.sha256 │ │ │ ├── strdup_test.com.gz.sha256 │ │ │ ├── strerror_r_test.com.dbg.gz.sha256 │ │ │ ├── strerror_r_test.com.gz.sha256 │ │ │ ├── strftime_test.com.dbg.gz.sha256 │ │ │ ├── strftime_test.com.gz.sha256 │ │ │ ├── stripcomponents_test.com.dbg.gz.sha256 │ │ │ ├── stripcomponents_test.com.gz.sha256 │ │ │ ├── stripexts_test.com.dbg.gz.sha256 │ │ │ ├── stripexts_test.com.gz.sha256 │ │ │ ├── strlcpy_test.com.dbg.gz.sha256 │ │ │ ├── strlcpy_test.com.gz.sha256 │ │ │ ├── strlen_test.com.dbg.gz.sha256 │ │ │ ├── strlen_test.com.gz.sha256 │ │ │ ├── strnlen_test.com.dbg.gz.sha256 │ │ │ ├── strnlen_test.com.gz.sha256 │ │ │ ├── strnwidth_test.com.dbg.gz.sha256 │ │ │ ├── strnwidth_test.com.gz.sha256 │ │ │ ├── strpbrk_test.com.dbg.gz.sha256 │ │ │ ├── strpbrk_test.com.gz.sha256 │ │ │ ├── strrchr_test.com.dbg.gz.sha256 │ │ │ ├── strrchr_test.com.gz.sha256 │ │ │ ├── strsak32_test.com.dbg.gz.sha256 │ │ │ ├── strsak32_test.com.gz.sha256 │ │ │ ├── strsignal_r_test.com.dbg.gz.sha256 │ │ │ ├── strsignal_r_test.com.gz.sha256 │ │ │ ├── strstr_test.com.dbg.gz.sha256 │ │ │ ├── strstr_test.com.gz.sha256 │ │ │ ├── strtod_test.com.dbg.gz.sha256 │ │ │ ├── strtod_test.com.gz.sha256 │ │ │ ├── strtok_r_test.com.dbg.gz.sha256 │ │ │ ├── strtok_r_test.com.gz.sha256 │ │ │ ├── strtolower_test.com.dbg.gz.sha256 │ │ │ ├── strtolower_test.com.gz.sha256 │ │ │ ├── symlinkat_test.com.dbg.gz.sha256 │ │ │ ├── symlinkat_test.com.gz.sha256 │ │ │ ├── sys_ptrace_test.com.dbg.gz.sha256 │ │ │ ├── sys_ptrace_test.com.gz.sha256 │ │ │ ├── system_test.com.dbg.gz.sha256 │ │ │ ├── system_test.com.gz.sha256 │ │ │ ├── tan_test.com.dbg.gz.sha256 │ │ │ ├── tan_test.com.gz.sha256 │ │ │ ├── tanh_test.com.dbg.gz.sha256 │ │ │ ├── tanh_test.com.gz.sha256 │ │ │ ├── tarjan_test.com.dbg.gz.sha256 │ │ │ ├── tarjan_test.com.gz.sha256 │ │ │ ├── test_suite_aes.cbc.com.dbg.gz.sha256 │ │ │ ├── test_suite_aes.cbc.com.gz.sha256 │ │ │ ├── test_suite_aes.cfb.com.dbg.gz.sha256 │ │ │ ├── test_suite_aes.cfb.com.gz.sha256 │ │ │ ├── test_suite_aes.ecb.com.dbg.gz.sha256 │ │ │ ├── test_suite_aes.ecb.com.gz.sha256 │ │ │ ├── test_suite_aes.ofb.com.dbg.gz.sha256 │ │ │ ├── test_suite_aes.ofb.com.gz.sha256 │ │ │ ├── test_suite_aes.rest.com.dbg.gz.sha256 │ │ │ ├── test_suite_aes.rest.com.gz.sha256 │ │ │ ├── test_suite_aes.xts.com.dbg.gz.sha256 │ │ │ ├── test_suite_aes.xts.com.gz.sha256 │ │ │ ├── test_suite_asn1parse.com.dbg.gz.sha256 │ │ │ ├── test_suite_asn1parse.com.gz.sha256 │ │ │ ├── test_suite_asn1write.com.dbg.gz.sha256 │ │ │ ├── test_suite_asn1write.com.gz.sha256 │ │ │ ├── test_suite_base64.com.dbg.gz.sha256 │ │ │ ├── test_suite_base64.com.gz.sha256 │ │ │ ├── test_suite_blowfish.com.dbg.gz.sha256 │ │ │ ├── test_suite_blowfish.com.gz.sha256 │ │ │ ├── test_suite_chacha20.com.dbg.gz.sha256 │ │ │ ├── test_suite_chacha20.com.gz.sha256 │ │ │ ├── test_suite_chachapoly.com.dbg.gz.sha256 │ │ │ ├── test_suite_chachapoly.com.gz.sha256 │ │ │ ├── test_suite_cipher.aes.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.aes.com.gz.sha256 │ │ │ ├── test_suite_cipher.blowfish.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.blowfish.com.gz.sha256 │ │ │ ├── test_suite_cipher.ccm.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.ccm.com.gz.sha256 │ │ │ ├── test_suite_cipher.chacha20.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.chacha20.com.gz.sha256 │ │ │ ├── test_suite_cipher.chachapoly.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.chachapoly.com.gz.sha256 │ │ │ ├── test_suite_cipher.des.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.des.com.gz.sha256 │ │ │ ├── test_suite_cipher.gcm.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.gcm.com.gz.sha256 │ │ │ ├── test_suite_cipher.misc.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.misc.com.gz.sha256 │ │ │ ├── test_suite_cipher.nist_kw.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.nist_kw.com.gz.sha256 │ │ │ ├── test_suite_cipher.null.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.null.com.gz.sha256 │ │ │ ├── test_suite_cipher.padding.com.dbg.gz.sha256 │ │ │ ├── test_suite_cipher.padding.com.gz.sha256 │ │ │ ├── test_suite_ctr_drbg.com.dbg.gz.sha256 │ │ │ ├── test_suite_ctr_drbg.com.gz.sha256 │ │ │ ├── test_suite_des.com.dbg.gz.sha256 │ │ │ ├── test_suite_des.com.gz.sha256 │ │ │ ├── test_suite_dhm.com.dbg.gz.sha256 │ │ │ ├── test_suite_dhm.com.gz.sha256 │ │ │ ├── test_suite_ecdh.com.dbg.gz.sha256 │ │ │ ├── test_suite_ecdh.com.gz.sha256 │ │ │ ├── test_suite_ecdsa.com.dbg.gz.sha256 │ │ │ ├── test_suite_ecdsa.com.gz.sha256 │ │ │ ├── test_suite_ecp.com.dbg.gz.sha256 │ │ │ ├── test_suite_ecp.com.gz.sha256 │ │ │ ├── test_suite_entropy.com.dbg.gz.sha256 │ │ │ ├── test_suite_entropy.com.gz.sha256 │ │ │ ├── test_suite_error.com.dbg.gz.sha256 │ │ │ ├── test_suite_error.com.gz.sha256 │ │ │ ├── test_suite_gcm.aes128_de.com.dbg.gz.sha256 │ │ │ ├── test_suite_gcm.aes128_de.com.gz.sha256 │ │ │ ├── test_suite_gcm.aes128_en.com.dbg.gz.sha256 │ │ │ ├── test_suite_gcm.aes128_en.com.gz.sha256 │ │ │ ├── test_suite_gcm.aes192_de.com.dbg.gz.sha256 │ │ │ ├── test_suite_gcm.aes192_de.com.gz.sha256 │ │ │ ├── test_suite_gcm.aes192_en.com.dbg.gz.sha256 │ │ │ ├── test_suite_gcm.aes192_en.com.gz.sha256 │ │ │ ├── test_suite_gcm.aes256_de.com.dbg.gz.sha256 │ │ │ ├── test_suite_gcm.aes256_de.com.gz.sha256 │ │ │ ├── test_suite_gcm.aes256_en.com.dbg.gz.sha256 │ │ │ ├── test_suite_gcm.aes256_en.com.gz.sha256 │ │ │ ├── test_suite_gcm.misc.com.dbg.gz.sha256 │ │ │ ├── test_suite_gcm.misc.com.gz.sha256 │ │ │ ├── test_suite_hkdf.com.dbg.gz.sha256 │ │ │ ├── test_suite_hkdf.com.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.misc.com.dbg.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.misc.com.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.no_reseed.com.dbg.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.no_reseed.com.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.nopr.com.dbg.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.nopr.com.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.pr.com.dbg.gz.sha256 │ │ │ ├── test_suite_hmac_drbg.pr.com.gz.sha256 │ │ │ ├── test_suite_md.com.dbg.gz.sha256 │ │ │ ├── test_suite_md.com.gz.sha256 │ │ │ ├── test_suite_mdx.com.dbg.gz.sha256 │ │ │ ├── test_suite_mdx.com.gz.sha256 │ │ │ ├── test_suite_memory_buffer_alloc.com.dbg.gz.sha256 │ │ │ ├── test_suite_memory_buffer_alloc.com.gz.sha256 │ │ │ ├── test_suite_mpi.com.dbg.gz.sha256 │ │ │ ├── test_suite_mpi.com.gz.sha256 │ │ │ ├── test_suite_net.com.dbg.gz.sha256 │ │ │ ├── test_suite_net.com.gz.sha256 │ │ │ ├── test_suite_nist_kw.com.dbg.gz.sha256 │ │ │ ├── test_suite_nist_kw.com.gz.sha256 │ │ │ ├── test_suite_oid.com.dbg.gz.sha256 │ │ │ ├── test_suite_oid.com.gz.sha256 │ │ │ ├── test_suite_pem.com.dbg.gz.sha256 │ │ │ ├── test_suite_pem.com.gz.sha256 │ │ │ ├── test_suite_pk.com.dbg.gz.sha256 │ │ │ ├── test_suite_pk.com.gz.sha256 │ │ │ ├── test_suite_pkcs1_v15.com.dbg.gz.sha256 │ │ │ ├── test_suite_pkcs1_v15.com.gz.sha256 │ │ │ ├── test_suite_pkcs1_v21.com.dbg.gz.sha256 │ │ │ ├── test_suite_pkcs1_v21.com.gz.sha256 │ │ │ ├── test_suite_pkcs5.com.dbg.gz.sha256 │ │ │ ├── test_suite_pkcs5.com.gz.sha256 │ │ │ ├── test_suite_pkparse.com.dbg.gz.sha256 │ │ │ ├── test_suite_pkparse.com.gz.sha256 │ │ │ ├── test_suite_pkwrite.com.dbg.gz.sha256 │ │ │ ├── test_suite_pkwrite.com.gz.sha256 │ │ │ ├── test_suite_poly1305.com.dbg.gz.sha256 │ │ │ ├── test_suite_poly1305.com.gz.sha256 │ │ │ ├── test_suite_random.com.dbg.gz.sha256 │ │ │ ├── test_suite_random.com.gz.sha256 │ │ │ ├── test_suite_rsa.com.dbg.gz.sha256 │ │ │ ├── test_suite_rsa.com.gz.sha256 │ │ │ ├── test_suite_shax.com.dbg.gz.sha256 │ │ │ ├── test_suite_shax.com.gz.sha256 │ │ │ ├── test_suite_ssl.com.dbg.gz.sha256 │ │ │ ├── test_suite_ssl.com.gz.sha256 │ │ │ ├── test_suite_timing.com.dbg.gz.sha256 │ │ │ ├── test_suite_timing.com.gz.sha256 │ │ │ ├── test_suite_version.com.dbg.gz.sha256 │ │ │ ├── test_suite_version.com.gz.sha256 │ │ │ ├── test_suite_x509parse.com.dbg.gz.sha256 │ │ │ ├── test_suite_x509parse.com.gz.sha256 │ │ │ ├── test_suite_x509write.com.dbg.gz.sha256 │ │ │ ├── test_suite_x509write.com.gz.sha256 │ │ │ ├── tgamma_test.com.dbg.gz.sha256 │ │ │ ├── tgamma_test.com.gz.sha256 │ │ │ ├── timevaltofiletime_test.com.dbg.gz.sha256 │ │ │ ├── timevaltofiletime_test.com.gz.sha256 │ │ │ ├── tkill_test.com.dbg.gz.sha256 │ │ │ ├── tkill_test.com.gz.sha256 │ │ │ ├── tls_test.com.dbg.gz.sha256 │ │ │ ├── tls_test.com.gz.sha256 │ │ │ ├── tmpfile_test.com.dbg.gz.sha256 │ │ │ ├── tmpfile_test.com.gz.sha256 │ │ │ ├── tokenbucket_test.com.dbg.gz.sha256 │ │ │ ├── tokenbucket_test.com.gz.sha256 │ │ │ ├── towupper_test.com.dbg.gz.sha256 │ │ │ ├── towupper_test.com.gz.sha256 │ │ │ ├── tpenc_test.com.dbg.gz.sha256 │ │ │ ├── tpenc_test.com.gz.sha256 │ │ │ ├── tprecode16to8_test.com.dbg.gz.sha256 │ │ │ ├── tprecode16to8_test.com.gz.sha256 │ │ │ ├── tprecode8to16_test.com.dbg.gz.sha256 │ │ │ ├── tprecode8to16_test.com.gz.sha256 │ │ │ ├── trunc_test.com.dbg.gz.sha256 │ │ │ ├── trunc_test.com.gz.sha256 │ │ │ ├── ttymove_test.com.dbg.gz.sha256 │ │ │ ├── ttymove_test.com.gz.sha256 │ │ │ ├── ttyraster_test.com.dbg.gz.sha256 │ │ │ ├── ttyraster_test.com.gz.sha256 │ │ │ ├── uleb128_test.com.dbg.gz.sha256 │ │ │ ├── uleb128_test.com.gz.sha256 │ │ │ ├── uleb64_test.com.dbg.gz.sha256 │ │ │ ├── uleb64_test.com.gz.sha256 │ │ │ ├── unchunk_test.com.dbg.gz.sha256 │ │ │ ├── unchunk_test.com.gz.sha256 │ │ │ ├── underlong_test.com.dbg.gz.sha256 │ │ │ ├── underlong_test.com.gz.sha256 │ │ │ ├── ungetc_test.com.dbg.gz.sha256 │ │ │ ├── ungetc_test.com.gz.sha256 │ │ │ ├── unlinkat_test.com.dbg.gz.sha256 │ │ │ ├── unlinkat_test.com.gz.sha256 │ │ │ ├── unveil_test.com.dbg.gz.sha256 │ │ │ ├── unveil_test.com.gz.sha256 │ │ │ ├── utf16to32_test.com.dbg.gz.sha256 │ │ │ ├── utf16to32_test.com.gz.sha256 │ │ │ ├── utf16to8_test.com.dbg.gz.sha256 │ │ │ ├── utf16to8_test.com.gz.sha256 │ │ │ ├── utf8to16_test.com.dbg.gz.sha256 │ │ │ ├── utf8to16_test.com.gz.sha256 │ │ │ ├── utf8to32_test.com.dbg.gz.sha256 │ │ │ ├── utf8to32_test.com.gz.sha256 │ │ │ ├── vappendf_test.com.dbg.gz.sha256 │ │ │ ├── vappendf_test.com.gz.sha256 │ │ │ ├── vfork_test.com.dbg.gz.sha256 │ │ │ ├── vfork_test.com.gz.sha256 │ │ │ ├── visualizecontrolcodes_test.com.dbg.gz.sha256 │ │ │ ├── visualizecontrolcodes_test.com.gz.sha256 │ │ │ ├── wait_test.com.dbg.gz.sha256 │ │ │ ├── wait_test.com.gz.sha256 │ │ │ ├── wcsrchr_test.com.dbg.gz.sha256 │ │ │ ├── wcsrchr_test.com.gz.sha256 │ │ │ ├── wcwidth_test.com.dbg.gz.sha256 │ │ │ ├── wcwidth_test.com.gz.sha256 │ │ │ ├── windex_test.com.dbg.gz.sha256 │ │ │ ├── windex_test.com.gz.sha256 │ │ │ ├── wmemrchr_test.com.dbg.gz.sha256 │ │ │ ├── wmemrchr_test.com.gz.sha256 │ │ │ ├── write_test.com.dbg.gz.sha256 │ │ │ ├── write_test.com.gz.sha256 │ │ │ ├── wut_test.com.dbg.gz.sha256 │ │ │ ├── wut_test.com.gz.sha256 │ │ │ ├── x86ild_popular_binary_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_binary_test.com.gz.sha256 │ │ │ ├── x86ild_popular_cmov_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_cmov_test.com.gz.sha256 │ │ │ ├── x86ild_popular_i186_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_i186_test.com.gz.sha256 │ │ │ ├── x86ild_popular_i386_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_i386_test.com.gz.sha256 │ │ │ ├── x86ild_popular_i86_2_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_i86_2_test.com.gz.sha256 │ │ │ ├── x86ild_popular_i86_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_i86_test.com.gz.sha256 │ │ │ ├── x86ild_popular_logical_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_logical_test.com.gz.sha256 │ │ │ ├── x86ild_popular_misc_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_popular_misc_test.com.gz.sha256 │ │ │ ├── x86ild_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_test.com.gz.sha256 │ │ │ ├── x86ild_widenop_test.com.dbg.gz.sha256 │ │ │ ├── x86ild_widenop_test.com.gz.sha256 │ │ │ ├── xasprintf_test.com.dbg.gz.sha256 │ │ │ ├── xasprintf_test.com.gz.sha256 │ │ │ ├── xfixpath_test.com.dbg.gz.sha256 │ │ │ ├── xfixpath_test.com.gz.sha256 │ │ │ ├── xjoinpaths_test.com.dbg.gz.sha256 │ │ │ ├── xjoinpaths_test.com.gz.sha256 │ │ │ ├── xlaterrno_test.com.dbg.gz.sha256 │ │ │ ├── xlaterrno_test.com.gz.sha256 │ │ │ ├── xslurp_test.com.dbg.gz.sha256 │ │ │ ├── xslurp_test.com.gz.sha256 │ │ │ ├── xstrcat_test.com.dbg.gz.sha256 │ │ │ ├── xstrcat_test.com.gz.sha256 │ │ │ ├── ycbcr2rgb2_test.com.dbg.gz.sha256 │ │ │ ├── ycbcr2rgb2_test.com.gz.sha256 │ │ │ ├── zleb64_test.com.dbg.gz.sha256 │ │ │ └── zleb64_test.com.gz.sha256 │ │ ├── 3/ │ │ │ ├── sqlite_test.com.dbg.gz.sha256 │ │ │ └── sqlite_test.com.gz.sha256 │ │ ├── 4/ │ │ │ ├── dtoa_test.com.dbg.gz.sha256 │ │ │ ├── dtoa_test.com.gz.sha256 │ │ │ ├── writev_test.com.dbg.gz.sha256 │ │ │ └── writev_test.com.gz.sha256 │ │ ├── 5/ │ │ │ ├── pipe_test.com.dbg.gz.sha256 │ │ │ ├── pipe_test.com.gz.sha256 │ │ │ ├── sigaction_test.com.dbg.gz.sha256 │ │ │ ├── sigaction_test.com.gz.sha256 │ │ │ ├── unix_test.com.dbg.gz.sha256 │ │ │ └── unix_test.com.gz.sha256 │ │ ├── 7/ │ │ │ ├── munmap_test.com.dbg.gz.sha256 │ │ │ ├── munmap_test.com.gz.sha256 │ │ │ ├── utimensat_test.com.dbg.gz.sha256 │ │ │ └── utimensat_test.com.gz.sha256 │ │ ├── 8/ │ │ │ ├── ftruncate_test.com.dbg.gz.sha256 │ │ │ ├── ftruncate_test.com.gz.sha256 │ │ │ ├── intrin_test.com.dbg.gz.sha256 │ │ │ └── intrin_test.com.gz.sha256 │ │ └── cosmo.mk │ ├── elks/ │ │ ├── README │ │ └── fd1440.img │ ├── freedos/ │ │ ├── README │ │ └── freedos13-floppy.img │ ├── gameoflife/ │ │ └── README.md │ ├── games/ │ │ └── README │ ├── gcc/ │ │ ├── 2/ │ │ │ ├── x86_64-linux-musl__mips64-linux-musl__g++-9.4.0.tar.xz.sha256 │ │ │ └── x86_64-linux-musl__powerpc64le-linux-musl__g++-9.2.0.tar.xz.sha256 │ │ ├── gcc.mk │ │ ├── x86_64-linux-musl__aarch64-linux-musl__g++-7.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__arm-linux-musleabi__g++-7.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__i486-linux-musl__g++-7.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__m68k-linux-musl__gcc-5.3.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__microblaze-linux-musl__g++-7.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__mips-linux-musl__g++-7.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__mips64el-linux-musl__gcc-5.3.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__mipsel-linux-musl__g++-9.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__powerpc-linux-musl__g++-7.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__riscv64-linux-musl__gcc-9.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__s390x-linux-musl__g++-7.2.0.tar.xz.sha256 │ │ ├── x86_64-linux-musl__x86_64-linux-musl__g++-4.9.4.tar.xz.sha256 │ │ ├── x86_64-linux-musl__x86_64-linux-musl__g++-7.2.0.tar.xz.sha256 │ │ └── x86_64-linux-musl__x86_64-linux-musl__gcc-4.8.5.tar.xz.sha256 │ ├── libc-test/ │ │ ├── README.md │ │ ├── bin/ │ │ │ ├── 2/ │ │ │ │ ├── functional/ │ │ │ │ │ ├── argv.elf.gz.sha256 │ │ │ │ │ ├── basename.elf.gz.sha256 │ │ │ │ │ ├── clocale_mbfuncs.elf.gz.sha256 │ │ │ │ │ ├── clock_gettime.elf.gz.sha256 │ │ │ │ │ ├── crypt.elf.gz.sha256 │ │ │ │ │ ├── dirname.elf.gz.sha256 │ │ │ │ │ ├── env.elf.gz.sha256 │ │ │ │ │ ├── fcntl.elf.gz.sha256 │ │ │ │ │ ├── fdopen.elf.gz.sha256 │ │ │ │ │ ├── fnmatch.elf.gz.sha256 │ │ │ │ │ ├── fscanf.elf.gz.sha256 │ │ │ │ │ ├── fwscanf.elf.gz.sha256 │ │ │ │ │ ├── iconv_open.elf.gz.sha256 │ │ │ │ │ ├── mbc.elf.gz.sha256 │ │ │ │ │ ├── memstream.elf.gz.sha256 │ │ │ │ │ ├── pthread_cancel-points.elf.gz.sha256 │ │ │ │ │ ├── pthread_cancel.elf.gz.sha256 │ │ │ │ │ ├── pthread_cond.elf.gz.sha256 │ │ │ │ │ ├── pthread_mutex.elf.gz.sha256 │ │ │ │ │ ├── pthread_tsd.elf.gz.sha256 │ │ │ │ │ ├── qsort.elf.gz.sha256 │ │ │ │ │ ├── random.elf.gz.sha256 │ │ │ │ │ ├── search_hsearch.elf.gz.sha256 │ │ │ │ │ ├── search_insque.elf.gz.sha256 │ │ │ │ │ ├── search_lsearch.elf.gz.sha256 │ │ │ │ │ ├── search_tsearch.elf.gz.sha256 │ │ │ │ │ ├── sem_init.elf.gz.sha256 │ │ │ │ │ ├── sem_open.elf.gz.sha256 │ │ │ │ │ ├── setjmp.elf.gz.sha256 │ │ │ │ │ ├── socket.elf.gz.sha256 │ │ │ │ │ ├── sscanf_long.elf.gz.sha256 │ │ │ │ │ ├── stat.elf.gz.sha256 │ │ │ │ │ ├── strftime.elf.gz.sha256 │ │ │ │ │ ├── string.elf.gz.sha256 │ │ │ │ │ ├── string_memcpy.elf.gz.sha256 │ │ │ │ │ ├── string_memmem.elf.gz.sha256 │ │ │ │ │ ├── string_memset.elf.gz.sha256 │ │ │ │ │ ├── string_strchr.elf.gz.sha256 │ │ │ │ │ ├── string_strcspn.elf.gz.sha256 │ │ │ │ │ ├── string_strstr.elf.gz.sha256 │ │ │ │ │ ├── strtol.elf.gz.sha256 │ │ │ │ │ ├── strtold.elf.gz.sha256 │ │ │ │ │ ├── tgmath.elf.gz.sha256 │ │ │ │ │ ├── time.elf.gz.sha256 │ │ │ │ │ ├── tls_init.elf.gz.sha256 │ │ │ │ │ ├── tls_local_exec.elf.gz.sha256 │ │ │ │ │ ├── udiv.elf.gz.sha256 │ │ │ │ │ ├── ungetc.elf.gz.sha256 │ │ │ │ │ ├── utime.elf.gz.sha256 │ │ │ │ │ ├── vfork.elf.gz.sha256 │ │ │ │ │ ├── wcsstr.elf.gz.sha256 │ │ │ │ │ └── wcstol.elf.gz.sha256 │ │ │ │ └── regression/ │ │ │ │ ├── dn_expand-empty.elf.gz.sha256 │ │ │ │ ├── dn_expand-ptr-0.elf.gz.sha256 │ │ │ │ ├── execle-env.elf.gz.sha256 │ │ │ │ ├── fflush-exit.elf.gz.sha256 │ │ │ │ ├── fgets-eof.elf.gz.sha256 │ │ │ │ ├── fgetwc-buffering.elf.gz.sha256 │ │ │ │ ├── flockfile-list.elf.gz.sha256 │ │ │ │ ├── ftello-unflushed-append.elf.gz.sha256 │ │ │ │ ├── getpwnam_r-crash.elf.gz.sha256 │ │ │ │ ├── getpwnam_r-errno.elf.gz.sha256 │ │ │ │ ├── iconv-roundtrips.elf.gz.sha256 │ │ │ │ ├── inet_ntop-v4mapped.elf.gz.sha256 │ │ │ │ ├── inet_pton-empty-last-field.elf.gz.sha256 │ │ │ │ ├── iswspace-null.elf.gz.sha256 │ │ │ │ ├── lrand48-signextend.elf.gz.sha256 │ │ │ │ ├── lseek-large.elf.gz.sha256 │ │ │ │ ├── malloc-0.elf.gz.sha256 │ │ │ │ ├── mbsrtowcs-overflow.elf.gz.sha256 │ │ │ │ ├── memmem-oob-read.elf.gz.sha256 │ │ │ │ ├── memmem-oob.elf.gz.sha256 │ │ │ │ ├── mkdtemp-failure.elf.gz.sha256 │ │ │ │ ├── mkstemp-failure.elf.gz.sha256 │ │ │ │ ├── printf-fmt-g-round.elf.gz.sha256 │ │ │ │ ├── printf-fmt-g-zeros.elf.gz.sha256 │ │ │ │ ├── printf-fmt-n.elf.gz.sha256 │ │ │ │ ├── pthread-robust-detach.elf.gz.sha256 │ │ │ │ ├── pthread_atfork-errno-clobber.elf.gz.sha256 │ │ │ │ ├── pthread_cancel-sem_wait.elf.gz.sha256 │ │ │ │ ├── pthread_cond-smasher.elf.gz.sha256 │ │ │ │ ├── pthread_condattr_setclock.elf.gz.sha256 │ │ │ │ ├── pthread_exit-cancel.elf.gz.sha256 │ │ │ │ ├── pthread_exit-dtor.elf.gz.sha256 │ │ │ │ ├── pthread_once-deadlock.elf.gz.sha256 │ │ │ │ ├── pthread_rwlock-ebusy.elf.gz.sha256 │ │ │ │ ├── putenv-doublefree.elf.gz.sha256 │ │ │ │ ├── regex-backref-0.elf.gz.sha256 │ │ │ │ ├── regex-bracket-icase.elf.gz.sha256 │ │ │ │ ├── regex-ere-backref.elf.gz.sha256 │ │ │ │ ├── regex-escaped-high-byte.elf.gz.sha256 │ │ │ │ ├── regex-negated-range.elf.gz.sha256 │ │ │ │ ├── regexec-nosub.elf.gz.sha256 │ │ │ │ ├── rewind-clear-error.elf.gz.sha256 │ │ │ │ ├── scanf-bytes-consumed.elf.gz.sha256 │ │ │ │ ├── scanf-match-literal-eof.elf.gz.sha256 │ │ │ │ ├── scanf-nullbyte-char.elf.gz.sha256 │ │ │ │ ├── sem_close-unmap.elf.gz.sha256 │ │ │ │ ├── setvbuf-unget.elf.gz.sha256 │ │ │ │ ├── sigaltstack.elf.gz.sha256 │ │ │ │ ├── sigprocmask-internal.elf.gz.sha256 │ │ │ │ ├── sigreturn.elf.gz.sha256 │ │ │ │ ├── sscanf-eof.elf.gz.sha256 │ │ │ │ ├── statvfs.elf.gz.sha256 │ │ │ │ ├── strverscmp.elf.gz.sha256 │ │ │ │ ├── syscall-sign-extend.elf.gz.sha256 │ │ │ │ ├── uselocale-0.elf.gz.sha256 │ │ │ │ ├── wcsncpy-read-overflow.elf.gz.sha256 │ │ │ │ └── wcsstr-false-negative.elf.gz.sha256 │ │ │ └── 3/ │ │ │ ├── functional/ │ │ │ │ ├── inet_pton.elf.gz.sha256 │ │ │ │ └── popen.elf.gz.sha256 │ │ │ └── regression/ │ │ │ ├── daemon-failure.elf.gz.sha256 │ │ │ ├── malloc-oom.elf.gz.sha256 │ │ │ ├── pthread_create-oom.elf.gz.sha256 │ │ │ └── setenv-oom.elf.gz.sha256 │ │ ├── deploy-libc-test │ │ └── libc-test.mk │ ├── libz/ │ │ ├── LICENSE │ │ ├── README.blink │ │ ├── adler32.c │ │ ├── compress.c │ │ ├── crc32.c │ │ ├── crc32.h │ │ ├── deflate.c │ │ ├── deflate.h │ │ ├── gzclose.c │ │ ├── gzguts.h │ │ ├── gzlib.c │ │ ├── gzread.c │ │ ├── gzwrite.c │ │ ├── infback.c │ │ ├── inffast.c │ │ ├── inffast.h │ │ ├── inffixed.h │ │ ├── inflate.c │ │ ├── inflate.h │ │ ├── inftrees.c │ │ ├── inftrees.h │ │ ├── trees.c │ │ ├── trees.h │ │ ├── uncompr.c │ │ ├── zconf.h │ │ ├── zlib.h │ │ ├── zlib.mk │ │ ├── zutil.c │ │ └── zutil.h │ ├── ltp/ │ │ ├── README.md │ │ ├── bin/ │ │ │ ├── 1/ │ │ │ │ ├── accept01.elf.gz.sha256 │ │ │ │ ├── accept4_01.elf.gz.sha256 │ │ │ │ ├── access01.elf.gz.sha256 │ │ │ │ ├── access03.elf.gz.sha256 │ │ │ │ ├── alarm02.elf.gz.sha256 │ │ │ │ ├── alarm03.elf.gz.sha256 │ │ │ │ ├── alarm05.elf.gz.sha256 │ │ │ │ ├── alarm06.elf.gz.sha256 │ │ │ │ ├── alarm07.elf.gz.sha256 │ │ │ │ ├── atof01.elf.gz.sha256 │ │ │ │ ├── autogroup01.elf.gz.sha256 │ │ │ │ ├── bind01.elf.gz.sha256 │ │ │ │ ├── bind03.elf.gz.sha256 │ │ │ │ ├── brk02.elf.gz.sha256 │ │ │ │ ├── chmod01.elf.gz.sha256 │ │ │ │ ├── chmod07.elf.gz.sha256 │ │ │ │ ├── chown01.elf.gz.sha256 │ │ │ │ ├── chown02.elf.gz.sha256 │ │ │ │ ├── chown05.elf.gz.sha256 │ │ │ │ ├── clock_getres01.elf.gz.sha256 │ │ │ │ ├── clock_gettime01.elf.gz.sha256 │ │ │ │ ├── clock_gettime04.elf.gz.sha256 │ │ │ │ ├── clock_nanosleep02.elf.gz.sha256 │ │ │ │ ├── clock_nanosleep04.elf.gz.sha256 │ │ │ │ ├── close01.elf.gz.sha256 │ │ │ │ ├── close02.elf.gz.sha256 │ │ │ │ ├── close_range02.elf.gz.sha256 │ │ │ │ ├── confstr01.elf.gz.sha256 │ │ │ │ ├── creat01.elf.gz.sha256 │ │ │ │ ├── creat03.elf.gz.sha256 │ │ │ │ ├── creat05.elf.gz.sha256 │ │ │ │ ├── dup01.elf.gz.sha256 │ │ │ │ ├── dup02.elf.gz.sha256 │ │ │ │ ├── dup04.elf.gz.sha256 │ │ │ │ ├── dup05.elf.gz.sha256 │ │ │ │ ├── dup07.elf.gz.sha256 │ │ │ │ ├── dup201.elf.gz.sha256 │ │ │ │ ├── dup202.elf.gz.sha256 │ │ │ │ ├── dup203.elf.gz.sha256 │ │ │ │ ├── dup204.elf.gz.sha256 │ │ │ │ ├── dup206.elf.gz.sha256 │ │ │ │ ├── dup207.elf.gz.sha256 │ │ │ │ ├── dup3_01.elf.gz.sha256 │ │ │ │ ├── dup3_02.elf.gz.sha256 │ │ │ │ ├── exit01.elf.gz.sha256 │ │ │ │ ├── exit02.elf.gz.sha256 │ │ │ │ ├── exit_group01.elf.gz.sha256 │ │ │ │ ├── fchdir01.elf.gz.sha256 │ │ │ │ ├── fchdir02.elf.gz.sha256 │ │ │ │ ├── fchmod01.elf.gz.sha256 │ │ │ │ ├── fchmod02.elf.gz.sha256 │ │ │ │ ├── fchmod04.elf.gz.sha256 │ │ │ │ ├── fchown01.elf.gz.sha256 │ │ │ │ ├── fchown02.elf.gz.sha256 │ │ │ │ ├── fchown05.elf.gz.sha256 │ │ │ │ ├── fchownat01.elf.gz.sha256 │ │ │ │ ├── fcntl01.elf.gz.sha256 │ │ │ │ ├── fcntl01_64.elf.gz.sha256 │ │ │ │ ├── fcntl02.elf.gz.sha256 │ │ │ │ ├── fcntl02_64.elf.gz.sha256 │ │ │ │ ├── fcntl03.elf.gz.sha256 │ │ │ │ ├── fcntl03_64.elf.gz.sha256 │ │ │ │ ├── fcntl04.elf.gz.sha256 │ │ │ │ ├── fcntl04_64.elf.gz.sha256 │ │ │ │ ├── fcntl08.elf.gz.sha256 │ │ │ │ ├── fcntl08_64.elf.gz.sha256 │ │ │ │ ├── fcntl09.elf.gz.sha256 │ │ │ │ ├── fcntl09_64.elf.gz.sha256 │ │ │ │ ├── fcntl10.elf.gz.sha256 │ │ │ │ ├── fcntl10_64.elf.gz.sha256 │ │ │ │ ├── fcntl11.elf.gz.sha256 │ │ │ │ ├── fcntl11_64.elf.gz.sha256 │ │ │ │ ├── fcntl14.elf.gz.sha256 │ │ │ │ ├── fcntl14_64.elf.gz.sha256 │ │ │ │ ├── fcntl15.elf.gz.sha256 │ │ │ │ ├── fcntl15_64.elf.gz.sha256 │ │ │ │ ├── fcntl16.elf.gz.sha256 │ │ │ │ ├── fcntl16_64.elf.gz.sha256 │ │ │ │ ├── fcntl17.elf.gz.sha256 │ │ │ │ ├── fcntl17_64.elf.gz.sha256 │ │ │ │ ├── fcntl19.elf.gz.sha256 │ │ │ │ ├── fcntl19_64.elf.gz.sha256 │ │ │ │ ├── fcntl20.elf.gz.sha256 │ │ │ │ ├── fcntl20_64.elf.gz.sha256 │ │ │ │ ├── fcntl21.elf.gz.sha256 │ │ │ │ ├── fcntl21_64.elf.gz.sha256 │ │ │ │ ├── fcntl22.elf.gz.sha256 │ │ │ │ ├── fcntl22_64.elf.gz.sha256 │ │ │ │ ├── fcntl27.elf.gz.sha256 │ │ │ │ ├── fcntl27_64.elf.gz.sha256 │ │ │ │ ├── fcntl28.elf.gz.sha256 │ │ │ │ ├── fcntl28_64.elf.gz.sha256 │ │ │ │ ├── fcntl29.elf.gz.sha256 │ │ │ │ ├── fcntl29_64.elf.gz.sha256 │ │ │ │ ├── fdatasync01.elf.gz.sha256 │ │ │ │ ├── fdatasync02.elf.gz.sha256 │ │ │ │ ├── flock01.elf.gz.sha256 │ │ │ │ ├── flock02.elf.gz.sha256 │ │ │ │ ├── flock03.elf.gz.sha256 │ │ │ │ ├── flock04.elf.gz.sha256 │ │ │ │ ├── flock06.elf.gz.sha256 │ │ │ │ ├── fork01.elf.gz.sha256 │ │ │ │ ├── fork03.elf.gz.sha256 │ │ │ │ ├── fork04.elf.gz.sha256 │ │ │ │ ├── fork05.elf.gz.sha256 │ │ │ │ ├── fork06.elf.gz.sha256 │ │ │ │ ├── fork07.elf.gz.sha256 │ │ │ │ ├── fork08.elf.gz.sha256 │ │ │ │ ├── fork09.elf.gz.sha256 │ │ │ │ ├── fork10.elf.gz.sha256 │ │ │ │ ├── fork11.elf.gz.sha256 │ │ │ │ ├── fstat02.elf.gz.sha256 │ │ │ │ ├── fsync02.elf.gz.sha256 │ │ │ │ ├── fsync03.elf.gz.sha256 │ │ │ │ ├── ftruncate01.elf.gz.sha256 │ │ │ │ ├── ftruncate01_64.elf.gz.sha256 │ │ │ │ ├── ftruncate03.elf.gz.sha256 │ │ │ │ ├── ftruncate03_64.elf.gz.sha256 │ │ │ │ ├── futex_wait01.elf.gz.sha256 │ │ │ │ ├── futex_wait02.elf.gz.sha256 │ │ │ │ ├── futex_wait04.elf.gz.sha256 │ │ │ │ ├── futex_wait05.elf.gz.sha256 │ │ │ │ ├── futex_wake01.elf.gz.sha256 │ │ │ │ ├── futex_wake04.elf.gz.sha256 │ │ │ │ ├── getcwd02.elf.gz.sha256 │ │ │ │ ├── getcwd03.elf.gz.sha256 │ │ │ │ ├── getcwd04.elf.gz.sha256 │ │ │ │ ├── getdents01.elf.gz.sha256 │ │ │ │ ├── getdomainname01.elf.gz.sha256 │ │ │ │ ├── getegid01.elf.gz.sha256 │ │ │ │ ├── getegid02.elf.gz.sha256 │ │ │ │ ├── geteuid01.elf.gz.sha256 │ │ │ │ ├── geteuid02.elf.gz.sha256 │ │ │ │ ├── getgid01.elf.gz.sha256 │ │ │ │ ├── getgid03.elf.gz.sha256 │ │ │ │ ├── getgroups03.elf.gz.sha256 │ │ │ │ ├── gethostname01.elf.gz.sha256 │ │ │ │ ├── getitimer01.elf.gz.sha256 │ │ │ │ ├── getpagesize01.elf.gz.sha256 │ │ │ │ ├── getpgid01.elf.gz.sha256 │ │ │ │ ├── getpgid02.elf.gz.sha256 │ │ │ │ ├── getpgrp01.elf.gz.sha256 │ │ │ │ ├── getpid01.elf.gz.sha256 │ │ │ │ ├── getpid02.elf.gz.sha256 │ │ │ │ ├── getppid01.elf.gz.sha256 │ │ │ │ ├── getppid02.elf.gz.sha256 │ │ │ │ ├── getpriority02.elf.gz.sha256 │ │ │ │ ├── getrandom02.elf.gz.sha256 │ │ │ │ ├── getrandom03.elf.gz.sha256 │ │ │ │ ├── getrandom04.elf.gz.sha256 │ │ │ │ ├── getrlimit01.elf.gz.sha256 │ │ │ │ ├── getrlimit02.elf.gz.sha256 │ │ │ │ ├── getrlimit03.elf.gz.sha256 │ │ │ │ ├── getrusage01.elf.gz.sha256 │ │ │ │ ├── getsid01.elf.gz.sha256 │ │ │ │ ├── getsid02.elf.gz.sha256 │ │ │ │ ├── gettid01.elf.gz.sha256 │ │ │ │ ├── gettimeofday01.elf.gz.sha256 │ │ │ │ ├── gettimeofday02.elf.gz.sha256 │ │ │ │ ├── getuid01.elf.gz.sha256 │ │ │ │ ├── getuid03.elf.gz.sha256 │ │ │ │ ├── growfiles.elf.gz.sha256 │ │ │ │ ├── hackbench.elf.gz.sha256 │ │ │ │ ├── hugemmap06.elf.gz.sha256 │ │ │ │ ├── in6_01.elf.gz.sha256 │ │ │ │ ├── inode01.elf.gz.sha256 │ │ │ │ ├── inode02.elf.gz.sha256 │ │ │ │ ├── kill02.elf.gz.sha256 │ │ │ │ ├── kill03.elf.gz.sha256 │ │ │ │ ├── kill06.elf.gz.sha256 │ │ │ │ ├── kill08.elf.gz.sha256 │ │ │ │ ├── kill09.elf.gz.sha256 │ │ │ │ ├── link02.elf.gz.sha256 │ │ │ │ ├── link03.elf.gz.sha256 │ │ │ │ ├── link05.elf.gz.sha256 │ │ │ │ ├── linkat01.elf.gz.sha256 │ │ │ │ ├── listen01.elf.gz.sha256 │ │ │ │ ├── llseek01.elf.gz.sha256 │ │ │ │ ├── llseek02.elf.gz.sha256 │ │ │ │ ├── llseek03.elf.gz.sha256 │ │ │ │ ├── locktests.elf.gz.sha256 │ │ │ │ ├── lseek01.elf.gz.sha256 │ │ │ │ ├── lseek02.elf.gz.sha256 │ │ │ │ ├── lseek07.elf.gz.sha256 │ │ │ │ ├── mkdir05.elf.gz.sha256 │ │ │ │ ├── mmap-corruption01.elf.gz.sha256 │ │ │ │ ├── mmap001.elf.gz.sha256 │ │ │ │ ├── mmap01.elf.gz.sha256 │ │ │ │ ├── mmap02.elf.gz.sha256 │ │ │ │ ├── mmap03.elf.gz.sha256 │ │ │ │ ├── mmap04.elf.gz.sha256 │ │ │ │ ├── mmap05.elf.gz.sha256 │ │ │ │ ├── mmap06.elf.gz.sha256 │ │ │ │ ├── mmap07.elf.gz.sha256 │ │ │ │ ├── mmap08.elf.gz.sha256 │ │ │ │ ├── mmap09.elf.gz.sha256 │ │ │ │ ├── mmap10.elf.gz.sha256 │ │ │ │ ├── mmap11.elf.gz.sha256 │ │ │ │ ├── mmap12.elf.gz.sha256 │ │ │ │ ├── mmap19.elf.gz.sha256 │ │ │ │ ├── mmapstress01.elf.gz.sha256 │ │ │ │ ├── mmapstress04.elf.gz.sha256 │ │ │ │ ├── mprotect02.elf.gz.sha256 │ │ │ │ ├── mprotect03.elf.gz.sha256 │ │ │ │ ├── msync01.elf.gz.sha256 │ │ │ │ ├── msync02.elf.gz.sha256 │ │ │ │ ├── munmap01.elf.gz.sha256 │ │ │ │ ├── munmap02.elf.gz.sha256 │ │ │ │ ├── munmap03.elf.gz.sha256 │ │ │ │ ├── nanosleep01.elf.gz.sha256 │ │ │ │ ├── nanosleep02.elf.gz.sha256 │ │ │ │ ├── nanosleep04.elf.gz.sha256 │ │ │ │ ├── nice04.elf.gz.sha256 │ │ │ │ ├── open01.elf.gz.sha256 │ │ │ │ ├── open03.elf.gz.sha256 │ │ │ │ ├── open04.elf.gz.sha256 │ │ │ │ ├── open06.elf.gz.sha256 │ │ │ │ ├── open09.elf.gz.sha256 │ │ │ │ ├── open11.elf.gz.sha256 │ │ │ │ ├── open14.elf.gz.sha256 │ │ │ │ ├── openat03.elf.gz.sha256 │ │ │ │ ├── pause01.elf.gz.sha256 │ │ │ │ ├── pause02.elf.gz.sha256 │ │ │ │ ├── pause03.elf.gz.sha256 │ │ │ │ ├── pipe01.elf.gz.sha256 │ │ │ │ ├── pipe02.elf.gz.sha256 │ │ │ │ ├── pipe03.elf.gz.sha256 │ │ │ │ ├── pipe04.elf.gz.sha256 │ │ │ │ ├── pipe06.elf.gz.sha256 │ │ │ │ ├── pipe07.elf.gz.sha256 │ │ │ │ ├── pipe08.elf.gz.sha256 │ │ │ │ ├── pipe09.elf.gz.sha256 │ │ │ │ ├── pipe10.elf.gz.sha256 │ │ │ │ ├── pipe11.elf.gz.sha256 │ │ │ │ ├── pipe13.elf.gz.sha256 │ │ │ │ ├── poll01.elf.gz.sha256 │ │ │ │ ├── poll02.elf.gz.sha256 │ │ │ │ ├── pread01.elf.gz.sha256 │ │ │ │ ├── pread01_64.elf.gz.sha256 │ │ │ │ ├── pread02.elf.gz.sha256 │ │ │ │ ├── pread02_64.elf.gz.sha256 │ │ │ │ ├── preadv01.elf.gz.sha256 │ │ │ │ ├── preadv01_64.elf.gz.sha256 │ │ │ │ ├── pselect02.elf.gz.sha256 │ │ │ │ ├── pselect02_64.elf.gz.sha256 │ │ │ │ ├── pselect03.elf.gz.sha256 │ │ │ │ ├── pselect03_64.elf.gz.sha256 │ │ │ │ ├── pty06.elf.gz.sha256 │ │ │ │ ├── pwrite01_64.elf.gz.sha256 │ │ │ │ ├── pwrite02.elf.gz.sha256 │ │ │ │ ├── pwrite02_64.elf.gz.sha256 │ │ │ │ ├── pwrite03.elf.gz.sha256 │ │ │ │ ├── pwrite03_64.elf.gz.sha256 │ │ │ │ ├── pwrite04.elf.gz.sha256 │ │ │ │ ├── pwrite04_64.elf.gz.sha256 │ │ │ │ ├── pwritev01.elf.gz.sha256 │ │ │ │ ├── pwritev01_64.elf.gz.sha256 │ │ │ │ ├── read01.elf.gz.sha256 │ │ │ │ ├── read03.elf.gz.sha256 │ │ │ │ ├── read04.elf.gz.sha256 │ │ │ │ ├── readdir01.elf.gz.sha256 │ │ │ │ ├── readlink01.elf.gz.sha256 │ │ │ │ ├── readv01.elf.gz.sha256 │ │ │ │ ├── recvmsg02.elf.gz.sha256 │ │ │ │ ├── rename09.elf.gz.sha256 │ │ │ │ ├── rename14.elf.gz.sha256 │ │ │ │ ├── rmdir01.elf.gz.sha256 │ │ │ │ ├── sbrk02.elf.gz.sha256 │ │ │ │ ├── sendto01.elf.gz.sha256 │ │ │ │ ├── set_robust_list01.elf.gz.sha256 │ │ │ │ ├── set_tid_address01.elf.gz.sha256 │ │ │ │ ├── setegid02.elf.gz.sha256 │ │ │ │ ├── setgroups01.elf.gz.sha256 │ │ │ │ ├── setgroups02.elf.gz.sha256 │ │ │ │ ├── setgroups04.elf.gz.sha256 │ │ │ │ ├── setitimer02.elf.gz.sha256 │ │ │ │ ├── setpgid01.elf.gz.sha256 │ │ │ │ ├── setpgid02.elf.gz.sha256 │ │ │ │ ├── setpgrp01.elf.gz.sha256 │ │ │ │ ├── setpgrp02.elf.gz.sha256 │ │ │ │ ├── setpriority02.elf.gz.sha256 │ │ │ │ ├── setrlimit03.elf.gz.sha256 │ │ │ │ ├── setsid01.elf.gz.sha256 │ │ │ │ ├── setsockopt03.elf.gz.sha256 │ │ │ │ ├── sigaction02.elf.gz.sha256 │ │ │ │ ├── sigaltstack01.elf.gz.sha256 │ │ │ │ ├── sigaltstack02.elf.gz.sha256 │ │ │ │ ├── signal01.elf.gz.sha256 │ │ │ │ ├── signal02.elf.gz.sha256 │ │ │ │ ├── signal04.elf.gz.sha256 │ │ │ │ ├── signal06.elf.gz.sha256 │ │ │ │ ├── sigprocmask01.elf.gz.sha256 │ │ │ │ ├── socket02.elf.gz.sha256 │ │ │ │ ├── socketpair02.elf.gz.sha256 │ │ │ │ ├── stat01.elf.gz.sha256 │ │ │ │ ├── stat01_64.elf.gz.sha256 │ │ │ │ ├── stat02.elf.gz.sha256 │ │ │ │ ├── stat02_64.elf.gz.sha256 │ │ │ │ ├── symlink01.elf.gz.sha256 │ │ │ │ ├── symlink02.elf.gz.sha256 │ │ │ │ ├── symlink04.elf.gz.sha256 │ │ │ │ ├── symlinkat01.elf.gz.sha256 │ │ │ │ ├── tkill01.elf.gz.sha256 │ │ │ │ ├── tkill02.elf.gz.sha256 │ │ │ │ ├── truncate02.elf.gz.sha256 │ │ │ │ ├── truncate02_64.elf.gz.sha256 │ │ │ │ ├── unlink05.elf.gz.sha256 │ │ │ │ ├── unlink08.elf.gz.sha256 │ │ │ │ ├── wait01.elf.gz.sha256 │ │ │ │ ├── wait02.elf.gz.sha256 │ │ │ │ ├── wait401.elf.gz.sha256 │ │ │ │ ├── wait402.elf.gz.sha256 │ │ │ │ ├── wait403.elf.gz.sha256 │ │ │ │ ├── waitpid01.elf.gz.sha256 │ │ │ │ ├── waitpid02.elf.gz.sha256 │ │ │ │ ├── waitpid03.elf.gz.sha256 │ │ │ │ ├── waitpid06.elf.gz.sha256 │ │ │ │ ├── waitpid07.elf.gz.sha256 │ │ │ │ ├── waitpid08.elf.gz.sha256 │ │ │ │ ├── waitpid09.elf.gz.sha256 │ │ │ │ ├── waitpid10.elf.gz.sha256 │ │ │ │ ├── waitpid11.elf.gz.sha256 │ │ │ │ ├── waitpid12.elf.gz.sha256 │ │ │ │ ├── waitpid13.elf.gz.sha256 │ │ │ │ ├── write01.elf.gz.sha256 │ │ │ │ ├── write02.elf.gz.sha256 │ │ │ │ ├── write04.elf.gz.sha256 │ │ │ │ ├── write06.elf.gz.sha256 │ │ │ │ ├── writev02.elf.gz.sha256 │ │ │ │ ├── writev05.elf.gz.sha256 │ │ │ │ └── writev06.elf.gz.sha256 │ │ │ ├── 2/ │ │ │ │ ├── access02.elf.gz.sha256 │ │ │ │ ├── bind02.elf.gz.sha256 │ │ │ │ ├── brk01.elf.gz.sha256 │ │ │ │ ├── brk02.elf.gz.sha256 │ │ │ │ ├── chdir04.elf.gz.sha256 │ │ │ │ ├── connect01.elf.gz.sha256 │ │ │ │ ├── dup03.elf.gz.sha256 │ │ │ │ ├── dup06.elf.gz.sha256 │ │ │ │ ├── dup205.elf.gz.sha256 │ │ │ │ ├── futex_wait03.elf.gz.sha256 │ │ │ │ ├── futimesat01.elf.gz.sha256 │ │ │ │ ├── getdents02.elf.gz.sha256 │ │ │ │ ├── getrandom01.elf.gz.sha256 │ │ │ │ ├── getrandom04.elf.gz.sha256 │ │ │ │ ├── hackbench.elf.gz.sha256 │ │ │ │ ├── mmap2.elf.gz.sha256 │ │ │ │ ├── open02.elf.gz.sha256 │ │ │ │ ├── open07.elf.gz.sha256 │ │ │ │ ├── open08.elf.gz.sha256 │ │ │ │ ├── open10.elf.gz.sha256 │ │ │ │ ├── openat01.elf.gz.sha256 │ │ │ │ ├── openfile.elf.gz.sha256 │ │ │ │ ├── pwrite01.elf.gz.sha256 │ │ │ │ ├── read02.elf.gz.sha256 │ │ │ │ ├── readlink03.elf.gz.sha256 │ │ │ │ ├── readlinkat01.elf.gz.sha256 │ │ │ │ ├── readlinkat02.elf.gz.sha256 │ │ │ │ ├── readv02.elf.gz.sha256 │ │ │ │ ├── realpath01.elf.gz.sha256 │ │ │ │ ├── recvfrom01.elf.gz.sha256 │ │ │ │ ├── recvmmsg01.elf.gz.sha256 │ │ │ │ ├── rt_sigaction02.elf.gz.sha256 │ │ │ │ ├── rt_sigaction03.elf.gz.sha256 │ │ │ │ ├── rt_sigprocmask02.elf.gz.sha256 │ │ │ │ ├── sched_yield01.elf.gz.sha256 │ │ │ │ ├── select01.elf.gz.sha256 │ │ │ │ ├── select02.elf.gz.sha256 │ │ │ │ ├── select04.elf.gz.sha256 │ │ │ │ ├── send01.elf.gz.sha256 │ │ │ │ ├── sendfile02.elf.gz.sha256 │ │ │ │ ├── sendfile03.elf.gz.sha256 │ │ │ │ ├── sendfile04.elf.gz.sha256 │ │ │ │ ├── sendfile05.elf.gz.sha256 │ │ │ │ ├── sendfile06.elf.gz.sha256 │ │ │ │ ├── sendfile07.elf.gz.sha256 │ │ │ │ ├── sendfile08.elf.gz.sha256 │ │ │ │ ├── sendfile09.elf.gz.sha256 │ │ │ │ ├── sendmmsg01.elf.gz.sha256 │ │ │ │ ├── sendmmsg02.elf.gz.sha256 │ │ │ │ ├── sigaction01.elf.gz.sha256 │ │ │ │ ├── sigsuspend01.elf.gz.sha256 │ │ │ │ ├── socket01.elf.gz.sha256 │ │ │ │ ├── socketpair01.elf.gz.sha256 │ │ │ │ ├── stat03.elf.gz.sha256 │ │ │ │ ├── symlink05.elf.gz.sha256 │ │ │ │ ├── unlink07.elf.gz.sha256 │ │ │ │ ├── unlinkat01.elf.gz.sha256 │ │ │ │ ├── waitpid04.elf.gz.sha256 │ │ │ │ ├── write03.elf.gz.sha256 │ │ │ │ ├── write05.elf.gz.sha256 │ │ │ │ ├── writetest.elf.gz.sha256 │ │ │ │ ├── writev01.elf.gz.sha256 │ │ │ │ └── writev07.elf.gz.sha256 │ │ │ └── 3/ │ │ │ ├── epoll-ltp.elf.gz.sha256 │ │ │ ├── epoll_create01.elf.gz.sha256 │ │ │ ├── epoll_create02.elf.gz.sha256 │ │ │ ├── epoll_create1_01.elf.gz.sha256 │ │ │ ├── epoll_create1_02.elf.gz.sha256 │ │ │ ├── epoll_ctl01.elf.gz.sha256 │ │ │ ├── epoll_ctl02.elf.gz.sha256 │ │ │ ├── epoll_ctl03.elf.gz.sha256 │ │ │ ├── epoll_ctl04.elf.gz.sha256 │ │ │ ├── epoll_ctl05.elf.gz.sha256 │ │ │ ├── epoll_pwait01.elf.gz.sha256 │ │ │ ├── epoll_pwait02.elf.gz.sha256 │ │ │ ├── epoll_pwait03.elf.gz.sha256 │ │ │ ├── epoll_pwait04.elf.gz.sha256 │ │ │ ├── epoll_pwait05.elf.gz.sha256 │ │ │ ├── epoll_wait01.elf.gz.sha256 │ │ │ ├── epoll_wait02.elf.gz.sha256 │ │ │ ├── epoll_wait03.elf.gz.sha256 │ │ │ ├── epoll_wait04.elf.gz.sha256 │ │ │ ├── recvmmsg01.elf.gz.sha256 │ │ │ └── sendmsg01.elf.gz.sha256 │ │ ├── cpuinfo │ │ ├── deploy-ltp │ │ ├── ltp.mk │ │ └── meminfo │ ├── musl/ │ │ ├── README.md │ │ ├── lib/ │ │ │ └── 1/ │ │ │ └── ld-musl-x86_64.so.1.gz.sha256 │ │ └── musl.mk │ ├── qemu/ │ │ ├── 4/ │ │ │ ├── qemu-aarch64.gz.sha256 │ │ │ ├── qemu-aarch64_be.gz.sha256 │ │ │ ├── qemu-alpha.gz.sha256 │ │ │ ├── qemu-arm.gz.sha256 │ │ │ ├── qemu-armeb.gz.sha256 │ │ │ ├── qemu-cris.gz.sha256 │ │ │ ├── qemu-hexagon.gz.sha256 │ │ │ ├── qemu-hppa.gz.sha256 │ │ │ ├── qemu-i386.gz.sha256 │ │ │ ├── qemu-loongarch64.gz.sha256 │ │ │ ├── qemu-m68k.gz.sha256 │ │ │ ├── qemu-microblaze.gz.sha256 │ │ │ ├── qemu-microblazeel.gz.sha256 │ │ │ ├── qemu-mips.gz.sha256 │ │ │ ├── qemu-mips64.gz.sha256 │ │ │ ├── qemu-mips64el.gz.sha256 │ │ │ ├── qemu-mipsel.gz.sha256 │ │ │ ├── qemu-mipsn32.gz.sha256 │ │ │ ├── qemu-mipsn32el.gz.sha256 │ │ │ ├── qemu-nios2.gz.sha256 │ │ │ ├── qemu-or1k.gz.sha256 │ │ │ ├── qemu-ppc.gz.sha256 │ │ │ ├── qemu-ppc64.gz.sha256 │ │ │ ├── qemu-ppc64le.gz.sha256 │ │ │ ├── qemu-riscv32.gz.sha256 │ │ │ ├── qemu-riscv64.gz.sha256 │ │ │ ├── qemu-s390x.gz.sha256 │ │ │ ├── qemu-sh4.gz.sha256 │ │ │ ├── qemu-sh4eb.gz.sha256 │ │ │ ├── qemu-sparc.gz.sha256 │ │ │ ├── qemu-sparc32plus.gz.sha256 │ │ │ ├── qemu-sparc64.gz.sha256 │ │ │ ├── qemu-x86_64.gz.sha256 │ │ │ ├── qemu-xtensa.gz.sha256 │ │ │ └── qemu-xtensaeb.gz.sha256 │ │ ├── README.md │ │ └── qemu.mk │ ├── sectorlisp/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── brainfuck.bin.dbg │ │ ├── sectorlisp-friendly.bin.dbg │ │ └── sectorlisp.bin.dbg │ └── xterm.js/ │ ├── LICENSE │ └── xterm.css └── tool/ ├── config/ │ ├── clock_settime.c │ ├── config.mk │ ├── dev_urandom.c │ ├── dup3.c │ ├── epoll_pwait1.c │ ├── epoll_pwait2.c │ ├── f_getown_ex.c │ ├── fdatasync.c │ ├── fexecve.c │ ├── fork.c │ ├── getdomainname.c │ ├── getentropy.c │ ├── getrandom.c │ ├── kern_arnd.c │ ├── libunwind.c │ ├── lm.c │ ├── lrt.c │ ├── map_anonymous.c │ ├── map_shared.c │ ├── memccpy.c │ ├── mkfifo.c │ ├── mkfifoat.c │ ├── noop.c │ ├── pipe2.c │ ├── preadv.c │ ├── pthread.c │ ├── pthread_process_shared.c │ ├── pthread_setcancelstate.c │ ├── realpath.c │ ├── rtlgenrandom.c │ ├── sa_len.c │ ├── sched_getaffinity.c │ ├── sched_h.c │ ├── sched_yield.c │ ├── scm_credentials.c │ ├── seekdir.c │ ├── sendto_zero.c │ ├── setgroups.c │ ├── setresuid.c │ ├── setreuid.c │ ├── siocgifconf.c │ ├── sockatmark.c │ ├── stdatomic.c │ ├── strchrnul.c │ ├── struct_timezone.c │ ├── sync.c │ ├── sys_getentropy.c │ ├── sys_getrandom.c │ ├── sys_mount_h.c │ ├── sysctl.c │ ├── sysinfo.c │ ├── vasprintf.c │ ├── wait4.c │ ├── wcwidth.c │ └── zlib.c ├── dispatch.py ├── fastsize.sh ├── flock.c ├── release-cosmo.sh ├── release-linux.sh ├── sha256sum.c ├── size.sh └── stdatomic/ └── stdatomic.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ --- BasedOnStyle: Google StatementMacros: - INITIALIZER AlignConsecutiveMacros: true AlignConsecutiveDeclarations: false AlwaysBreakBeforeMultilineStrings: false AllowShortFunctionsOnASingleLine: false KeepEmptyLinesAtTheStartOfBlocks: true ConstructorInitializerAllOnOneLineOrOnePerLine: true --- Language: Cpp AllowShortFunctionsOnASingleLine: false --- Language: Proto ... ================================================ FILE: .gitattributes ================================================ # -*- conf -*- *.xz binary *.com binary *.elf binary /configure text eol=lf ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [jart] ================================================ FILE: .github/workflows/cygwin.yml ================================================ name: Build with Cygwin on: push: branches: - "master" - "flake" - "ga" pull_request: branches: - "master" # run workflow manually from the Actions tab workflow_dispatch: jobs: build: runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Install cached Cygwin id: cache uses: actions/cache@v3 with: path: C:\tools\cygwin key: 'cygwin' - name: Install Cygwin if: steps.cache.outputs.cache-hit != 'true' uses: egor-tensin/setup-cygwin@v4.0.1 with: packages: gcc-core make chere - name: make matrix run: | cd "$GITHUB_WORKSPACE" ./configure cat config.log make -j$(nproc) check o//test/blink shell: C:\tools\cygwin\bin\bash.exe --login --norc -eo pipefail -o igncr '{0}' - name: Test with VFS enabled run: | cd "$GITHUB_WORKSPACE" ./configure --enable-vfs cat config.log export BLINK_PREFIX="o" make -j$(nproc) check o//test/blink shell: C:\tools\cygwin\bin\bash.exe --login --norc -eo pipefail -o igncr '{0}' ================================================ FILE: .gitignore ================================================ # -*- conf -*- *.gz *.xz *.elf *.so *.so.1 blink.log /o /core* /TAGS /HTAGS /config.h /config.mk /config.log /*.dump /gmon.out /perf.data /perf.data.old /third_party/cosmo/**/*.com /third_party/cosmo/**/*.dbg ================================================ FILE: LICENSE ================================================ ISC License Copyright 2022 Justine Alexandra Roberts Tunney Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: Makefile ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ SHELL = /bin/sh MAKEFLAGS += --no-builtin-rules ARCHITECTURES = x86_64 x86_64-gcc49 i486 aarch64 arm mips s390x mipsel mips64 mips64el powerpc powerpc64le .SUFFIXES: .DELETE_ON_ERROR: .FEATURES: output-sync .PHONY: o all clean check check2 test tags format install ifeq ($(MAKE_VERSION), 3.81) $(error please "brew install make" and use the "gmake" command) endif ifneq ($(shell echo -e "4.0\n$(MAKE_VERSION)" | sort -ct. -k1,1n -k2,2n 2>/dev/null && echo YES), YES) $(error please use GNU Make 4.0 or newer) endif ifeq ($(wildcard config.h),) $(error ./configure needs to be run, use ./configure --help for help) endif include config.mk CONFIG_COMMAND ?= ./configure ifneq ($(CONFIG_HOSTNAME), $(shell hostname)) undefine CC undefine AR undefine TMPDIR undefine CFLAGS undefine LDFLAGS undefine UOPFLAGS undefine CPPFLAGS undefine TARGET_ARCH $(shell $(CONFIG_COMMAND)) $(error please run $(MAKE) again) endif ifneq ($(m),) ifeq ($(MODE),) MODE := $(m) endif endif ifneq ($(HOST_SYSTEM), Linux) VM = o/$(MODE)/blink/blink endif ifneq ($(HOST_ARCH), x86_64) VM = o/$(MODE)/blink/blink endif o: o/ok o/ok: o/$(MODE)/blink touch $@ @echo "" @echo "Your Blink Virtual Machine successfully compiled:" @echo "" @echo " o/$(MODE)/blink/blink" @echo " o/$(MODE)/blink/blinkenlights" @echo "" @echo "You may also want to run:" @echo "" @echo " make check" @echo " doas make install" @echo "" test: o/$(MODE)/blink \ o/$(MODE)/test format: clang-format -i -style=file blink/*.c blink/*.h check: test \ o/$(MODE)/third_party/cosmo \ o/$(MODE)/third_party/libc-test \ o/$(MODE)/test/metal \ o/$(MODE)/test/metalrom check2: o/$(MODE)/test/sse \ o/$(MODE)/test/lib \ o/$(MODE)/test/sys \ o/$(MODE)/test/func \ o/$(MODE)/test/asm \ o/$(MODE)/third_party/ltp \ o/$(MODE)/test/asm/emulates \ o/$(MODE)/test/func/emulates emulates: \ o/$(MODE)/test/asm \ o/$(MODE)/test/flat \ o/$(MODE)/third_party/ltp/medium \ o/$(MODE)/third_party/cosmo/emulates tags: TAGS HTAGS include build/config.mk include build/rules.mk include third_party/libz/zlib.mk include blink/blink.mk include test/test.mk include test/asm/asm.mk include test/func/func.mk include test/flat/flat.mk include test/blink/test.mk include test/metal/metal.mk include test/metalrom/metalrom.mk include tool/config/config.mk include third_party/gcc/gcc.mk include third_party/ltp/ltp.mk include third_party/musl/musl.mk include third_party/qemu/qemu.mk include third_party/cosmo/cosmo.mk include third_party/libc-test/libc-test.mk BUILD_TOOLCHAIN := -DBUILD_TOOLCHAIN="\"$(shell $(CC) --version | head -n1 | sed s/\ / /g)\"" BUILD_TIMESTAMP := -DBUILD_TIMESTAMP="\"$(shell LC_ALL=C TZ=UTC date +"%a %b %e %T %Z %Y" | sed s/\ / /g)\"" BLINK_COMMITS := -DBLINK_COMMITS="\"$(shell git rev-list HEAD --count 2>/dev/null)\"" BLINK_GITSHA := -DBLINK_GITSHA="\"$(shell git rev-parse --verify HEAD 2>/dev/null)\"" CONFIG_CPPFLAGS = \ $(CONFIG_ARGUMENTS) \ $(BUILD_TOOLCHAIN) \ $(BUILD_TIMESTAMP) \ $(BLINK_COMMITS) \ $(BLINK_UNAME_V) \ $(BLINK_GITSHA) \ -DBUILD_MODE="\"$(MODE)\"" OBJS = $(foreach x,$(PKGS),$($(x)_OBJS)) SRCS := $(foreach x,$(PKGS),$($(x)_SRCS)) HDRS := $(foreach x,$(PKGS),$($(x)_HDRS)) INCS = $(foreach x,$(PKGS),$($(x)_INCS)) BINS = $(foreach x,$(PKGS),$($(x)_BINS)) TESTS = $(foreach x,$(PKGS),$($(x)_TESTS)) CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS)) o/$(MODE)/.x: @mkdir -p $(@D) @touch $@ o/tool/sha256sum: tool/sha256sum.c @mkdir -p $(@D) $(CC) -w -O2 -o $@ $< o/$(MODE)/tool/sha256sum.o: tool/sha256sum.c @mkdir -p $(@D) clang++ -Wall -Wextra -Werror -pedantic -O2 -xc++ -c -o $@ $< g++ -Wall -Wextra -Werror -pedantic -O2 -xc++ -c -o $@ $< clang -Wall -Wextra -Werror -pedantic -O2 -c -o $@ $< gcc -Wall -Wextra -Werror -pedantic -O2 -c -o $@ $< o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(SRCS) $(call uniq,$(foreach x,$(SRCS),$(dir $(x)))) $(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x))) o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(HDRS) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x)))) $(file >$@) $(foreach x,blink/types.h $(HDRS) $(INCS),$(file >>$@,$(x))) MAKEFILES = \ Makefile \ build/config.mk \ build/rules.mk \ blink/blink.mk \ third_party/libz/zlib.mk $(OBJS): $(MAKEFILES) DEPENDS = \ o/$(MODE)/depend.host \ o/$(MODE)/depend.i486 \ o/$(MODE)/depend.m68k \ o/$(MODE)/depend.x86_64 \ o/$(MODE)/depend.x86_64-gcc49 \ o/$(MODE)/depend.arm \ o/$(MODE)/depend.aarch64 \ o/$(MODE)/depend.riscv64 \ o/$(MODE)/depend.mips \ o/$(MODE)/depend.mipsel \ o/$(MODE)/depend.mips64 \ o/$(MODE)/depend.mips64el \ o/$(MODE)/depend.s390x \ o/$(MODE)/depend.microblaze \ o/$(MODE)/depend.powerpc \ o/$(MODE)/depend.powerpc64le o/$(MODE)/depend: $(DEPENDS) cat $^ >$@ o/$(MODE)/depend.host: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.i486: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/i486/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.m68k: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/m68k/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.x86_64: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/x86_64/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.x86_64-gcc49: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/x86_64-gcc49/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.arm: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/arm/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.aarch64: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/aarch64/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.riscv64: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/riscv64/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.mips: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/mips/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.mipsel: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/mipsel/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.mips64: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/mips64/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.mips64el: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/mips64el/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.s390x: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/s390x/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.microblaze: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/microblaze/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.powerpc: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/powerpc/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null o/$(MODE)/depend.powerpc64le: o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(VM) build/bootstrap/mkdeps.com -o $@ -r o/$(MODE)/powerpc64le/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt 2>/dev/null TAGS: o/$(MODE)/srcs.txt $(SRCS) $(RM) $@ $(TAGS) $(TAGSFLAGS) -L $< -o $@ HTAGS: o/$(MODE)/hdrs.txt $(HDRS) $(RM) $@ build/htags -L $< -o $@ $(OBJS): config.h config.h: configure $(CONFIG_COMMAND) install: mkdir -p $(PREFIX)/bin install -m 0755 o//blink/blink $(PREFIX)/bin/blink install -m 0755 o//blink/blinkenlights $(PREFIX)/bin/blinkenlights mkdir -p $(PREFIX)/share/man/man1 install -m 0644 blink/blink.1 $(PREFIX)/share/man/man1/blink.1 install -m 0644 blink/blinkenlights.1 $(PREFIX)/share/man/man1/blinkenlights.1 clean: rm -f $(OBJS) o/$(MODE)/blink/blink o/$(MODE)/blink/blinkenlights o/$(MODE)/blink/blink.a o/$(MODE)/third_party/libz/zlib.a distclean: rm -rf o rm -f config.h TAGS HTAGS *.dump gmon.out perf.data perf.data.old rm -f $(find third_party -name \*.elf) rm -f $(find third_party -name \*.com) rm -f $(find third_party -name \*.dbg) rm -f $(find third_party -name \*.so.1) rm -f $(find third_party -name \*.so) rm -f $(find third_party -name \*.gz) rm -f $(find third_party -name \*.xz) $(SRCS): $(HDRS): $(INCS): .DEFAULT: @echo >&2 @echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2 @echo >&2 rm -f o/$(MODE)/depend $(DEPENDS) -include o/$(MODE)/depend ================================================ FILE: README.md ================================================ ![Screenshot of Blink running GCC 9.4.0](blink/blink-gcc.png) # Blinkenlights This project contains two programs: `blink` is a virtual machine that runs x86-64-linux programs on different operating systems and hardware architectures. It's designed to do the same thing as the `qemu-x86_64` command, except that 1. Blink is 221kb in size (115kb with optional features disabled), whereas qemu-x86_64 is a 4mb binary. 2. Blink will run your Linux binaries on any POSIX system, whereas qemu-x86_64 only supports Linux. 3. Blink goes 2x faster than qemu-x86_64 on some benchmarks, such as SSE integer / floating point math. Blink is also much faster at running ephemeral programs such as compilers. [`blinkenlights`](https://justine.lol/blinkenlights) is a terminal user interface that may be used for debugging x86_64-linux or i8086 programs across platforms. Unlike GDB, Blinkenlights focuses on visualizing program execution. It uses UNICODE IBM Code Page 437 characters to display binary memory panels, which change as you step through your program's assembly code. These memory panels may be scrolled and zoomed using your mouse wheel. Blinkenlights also permits reverse debugging, where scroll wheeling over the assembly display allows the rewinding of execution history. ## Getting Started We regularly test that Blink is able run x86-64-linux binaries on the following platforms: - Linux (x86, ARM, RISC-V, MIPS, PowerPC, s390x) - macOS (x86, ARM) - FreeBSD - OpenBSD - Cygwin Blink depends on the following libraries: - libc (POSIX.1-2017 with XSI extensions) Blink can be compiled on UNIX systems that have: - A C11 compiler with atomics (e.g. GCC 4.9.4+) - Modern GNU Make (i.e. not the one that comes with XCode) The instructions for compiling Blink are as follows: ```sh ./configure make -j4 doas make install # note: doas is modern sudo blink -v man blink ``` Here's how you can run a simple hello world program with Blink: ```sh blink third_party/cosmo/tinyhello.elf ``` Blink has a debugger TUI, which works with UTF-8 ANSI terminals. The most important keystrokes in this interface are `?` for help, `s` for step, `c` for continue, and scroll wheel for reverse debugging. ```sh blinkenlights third_party/cosmo/tinyhello.elf ``` ### Alternative Builds For maximum tinyness, use `MODE=tiny`, since it makes Blink's binary footprint 50% smaller. The Blink executable should be on the order of 200kb in size. Performance isn't impacted. Please note that all assertions will be removed, as well as all logging. Use this mode if you're confident that Blink is bug-free for your use case. ```sh make MODE=tiny strip o/tiny/blink/blink ls -hal o/tiny/blink/blink ``` Some distros configure their compilers to add a lot of security bloat, which might add 60kb or more to the above binary size. You can work around that by using one of Blink's toolchains. This should produce consistently the smallest possible executable size. ```sh make MODE=tiny o/tiny/x86_64/blink/blink o/third_party/gcc/x86_64/bin/x86_64-linux-musl-strip o/tiny/x86_64/blink/blink ls -hal o/tiny/x86_64/blink/blink ``` If you want to make Blink *even tinier* (more on the order of 120kb rather than 200kb) than you can tune the `./configure` script to disable optional features such as jit, threads, sockets, x87, bcd, xsi, etc. ```sh ./configure --disable-all --posix make MODE=tiny o/tiny/x86_64/blink/blink o/third_party/gcc/x86_64/bin/x86_64-linux-musl-strip o/tiny/x86_64/blink/blink ls -hal o/tiny/x86_64/blink/blink ``` The traditional `MODE=rel` or `MODE=opt` modes are available. Use this mode if you're on a non-JIT architecture (since this won't improve performance on AMD64 and ARM64) and you're confident that Blink is bug-free for your use case, and would rather have Blink not create a `blink.log` or print `SIGSEGV` delivery warnings to standard error, since many apps implement their own crash reporting. ```sh make MODE=rel o/rel/blink/blink -h ``` You can hunt down bugs in Blink using the following build modes: - `MODE=asan` helps find memory safety bugs - `MODE=tsan` helps find threading related bugs - `MODE=ubsan` to find violations of the C standard - `MODE=msan` helps find uninitialized memory errors You can check Blink's compliance with the POSIX standard using the following configuration flags: ```sh ./configure --posix # only use c11 with posix xopen standard ``` If you want to run a full `chroot`'d Linux distro and require correct handling of absolute symlinks, displaying of certain values in `/proc`, and so on, and you don't mind paying a small price in terms of size and performance, you can enable the emulated VFS feature by using the following configuration: ```sh ./configure --enable-vfs ``` ### Testing Blink is tested primarily using precompiled binaries downloaded automatically. Blink has more than 700 test programs total. You can check how well Blink works on your local platform by running: ```sh make check ``` To check that Blink works on 11 different hardware `$(ARCHITECTURES)` (see [Makefile](Makefile)), you can run the following command, which will download statically-compiled builds of GCC and Qemu. Since our toolchain binaries are intended for x86-64 Linux, Blink will bootstrap itself locally first, so that it's possible to run these tests on other operating systems and architectures. ```sh make check2 make emulates ``` ### Production Worthiness Blink passes 194 test suites from the Cosmopolitan Libc project (see [third_party/cosmo](third_party/cosmo)). Blink passes 350 test suites from the [Linux Test Project](https://github.com/linux-test-project/ltp) (see [third_party/ltp](third_party/ltp)). Blink passes 108 of [Musl Libc's unit test suite](https://github.com/jart/libc-test) (see [third_party/libc-test](third_party/libc-test)). The tests we haven't included are because either (1) it wanted x87 long double to have 80-bit precision, or (2) it used Linux APIs we can't or won't support, e.g. System V message queues. Blink runs the precompiled Linux test binaries above on other operating systems too, e.g. Apple M1, FreeBSD, Cygwin. ## Reference The Blinkenlights project provides two programs which may be launched on the command line. ### `blink` Flags The headless Blinkenlights virtual machine command (named `blink` by convention) accepts command line arguments per the specification: ``` blink [FLAG...] PROGRAM [ARG...] ``` Where `PROGRAM` is an x86_64-linux binary that may be specified as: 1. An absolute path to an executable file, which will be run as-is 2. A relative path containing slashes, which will be run as-is 3. A path name without slashes, which will be `$PATH` searched The following `FLAG` arguments are provided: - `-h` shows help on command usage - `-v` shows version and build configuration details - `-e` means log to standard error (fd 2) in addition to the log file. If logging to *only* standard error is desired, then `-eL/dev/null` may be used. - `-j` disables Just-In-Time (JIT) compilation, which will make Blink go ~10x slower. - `-m` disables the linear memory optimization. This makes Blink memory safe, but comes at the cost of going ~4x slower. On some platforms this can help avoid the possibility of an mmap() crisis. - `-0` allows `argv[0]` to be specified on the command line. Under normal circumstances, `blink cmd arg1` is equivalent to `execve("cmd", {"cmd", "arg1"})` since that's how most programs are launched. However if you need the full power of execve() process spawning, you can say `blink -0 cmd arg0 arg1` which is equivalent to `execve("cmd", {"arg0", "arg1"})`. - `-L PATH` specifies the log path. The default log path is `blink.log` in the current directory at startup. This log file won't be created until something is actually logged. If logging to a file isn't desired, then `-L /dev/null` may be used. See also the `-e` flag for logging to standard error. - `-s` enables system call logging. This will emit to the log file the names of system calls each time a SYSCALL instruction in executed, along with its arguments and result. System calls are logged once they've completed. If this option is specified twice, then system calls which are likely to block (e.g. poll) will be logged at entry too. If this option is specified thrice, then all cancellation points will be logged upon entry. System call logging isn't available in `MODE=rel` and `MODE=tiny` builds, in which case this flag is ignored. - `-Z` will cause internal statistics to be printed to standard error on exit. Stats aren't available in `MODE=rel` and `MODE=tiny` builds, and this flag is ignored. - `-C path` will cause blink to launch the program in a chroot'd environment. This flag is both equivalent to and overrides the `BLINK_OVERLAYS` environment variable. Note: This flag works especially well if you use `./configure --enable-vfs`. ### `blinkenlights` Flags The Blinkenlights ANSI TUI interface command (named `blinkenlights` by convention) accepts its command line arguments in accordance with the following specification: ``` blinkenlights [FLAG...] PROGRAM [ARG...] ``` Where `PROGRAM` is an x86_64-linux binary that may be specified as: 1. An absolute path to an executable file, which will be run as-is 2. A relative path containing slashes, which will be run as-is 3. A path name without slashes, which will be `$PATH` searched The following `FLAG` arguments are provided: - `-h` shows help on command usage - `-v` shows version and build configuration details - `-r` puts your virtual machine in real mode. This may be used to run 16-bit i8086 programs, such as SectorLISP. It's also used for booting programs from Blinkenlights's simulated BIOS. - `-b ADDR` pushes a breakpoint, which may be specified as a raw hexadecimal address, or a symbolic name that's defined by your ELF binary (or its associated `.dbg` file). When pressing `c` (continue) or `C` (continue harder) in the TUI, Blink will immediately stop upon reaching an instruction that's listed as a breakpoint, after which a modal dialog is displayed. The modal dialog may be cleared by `ENTER` after which the TUI resumes its normal state. - `-w ADDR` pushes a watchpoint, which may be specified as a raw hexadecimal address, or a symbolic name that's defined by your ELF binary (or its associated `.dbg` file). When pressing `c` (continue) or `C` (continue harder) in the TUI, Blink will immediately stop upon reaching an instruction that either (a) has a ModR/M encoding that references an address that's listed as a watchpoint, or (b) manages to mutate the memory stored at a watchpoint address by some other means. When Blinkenlights is stopped at a watchpoint, a modal dialog will be displayed which may be cleared by pressing `ENTER`, after which the TUI resumes its normal state. - `-j` enables Just-In-Time (JIT) compilation. This will make Blinkenlights go significantly faster, at the cost of taking away the ability to step through each instruction. The TUI will visualize JIT path formation in the assembly display; see the JIT Path Glyphs section below to learn more. Please note this flag has the opposite meaning as it does in the `blink` command. - `-m` enables the linear memory optimization. This makes blinkenlights capable of faster emulation, at the cost of losing some statistics. It no longer becomes possible to display which percentage of a memory map has been activated. Blinkenlights will also remove the commit / reserve / free page statistics from the status panel on the bottom right of the display. Please note this flag has the opposite meaning as it does in the `blink` command. - `-t` may be used to disable Blinkenlights TUI mode. This makes the program behave similarly to the `blink` command, however not as good. We're currently using this flag for unit testing real mode programs, which are encouraged to use the `SYSCALL` instruction to report their exit status. - `-L PATH` specifies the log path. The default log path is `$TMPDIR/blink.log` or `/tmp/blink.log` if `$TMPDIR` isn't defined. - `-C path` will cause blink to launch the program in a chroot'd environment. This flag is both equivalent to and overrides the `BLINK_OVERLAYS` environment variable. - `-s` enables system call logging. This will emit to the log file the names of system calls each time a SYSCALL instruction in executed, along with its arguments and result. System calls are logged once they've completed. If this option is specified twice, then system calls which are likely to block (e.g. poll) will be logged at entry too. If this option is specified thrice, then all cancellation points will be logged upon entry. System call logging isn't available in `MODE=rel` and `MODE=tiny` builds, in which case this flag is ignored. - `-Z` will cause internal statistics to be printed to standard error on exit. Each line will display a monitoring metric. Most metrics will either be integer counters or floating point running averages. Most but not all integer counters are monotonic. In the interest of not negatively impacting Blink's performance, statistics are computed on a best effort basis which currently isn't guaranteed to be atomic in a multi-threaded environment. Stats aren't available in `MODE=rel` and `MODE=tiny` builds, and this flag is ignored. - `-z` [repeatable] may be specified to zoom the memory panels, so they display a larger amount of memory in a smaller space. By default, one terminal cell corresponds to a single byte of memory. When memory has been zoomed the magic kernel is used (similar to Lanczos) to decimate the number of bytes by half, for each `-z` that's specified. Normally this would be accomplished by using `CTRL+MOUSEWHEEL` where the mouse cursor is hovered over the panel that should be zoomed. However, many terminal emulators (especially on Windows), do not support this xterm feature and as such, this flag is provided as an alternative. - `-V` [repeatable] increases verbosity - `-R` disables reactive error mode - `-H` disables syntax highlighting - `-N` enables natural scrolling ### Recommended Environments Blinkenlights' TUI requires a UTF-8 VT100 / XTERM style terminal to use. We recommend the following terminals, ordered by preference: - [KiTTY](https://sw.kovidgoyal.net/kitty/) (Linux) - [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html) (Windows) - Gnome Terminal (Linux) - Terminal.app (macOS) - CMD.EXE (Windows 10+) - PowerShell (Windows 10+) - Xterm (Linux) The following fonts are recommended, ordered by preference: - [PragmataPro Regular Mono](https://fsd.it/shop/fonts/pragmatapro/) (€59) - Bitstream Vera Sans Mono (a.k.a. DejaVu Sans Mono) - Consolas - Menlo #### JIT Path Glyphs When the Blinkenlights TUI is run with JITing enabled (using the `-j` flag) the assembly dump display will display a glyph next to the address of each instruction, to indicate the status of JIT path formation. Those glyphs are defined as follows: - ` ` or space indicates no JIT path is associated with an address - `S` means that a JIT path is currently being constructed which starts at this address. By continuing to press `s` (step) in the TUI interface, the JIT path will grow longer until it is eventually completed, and the `S` glyph is replaced by `*`. - `*` (asterisk) means that a JIT path has been installed to the adjacent address. When `s` (step) is pressed at such addresses within the TUI display, stepping takes on a different meaning. Rather than stepping a single instruction, it will step the entire length of the JIT path. The next assembly line that'll be highlighted will be the instruction after where the path ends. ### Environment Variables The following environment variables are recognized by both the `blink` and `blinkenlights` commands: - `BLINK_LOG_FILENAME` may be specified to supply a log path to be used in cases where the `-L PATH` flag isn't specified. This value should be an absolute path. If logging to standard error is desired, use the `blink -e` flag. - `BLINK_OVERLAYS` specifies one or more directories to use as the root filesystem. Similar to `$PATH` this is a colon delimited list of pathnames. If relative paths are specified, they'll be resolved to an absolute path at startup time. Overlays only apply to IO system calls that specify an absolute path. The empty string overlay means use the normal `/` root filesystem. The default value is `:o`, which means if the absolute path `/$f` is opened, then first check if `/$f` exists, and if it doesn't, then check if `o/$f` exists, in which case open that instead. Blink uses this convention to open shared object tests. It favors the system version if it exists, but also downloads `ld-musl-x86_64.so.1` to `o/lib/ld-musl-x86_64.so.1` so the dynamic linker can transparently find it on platforms like Apple, that don't let users put files in the root folder. On the other hand, it's possible to say `BLINK_OVERLAYS=o:` so that `o/...` takes precedence over `/...` (noting again that empty string means root). If a single overlay is specified that isn't empty string, then it'll effectively act as a restricted chroot environment. ## Compiling and Running Programs under Blink Blink can be picky about which Linux binaries it'll execute. It may also be the case that your Linux binary will only run under Blink on Linux, but report errors if run under Blink on another platform, e.g. macOS. In our experience, how successfully a program can run under Blink depends almost entirely on (1) how it was compiled, and (2) which C library it uses. This section will provide guidance on which tools will work best. First, some background. Blink's coverage of the x86_64 instruction set is comprehensive. However the Linux system call ABI is much larger and therefore not possible to fully support, unless Blink emulated a Linux kernel image too. Blink has sought to support the subset of Linux ABIs that are either (1) standardized by POSIX.1-2017 or (2) too popular to *not* support. As an example, `AF_INET`, `AF_UNIX`, and `AF_INET6` are supported, but Blink will return `EINVAL` if a program requests any of the dozens of other ones, e.g. `AF_BLUETOOTH`. Such errors are usually logged to `/tmp/blink.log`, to make it easy to file a feature request. In other cases ABIs aren't supported simply because they're Linux-only and difficult to polyfill on other POSIX platforms. For example, Blink will polyfill `open(O_TMPFILE)` on non-Linux platforms so it works the same way, but other Linux-specific ABIs like `membarrier()` we haven't had the time to figure out yet. Since app developers usually don't use non-portable APIs, it's usually the platform C library that's at fault for calling them. Many Linux system calls, could be rightfully thought of as an implementation detail of Glibc. Blink's prime directive is to support binaries built with Cosmopolitan Libc. Actually Portable Executables make up the bulk of Blink's unit test suite. Anything created by Cosmopolitan is almost certainly going to work very well. Since Cosmopolitan is closely related to Musl Libc, programs compiled using Musl also tend to work very well. For example, Alpine Linux is a Musl Libc based distro, so their prebuilt dynamic binaries tend to all work well, and it's also a great platform to use for compiling other software from source that's intended for Blink. So the recommended approach is either: 1. Build your app using Cosmopolitan Libc, otherwise 2. Build your app using GNU Autotools on Alpine Linux 3. Build your app using Buildroot For Cosmopolitan, please read [Getting Started with Cosmopolitan Libc](https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/) for information on how to get started. Cosmopolitan comes with a lot of third party software included that you can try with Blink right away, e.g. SQLite, Python, QuickJS, and Antirez's Kilo editor. ``` git clone https://github.com/jart/cosmopolitan/ cd cosmopolitan make -j8 o//third_party/python/python.com blinkenlights -jm o//third_party/python/python.com make -j8 o//third_party/quickjs/qjs.com blinkenlights -jm o//third_party/quickjs/qjs.com make -j8 o//third_party/sqlite3/sqlite3.com blinkenlights -jm o//third_party/sqlite3/sqlite3.com make -j8 o//examples/kilo.com blinkenlights -jm o//examples/kilo.com ``` Blink is great for making single-file autonomous binaries like the above easily copyable across platforms. If you're more interested in building systems instead, then [Buildroot](https://buildroot.org/) is one way to create a Linux userspace that'll run under Blink. All you have to do is set the `$BLINK_OVERLAYS` environment variable to the buildroot target folder, which will ask Blink to create a chroot'd environment. ``` cd ~/buildroot export CC="gcc -Wl,-z,common-page-size=65536,-z,max-page-size=65536" make menuconfig make cp -R output/target ~/blinkroot doas mount -t devtmpfs none ~/blinkroot/dev doas mount -t sysfs none ~/blinkroot/sys doas mount -t proc none ~/blinkroot/proc cd ~/blink make -j8 export BLINK_OVERLAYS=$HOME/blinkroot blink sh uname -a Linux hostname 4.5 blink-1.0 x86_64 GNU/Linux ``` If you want to build an Autotools project like Emacs, the best way to do that is to spin up an Alpine Linux container and use [jart/blink-isystem](https://github.com/jart/blink-isystem) as your system header subset. blink-isystem is basically just the Musl Linux headers with all the problematic APIs commented out. That way autoconf won't think the APIs Blink doesn't have are available, and will instead configure Emacs to use portable alternatives. Setting this up is simple: ``` ./configure CFLAGS="-isystem $HOME/blink-isystem" \ CXXFLAGS="-isystem $HOME/blink-isystem" \ LDFLAGS="-static -Wl,-z,common-page-size=65536,-z,max-page-size=65536" make -j ``` Another big issue is the host system page size may cause problems on non-Linux platforms like Apple M1 (16kb) and Cygwin (64kb). On such platforms, you may encounter an error like this: ``` p_vaddr p_offset skew unequal w.r.t. host page size ``` The simplest way to solve that is by disabling the linear memory optimization (using the `blink -m` flag) but that'll slow down performance. Another option is to try recompiling your executable so that its ELF program headers will work on systems with a larger page size. You can do that using these GCC flags: ``` gcc -static -Wl,-z,common-page-size=65536,-z,max-page-size=65536 ... ``` However that's just step one. The program also needs to be using APIs like `sysconf(_SC_PAGESIZE)` which will return the true host page size, rather than naively assuming it's 4096 bytes. Your C library gets this information from Blink via `getauxval(AT_PAGESZ)`. If you're using the Blinkenlights debugger TUI, then another important set of flags to use are the following: - `-fno-omit-frame-pointer` - `-mno-omit-leaf-frame-pointer` By default, GCC and Clang use the `%rbp` backtrace pointer as a general purpose register, and as such, Blinkenlights won't be able to display a frames panel visualizing your call stack. Using those flags solves that. However it's tricky sometimes to correctly specify them in a complex build environment, where other optimization flags might subsequently turn them back off again. The trick we recommend using for compiling your programs, is to create a shell script that wraps your compiler command, and then use the script in your `$CC` environment variable. The script should look something like the following: ```sh #!/bin/sh set /usr/bin/gcc "$@" -g \ -fno-omit-frame-pointer \ -fno-optimize-sibling-calls \ -mno-omit-leaf-frame-pointer \ -Wl,-z,norelro \ -Wl,-z,noseparate-code \ -Wl,-z,max-page-size=65536 \ -Wl,-z,common-page-size=65536 printf '%s\n' "$*" >>/tmp/gcc.log exec "$@" ``` Those flags will go a long way towards helping your Linux binaries be (1) capable of running under Blink on all of its supported operating systems and microprocessor architectures, and (2) trading away some of the modern security blankets in the interest of making the assembly panel more readable, and less likely to be picky about memory. If you're a Cosmopolitan Libc user, then Cosmopolitan already provides such a script, which is the `cosmocc` and `cosmoc++` toolchain. Please note that Cosmopolitan Libc uses a 64kb page size so it isn't impacted by many of these issues that Glibc and Musl users may experience. - [cosmopolitan/tool/scripts/cosmocc](https://github.com/jart/cosmopolitan/blob/master/tool/scripts/cosmocc) - [cosmopolitan/tool/scripts/cosmoc++](https://github.com/jart/cosmopolitan/blob/master/tool/scripts/cosmoc%2B%2B) If you're not a C / C++ developer, and you prefer to use high-level languages instead, then one program you might consider emulating is Actually Portable Python, which is an APE build of the CPython v3.6 interpreter. It can be built from source, and then used as follows: ``` git clone https://github.com/jart/cosmopolitan/ cd cosmopolitan make -j8 o//third_party/python/python.com blinkenlights -jm o//third_party/python/python.com ``` The `-jm` flags are helpful here, since they ask the Blinkenlights TUI to enable JIT and the linear memory optimization. It's helpful to have those flags because Python is a very complicated and compute intensive program, that would otherwise move too slowly under the Blinkenlights vizualization. You may also want to press the `CTRL-T` (TURBO) key a few times, to make Python emulate in the TUI even faster. ## Technical Details blink is an x86-64 interpreter for POSIX platforms that's written in ANSI C11 that's compatible with C++ compilers. Instruction decoding is done using our trimmed-down version of Intel's disassembler Xed. The prime directive of this project is to act as a virtual machine for userspace binaries compiled by Cosmopolitan Libc. However we've also had success virtualizing programs compiled with Glibc and Musl Libc, such as GCC and Qemu. Blink supports 500+ instructions and 150+ Linux syscalls, including fork() and clone(). Linux system calls may only be used by long mode programs via the `SYSCALL` instruction, as it is written in the System V ABI. ### Instruction Sets The following hardware ISAs are supported by Blink. - i8086 - i386 - X87 - SSE2 - x86_64 - SSE3 - SSSE3 - CLMUL - POPCNT - ADX - BMI2 - RDRND - RDSEED - RDTSCP Programs may use `CPUID` to confirm the presence or absence of optional instruction sets. Please note that Blink does not follow the same monotonic progress as Intel's hardware. For example, BMI2 is supported; this is an AVX2-encoded (VEX) instruction set, which Blink is able to decode, even though the AVX2 ISA isn't supported. Therefore it's important to not glob ISAs into "levels" (as Windows software tends to do) where it's assumed that BMI2 support implies AVX2 support; because with Blink that currently isn't the case. On the other hand, Blink does share Windows' x87 behavior w.r.t. double (rather than long double) precision. It's not possible to use 80-bit floating point precision with Blink, because Blink simply passes along floating point operations to the host architecture, and very few architectures support `long double` precision. You can still use x87 with 80-bit words. Blink will just store 64-bit floating point values inside them, and that's a legal configuration according to the x87 FPU control word. If possible, it's recommended that `long double` simply be avoided. If 64-bit floating point [is good enough for the rocket scientists at NASA](https://www.jpl.nasa.gov/edu/news/2016/3/16/how-many-decimals-of-pi-do-we-really-need/) then it should be good enough for everybody. There are some peculiar differences in behavior with `double` across architectures (which Blink currently does nothing to address) but they tend to be comparatively minor, e.g. an op returning `NAN` instead of `-NAN`. Blink has reasonably comprehensive coverage of the baseline ISAs, including even support for BCD operations (even in long mode!). But there are some truly fringe instructions Blink hasn't implemented, such as `BOUND` and `ENTER`. Most of the unsupported instructions, are usually ring-0 system instructions, since Blink is primarily a user-mode VM, and therefore only has limited support for bare metal operating system software (which we'll discuss more in-depth in a later section). Blink advertises itself as `Linux 4.5` in the `uname()` system call and `uname -v` will report `blink-1.0`. Programs may detect they're running in Blink by issuing a `CPUID` instruction where `EAX` is set to the leaf number: - Leaf `0x0` (or `0x80000000`) reports `GenuineIntel` in `EBX ‖ EDX ‖ ECX` - Leaf `0x1` reports that Blink is a hypervisor in bit `31` of `ECX` - Leaf `0x40000000` reports `GenuineBlink` as the hypervisor name in `EBX ‖ ECX ‖ EDX` - Leaf `0x40031337` reports the underlying operating system name in `EBX ‖ ECX ‖ EDX` with zero filling for strings shorter than 12: - `Linux` for Linux - `XNU` for macOS - `FreeBSD` for FreeBSD - `NetBSD` for NetBSD - `OpenBSD` for OpenBSD - `Linux` for Linux - `Cygwin` for Windows under Cygwin - `Windows` for Windows under Cosmopolitan - `Unknown` if compiled on unrecognized platform - Leaf `0x40031338` reports the underlying hardware architecture name in `EBX ‖ ECX ‖ EDX` with zero filling for strings shorter than 12: - `x86_64` for x86_64 - `i386` for i386 - `aarch64` for aarch64 - `arm` for arm32 - `ppc64` for powerpc64 - `ppc64le` for powerpc64le - `ppc` for powerpc - `s390x` for s390x - `riscv64` for riscv64 - `riscv32` for riscv32 - `Unknown` if compiled on unrecognized platform - Leaf `0x80000001` tells if Blink's JIT is enabled in bit `31` in `ECX` ### JIT Blink uses just-in-time compilation, which is supported on x86_64 and aarch64. Blink takes the appropriate steps to work around restrictions relating to JIT, on platforms like Apple and OpenBSD. We generate JIT code using a printf-style domain-specific language. The JIT works by generating functions at runtime which call the micro-op functions the compiler created. To make micro-operations go faster, Blink determines the byte length of the compiled function at runtime by scanning for a RET instruction. Blink will then copy the compiled function into the function that the JIT is generating. This works in most cases, however some tools can cause problems. For example, OpenBSD RetGuard inserts static memory relocations into every compiled function, which Blink's JIT currently doesn't understand; so we need to use compiler flags to disable that type of magic. In the event other such magic slips through, Blink has a runtime check which will catch obvious problems, and then gracefully fall back to using a CALL instruction. Since no JIT can be fully perfect on all platforms, the `blink -j` flag may be passed to disable Blink's JIT. Please note that disabling JIT makes Blink go 10x slower. With the `blinkenlights` command, the `-j` flag takes on the opposite meaning, where it instead *enables* JIT. This can be useful for troubleshooting the JIT, because the TUI display has a feature that lets JIT path formation be visualized. Blink currently only enables the JIT for programs running in long mode (64-bit) but we may support JITing 16-bit programs in the future. ### Virtualization Blink virtualizes memory using the same PML4T approach as the hardware itself, where memory lookups are indirected through a four-level radix tree. Since performing four separate page table lookups on every memory access can be slow, Blink checks a translation lookaside buffer, which contains the sixteen most recently used page table entries. The PML4T allows all memory lookups in Blink to be "safe" but it still doesn't offer the best possible performance. Therefore, on systems with a huge address space (i.e. petabytes of virtual memory) Blink relies on itself being loaded to a random location, and then identity maps guest memory using a simple linear translation. For example, if the guest virtual address is `0x400000` then the host address might be `0x400000+0x088800000000`. This means that each time a memory operation is executed, only a simple addition needs to be performed. This goes extremely fast, however it may present issues for programs that use `MAP_FIXED`. Some systems, such as modern Raspberry Pi, actually have a larger address space than x86-64, which lets Blink offer the guest the complete address space. However on some platforms, like 32-bit ones, only a limited number of identity mappings are possible. There's also compiler tools like TSAN which lay claim to much of the fixed address space. Blink's solution is designed to meet the needs of Cosmopolitan Libc, while working around Apple's restriction on 32-bit addresses, and still remain fully compatible with ASAN's restrictions. In the event that this translation scheme doesn't work on your system, the `blink -m` flag may be passed to disable the linear translation optimization, and instead use only the memory safe full virtualization approach of the PML4T and TLB. #### Lockless Hashing Blink stores generated functions by virtual address in a multithreaded lockless hash table. The hottest operation in the codebase is reading from this hash table, using a function called `GetJitHook`. Since it'd slow Blink down by more than 33% if a mutex were used here, Blink will synchronize reads optimistically using only carefully ordered load instructions, three of which have acquire semantics. This hash table starts off at a reasonable size and grows gradually with the memory requirements. This design is the primary reason Blink usually uses 40% less peak resident memory than Qemu. #### Acyclic Codegen Even though JIT paths will always end at branching instructions, Blink will generate code so that paths tail call into each other, in order to avoid dropping back into the main interpreter loop. The average length of a JIT path is about ~5 opcodes. Connecting paths causes the average path length to be ~13 opcodes. Since Blink only checks for asynchronous signal delivery and shutdown events from the main interpreter loop, Blink maintains a bidirectional map of edges between generated functions, so that path connections which would result in cycles are never introduced. An exception is made for tight conditional branches, i.e. jumps whose taken path jump backwards to the start of the JIT path. Such branches are allowed to be self-referencing so that whole loops of non-system operations may be run in purely native code. #### Reliable Memory Blink has a 22mb global static variable that's set aside for JIT code. This limit was chosen because that's roughly the maximum displacement permitted on Arm64 architecture. Having that memory near the program image helps make Blink simpler, since generated functions call normal functions, without needing relocations or procedure linkage tables. When Blink runs out of JIT memory, it simply clears all JIT hooks and lets the whole code generation process start again. Blink is very fast at generating code, and it wouldn't make sense during an OOM panic to arbitrarily choose a subset of pages to reset, since resetting pages requires tracing their dependencies and resetting those too. Starting over is much better. It's so much better in fact, that even if Blink only reserved less than a megabyte of memory for JIT, then the slowdown that'd be incurred running 40mb binaries like GCC CC1 would only be 3x. Blink triggers the OOM panic when only 10% of its JIT memory remains. That's because in multi-threaded programs, there's no way to guarantee nothing is still executing on the retired code blocks. Blink solves this by letting retired blocks cool off at the back of a freelist queue, so the acyclicity invariant has abundant time to ensure threads drop out. ### Self-Modifying Code Many CPU architectures require esoteric rituals for flushing CPU caches when code modifies itself. That's not the case with x86 architecture, which takes care of this chore automatically. Blink is able to offer the same promises here as Intel and AMD, by abstracting fast and automatic invalidation of caches for programs using self-modifying code (SMC). When Blink's JIT isn't enabled, self-modifying code always causes instruction caches to be invalidated immediately, at least within the same thread. That's because Blink compares the raw instruction bytes with what's in the instruction cache before fetching its decoded value. When JITing is enabled, Blink will automatically invalidate JIT memory associated with code that's been modified. This happens on a 4096-byte page granularity. When a function like mprotect() is called that causes memory pages to transition from a non-executable to executable state, the impacted pages will be invalidated by the JIT. The JIT maintains a hash table where the key is the virtual address at which a generated function begins (which we call a "path") and the value is a function pointer to the generated code. When Blink is generating paths, it is careful to ensure that all the guest instructions which are added to a path, only exist within the confines of a single 4096-byte page. Thus when a page needs to be invalidated, Blink simply deletes any hook for each address within the page. When RWX memory is used, Blink can't rely on mprotect() to communicate the intent of the guest program. What Blink will do instead is protect any RWX guest memory, so that it's registered as read-only in the host operating system. This way, whenever the guest writes to RWX memory, a SIGSEGV signal will be delivered to Blink, which then re-enables write permissions on the impacted RWX page, flips a bit to the thread in the SMC state and then permits execution to resume for at least one opcode before the interpreter loop notices the SMC state, invalidates the JIT and re-enables the memory protection. This means that: 1. Memory ops in general aren't slowed down by Blink's SMC support 2. RWX memory can be written-to with some overhead 3. RWX memory can be read-from with zero overhead 4. Changes take effect when a JIT path ends Intel's sixteen thousand page manual lays out the following guidelines for conformant self-modifying code: > To write self-modifying code and ensure that it is compliant with > current and future versions of the IA-32 architectures, use one of > the following coding options: > > (* OPTION 1 *) > Store modified code (as data) into code segment; > Jump to new code or an intermediate location; > Execute new code; > > (* OPTION 2 *) > Store modified code (as data) into code segment; > Execute a serializing instruction; (* For example, CPUID instruction *) > Execute new code; > > ──Quoth Intel Manual V.3, §8.1.3 Blink implements this behavior because branching instructions cause JIT paths to end, paths only jump into one another selectively , and lastly serializing instructions are never added to paths in the first place. Intel's rules allow Blink some leeway to make writing to RWX memory go fast, without causing any signal storms, or incurring too much system call overhead. As an example, consider the internal statistics printed by the [`smc2_test.c`](test/func/smc2_test.c) program: ``` make -j8 o//blink/blink o//test/func/smc2_test.elf o//blink/blink -Z o//test/func/smc2_test.elf [...] icache_resets = 1 jit_blocks = 1 jit_hooks_installed = 132 jit_hooks_deleted = 19 jit_page_resets = 21 smc_checks = 22 smc_flushes = 22 smc_enqueued = 22 smc_segfaults = 22 [...] ``` The above program performs 300+ independent write operations to RWX memory. However we can see very few of them resulted in segfaults, since most of those ops happened in the SlowMemCpy() function which uses a tight conditional branch loop rather than a proper jump. This let the program get more accomplished, before dropping out of JIT code back into the main interpreter loop, which is where Blink checks the SMC state in order to flush the caches reapply any missing write protection. ## Pseudoteletypewriter Blink has an xterm-compatible ANSI pseudoteletypewriter display implementation which allows Blink's TUI interface to host other TUI programs, within an embedded terminal display. For example, it's possible to use Antirez's Kilo text editor inside Blink's TUI. For the complete list of ANSI sequences which are supported, please refer to [blink/pty.c](blink/pty.c). In real mode, Blink's PTY can be configured via `INT $0x16` to convert CGA memory stored at address `0xb0000` into UNICODE block characters, thereby making retro video gaming in the terminal possible. ## Real Mode Blink supports 16-bit BIOS programs, such as SectorLISP. To boot real mode programs in Blink, the `blinkenlights -r` flag may be passed, which puts the virtual machine in i8086 mode. Currently only a limited set of BIOS APIs are available. For example, Blink supports IBM PC Serial UART, CGA, and MDA. We hope to expand our real mode support in the near future, in order to run operating systems like ELKS. Blink supports troubleshooting operating system bootloaders. Blink was designed for Cosmopolitan Libc, which embeds an operating system in each binary it compiles. Blink has helped us debug our bare metal support, since Blink is capable of running in the 16-bit, 32-bit, and 64-bit modes a bootloader requires at various stages. In order to do that, we needed to implement some ring0 hardware instructions. Blink has enough to support Cosmopolitan, but it'll take much more time to get Blink to a point where it can boot something like Windows. ## Executable Formats Blink supports several different executable formats. You can run: - x86-64-linux ELF executables (both static and dynamic). - Actually Portable Executables, which have either the `MZqFpD` or `jartsr` magic. - Flat executables, which must end with the file extension `.bin`. In this case, you can make executables as small as 10 bytes in size, since they're treated as raw x86-64 code. Blink always loads flat executables to the address `0x400000` and automatically appends 16mb of BSS memory. - Real mode executables, which are loaded to the address `0x7c00`. These programs must be run using the `blinkenlights` command with the `-r` flag. ## Filesystems When Blink is built with the VFS feature enabled (`--enable-vfs`), it comes with three default filesystems: - `hostfs`: A filesystem that mirrors a certain directory on the host's filesystem. Files on `hostfs` mounts have everything read from and written directly to the corresponding host directory, with the exception of `st_dev` and `st_ino` fields. `st_dev` is managed by Blink's VFS subsystem, while `st_ino` is calculated using a hash function based on the host's `st_dev` and `st_ino` value. - `proc`: A filesystem that emulates Linux's `/proc` using information available to Blink. - `devfs`: A filesystem that emulates Linux's `/dev`. Currently, this is only a wrapper for `hostfs`. When Blink is launched, these default mount points are added: - `/` of type `hostfs` pointing to the corresponding host directory. This is determined by querying `$BLINK_PREFIX` and the `-C` parameter in order and falls back to `/` if neither are available. - `/proc` of type `proc`. - `/dev` of type `devfs`. - `/SytemRoot` of type `hostfs` pointing to the host's root `/`. It is possbile for programs to add additional mount points by using the `mount` syscall (for `hostfs` mounts, pass the path to the directory on the _host_ as the `source` argument), but see the quirks below. ## Quirks Here's the current list of Blink's known quirks and tradeoffs. ### Flags Flag dependencies may not carry across function call boundaries under long mode. This is because when Blink's JIT is speculating whether or not it's necessary for an arithmetic instruction to compute flags, it considers `RET` and `CALL` terminal ops that break the chain. As such 64-bit code shouldn't do things we did in the DOS days, such as using carry flag as a return value to indicate error. This should work fine when `STC` is used to set the carry flag, but if the code computes it cleverly using instructions like `SUB`, then EFLAGS might not change. As a special case, if a `RET` instruction sports a `REP` prefix, then Blink can return flags across the `RET`. ### Faults Blink may not report the precise program counter where a fault occurred in `ucontext_t::uc_mcontext::rip` when signalling a segmentation fault. This is currently only possible when `PUSH` or `POP` access bad memory. That's because Blink's JIT tries to avoid updating `Machine::ip` on ops it considers "pure" such as those that only access registers, which for reasons of performance is defined to include pushing and popping. ### Threads Blink doesn't have a working implementation of `set_robust_list()` yet, which means robust mutexes might not get unlocked if a process crashes. ### Coherency POSIX.1 provides almost no guarantees of coherency, synchronization, and durability when it comes to `MAP_SHARED` mappings and recommends that msync() be explicitly used to synchronize memory with file contents. The Linux Kernel implements shared memory so well, that this is rarely necessary. However some platforms like OpenBSD lack write coherency. This means if you change a shared writable memory map and then call pread() on the associated file region, you might get stale data. Blink isn't able to polyfill incoherent platforms to be as coherent as Linux, therefore apps that run in Blink should assume the POSIX rules apply. ### Signal Handling Blink uses `SIGSYS` to deliver signals internally. This signal is precious to Blink. It's currently not possible for guest applications to capture it from external processes. ### Memory Protection Blink offers guest programs a 48-bit virtual address space with a 4096-byte page size. When programs are run on (1) host systems that have a larger page (e.g. Apple M1, Cygwin), and (2) the linear memory optimization is enabled (i.e. you're *not* using `blink -m`) then Blink may need to relax memory protections in cases where the memory intervals defined by the guest aren't aligned to the host system page size. This means that, on system with a larger than 4096 byte page size: 1. Misaligned read-only pages could become writable 2. JIT hooks might not invalidate automatically on misaligned RWX pages It's recommended, when calling functions like mmap() and mprotect(), that both `addr` and `addr + size` be aliged to the host page size. Blink reports that value to the guest program in `getauxval(AT_PAGESZ)`, which should be obtainable via the POSIX API `sysconf(_SC_PAGESIZE)` if the C library is implemented correctly. Please note that when Blink is running in full virtualization mode (i.e. `blink -m`) this concern no longer applies. That's because Blink will allocate a full system page for every 4096 byte page that's mapped from a file. ### Process Management For builds with the VFS feature enabled (--enable-vfs), while a `procfs` mount is available at `/proc`, it is limited to information available in a single process. Only `/proc/self` and the corresponding PID folder is available. This means programs can get the expected values at `/proc/self/exe` and similar files, but process management tools like `ps` will not work. On Linux, some `procfs` symlinks possess a hardlink-like ability of being dereferenceable even after the target has been `unlink`ed. Blink's implementation currently does not support this use case. ### Mounts For builds with the VFS feature enabled (`--enable-vfs`), Blink does not share mount information with other emulated processes. As a result, commands like this may seem to work (by return a 0 status code): ```sh mount -t hostfs /some/path/on/host folder ``` But subsequent calls to `ls folder` on the same shell still does not display the expected contents. This is because the `mount` command could only modify the mount table kept by itself (and propagated to children through `fork`), but not the one used by its parent shell. In other words, Blink behaves as if `CLONE_NEWNS` is added to every `clone` call, separating the mount namespace of the child from its parent. Some might view this behavior as a feature, but it diverges from classic system behavior; a mechanism for handling shared process state is being considered in [#92](https://github.com/jart/blink/issues/92). ================================================ FILE: blink/abort.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/assert.h" #include "blink/macros.h" #include "blink/stats.h" #include "blink/util.h" static struct AbortHooks { int n; aborthook_f *p[4]; } g_aborthooks; void AtAbort(aborthook_f *hook) { unassert(g_aborthooks.n < ARRAYLEN(g_aborthooks.p)); g_aborthooks.p[g_aborthooks.n++] = hook; } void Abort(void) { int i; #ifndef NDEBUG if (FLAG_statistics) { PrintStats(); } #endif for (i = g_aborthooks.n; i--;) { g_aborthooks.p[i](); } abort(); } ================================================ FILE: blink/address.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/assert.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/x86.h" i64 GetPc(struct Machine *m) { return m->cs.base + GetIp(m); } i64 GetIp(struct Machine *m) { return MaskAddress(m->mode.omode, m->ip); } u64 MaskAddress(u32 mode, u64 x) { if (mode != XED_MODE_LONG) { if (mode == XED_MODE_REAL) { x &= 0xffff; } else { x &= 0xffffffff; } } return x; } i64 AddSegment(P, u64 i, u64 s) { if (!Sego(rde)) { return i + s; } else { return i + m->seg[Sego(rde) - 1].base; } } u64 AddressOb(P) { return AddSegment(A, disp, m->ds.base); } u64 GetSegmentBase(P, unsigned s) { if (s < 6) { return m->seg[s].base; } else { OpUdImpl(m); } } i64 DataSegment(P, u64 i) { return AddSegment(A, i, m->ds.base); } i64 AddressSi(P) { switch (Eamode(rde)) { case XED_MODE_LONG: return DataSegment(A, Get64(m->si)); case XED_MODE_REAL: return DataSegment(A, Get16(m->si)); case XED_MODE_LEGACY: return DataSegment(A, Get32(m->si)); default: __builtin_unreachable(); } } u64 AddressDi(P) { u64 i = m->es.base; switch (Eamode(rde)) { case XED_MODE_LONG: return i + Get64(m->di); case XED_MODE_REAL: return i + Get16(m->di); case XED_MODE_LEGACY: return i + Get32(m->di); default: __builtin_unreachable(); } } ================================================ FILE: blink/alu.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/alu.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/log.h" #include "blink/machine.h" const aluop_f kAlu[12][4] = { {Add8, Add16, Add32, Add64}, // {Or8, Or16, Or32, Or64}, // {Adc8, Adc16, Adc32, Adc64}, // {Sbb8, Sbb16, Sbb32, Sbb64}, // {And8, And16, And32, And64}, // {Sub8, Sub16, Sub32, Sub64}, // {Xor8, Xor16, Xor32, Xor64}, // {Sub8, Sub16, Sub32, Sub64}, // {Not8, Not16, Not32, Not64}, // {Neg8, Neg16, Neg32, Neg64}, // {Inc8, Inc16, Inc32, Inc64}, // {Dec8, Dec16, Dec32, Dec64}, // }; const aluop_f kBsu[8][4] = { {Rol8, Rol16, Rol32, Rol64}, // {Ror8, Ror16, Ror32, Ror64}, // {Rcl8, Rcl16, Rcl32, Rcl64}, // {Rcr8, Rcr16, Rcr32, Rcr64}, // {Shl8, Shl16, Shl32, Shl64}, // {Shr8, Shr16, Shr32, Shr64}, // {Shl8, Shl16, Shl32, Shl64}, // {Sar8, Sar16, Sar32, Sar64}, // }; static i64 AluFlags(struct Machine *m, u64 x, u32 af, u32 of, u32 cf, u32 sf) { m->flags &= ~(CF | ZF | SF | OF | AF | 0xFF000000u); m->flags |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF | af << FLAGS_AF | (x & 0xFF) << 24; return x; } static i64 AluFlags8(struct Machine *m, u8 z, u32 af, u32 of, u32 cf) { return AluFlags(m, z, af, of, cf, z >> 7); } i64 Xor8(struct Machine *m, u64 x, u64 y) { return AluFlags8(m, x ^ y, 0, 0, 0); } i64 Or8(struct Machine *m, u64 x, u64 y) { return AluFlags8(m, x | y, 0, 0, 0); } i64 And8(struct Machine *m, u64 x, u64 y) { return AluFlags8(m, x & y, 0, 0, 0); } i64 Sub8(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u8 x, y, z; x = x64; y = y64; z = x - y; cf = x < z; af = (x & 15) < (z & 15); of = ((x ^ y) & (z ^ x)) >> 7; return AluFlags8(m, z, af, of, cf); } i64 Add8(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u8 x, y, z; x = x64; y = y64; z = x + y; cf = z < y; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ y)) >> 7; return AluFlags8(m, z, af, of, cf); } static i64 AluFlags32(struct Machine *m, u32 z, u32 af, u32 of, u32 cf) { return AluFlags(m, z, af, of, cf, z >> 31); } i64 Xor32(struct Machine *m, u64 x, u64 y) { return AluFlags32(m, x ^ y, 0, 0, 0); } i64 Or32(struct Machine *m, u64 x, u64 y) { return AluFlags32(m, x | y, 0, 0, 0); } i64 And32(struct Machine *m, u64 x, u64 y) { return AluFlags32(m, x & y, 0, 0, 0); } i64 Sub32(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u32 x, y, z; x = x64; y = y64; z = x - y; cf = x < z; af = (x & 15) < (z & 15); of = ((x ^ y) & (z ^ x)) >> 31; return AluFlags32(m, z, af, of, cf); } i64 Add32(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u32 x, y, z; x = x64; y = y64; z = x + y; cf = z < y; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ y)) >> 31; return AluFlags32(m, z, af, of, cf); } static i64 AluFlags64(struct Machine *m, u64 z, u32 af, u32 of, u32 cf) { return AluFlags(m, z, af, of, cf, z >> 63); } i64 Xor64(struct Machine *m, u64 x, u64 y) { return AluFlags64(m, x ^ y, 0, 0, 0); } i64 Or64(struct Machine *m, u64 x, u64 y) { return AluFlags64(m, x | y, 0, 0, 0); } i64 And64(struct Machine *m, u64 x, u64 y) { return AluFlags64(m, x & y, 0, 0, 0); } i64 Sub64(struct Machine *m, u64 x, u64 y) { u64 z; bool cf, of, af; z = x - y; cf = x < z; af = (x & 15) < (z & 15); of = ((x ^ y) & (z ^ x)) >> 63; return AluFlags64(m, z, af, of, cf); } i64 Add64(struct Machine *m, u64 x, u64 y) { u64 z; bool cf, of, af; z = x + y; cf = z < y; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ y)) >> 63; return AluFlags64(m, z, af, of, cf); } i64 Adc8(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u8 x, y, z, t; x = x64; y = y64; t = x + !!(m->flags & CF); z = t + y; cf = (t < x) | (z < y); of = ((z ^ x) & (z ^ y)) >> 7; af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); return AluFlags8(m, z, af, of, cf); } i64 Adc32(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u32 x, y, z, t; x = x64; y = y64; t = x + !!(m->flags & CF); z = t + y; cf = (t < x) | (z < y); of = ((z ^ x) & (z ^ y)) >> 31; af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); return AluFlags32(m, z, af, of, cf); } i64 Adc64(struct Machine *m, u64 x, u64 y) { u64 z, t; bool cf, of, af; t = x + !!(m->flags & CF); z = t + y; cf = (t < x) | (z < y); of = ((z ^ x) & (z ^ y)) >> 63; af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); return AluFlags64(m, z, af, of, cf); } i64 Sbb8(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u8 x, y, z, t; x = x64; y = y64; t = x - !!(m->flags & CF); z = t - y; cf = (x < t) | (t < z); of = ((z ^ x) & (x ^ y)) >> 7; af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); return AluFlags8(m, z, af, of, cf); } i64 Sbb32(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u32 x, y, z, t; x = x64; y = y64; t = x - !!(m->flags & CF); z = t - y; cf = (x < t) | (t < z); of = ((z ^ x) & (x ^ y)) >> 31; af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); return AluFlags32(m, z, af, of, cf); } i64 Sbb64(struct Machine *m, u64 x, u64 y) { u64 z, t; bool cf, of, af; t = x - !!(m->flags & CF); z = t - y; cf = (x < t) | (t < z); of = ((z ^ x) & (x ^ y)) >> 63; af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); return AluFlags64(m, z, af, of, cf); } i64 Neg8(struct Machine *m, u64 x64, u64 y) { u8 x; bool cf, of, af; x = x64; af = cf = !!x; of = x == 0x80; x = ~x + 1; return AluFlags8(m, x, af, of, cf); } i64 Neg32(struct Machine *m, u64 x64, u64 y) { u32 x; bool cf, of, af; x = x64; af = cf = !!x; of = x == 0x80000000; x = ~x + 1; return AluFlags32(m, x, af, of, cf); } i64 Neg64(struct Machine *m, u64 x64, u64 y) { u64 x; bool cf, of, af; x = x64; af = cf = !!x; of = x == 0x8000000000000000; x = ~x + 1; return AluFlags64(m, x, af, of, cf); } static i64 BumpFlags(struct Machine *m, u64 x, u32 af, u32 of, u32 sf) { return AluFlags(m, x, af, of, !!(m->flags & CF), sf); } i64 Dec32(struct Machine *m, u64 x64, u64 y) { u32 x, z, of, sf, af; x = x64; z = x - 1; sf = z >> 31; af = (x & 15) < (z & 15); of = ((z ^ x) & (x ^ 1)) >> 31; return BumpFlags(m, z, af, of, sf); } i64 Inc32(struct Machine *m, u64 x64, u64 y) { u32 x, z, of, sf, af; x = x64; z = x + 1; sf = z >> 31; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ 1)) >> 31; return BumpFlags(m, z, af, of, sf); } i64 Inc64(struct Machine *m, u64 x, u64 y) { u64 z; u32 of, sf, af; z = x + 1; sf = z >> 63; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ 1)) >> 63; return BumpFlags(m, z, af, of, sf); } i64 Dec64(struct Machine *m, u64 x, u64 y) { u64 z; u32 of, sf, af; z = x - 1; sf = z >> 63; af = (x & 15) < (z & 15); of = ((z ^ x) & (x ^ 1)) >> 63; return BumpFlags(m, z, af, of, sf); } i64 Inc8(struct Machine *m, u64 x64, u64 y) { u8 x, z; u32 of, sf, af; x = x64; z = x + 1; sf = z >> 7; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ 1)) >> 7; return BumpFlags(m, z, af, of, sf); } i64 Dec8(struct Machine *m, u64 x64, u64 y) { u8 x, z; u32 of, sf, af; x = x64; z = x - 1; sf = z >> 7; af = (x & 15) < (z & 15); of = ((z ^ x) & (x ^ 1)) >> 7; return BumpFlags(m, z, af, of, sf); } i64 Shr8(struct Machine *m, u64 x64, u64 y) { u32 x, cf; x = x64 & 0xff; if ((y &= 31)) { cf = (x >> (y - 1)) & 1; x >>= y; return AluFlags8(m, x, 0, ((x << 1) ^ x) >> 7, cf); } else { return x; } } i64 Shr32(struct Machine *m, u64 x64, u64 y) { u32 cf, x = x64; if ((y &= 31)) { cf = (x >> (y - 1)) & 1; x >>= y; return AluFlags32(m, x, 0, ((x << 1) ^ x) >> 31, cf); } else { return x; } } i64 Shr64(struct Machine *m, u64 x, u64 y) { u32 cf; if ((y &= 63)) { cf = (x >> (y - 1)) & 1; x >>= y; return AluFlags64(m, x, 0, ((x << 1) ^ x) >> 63, cf); } else { return x; } } i64 Shl8(struct Machine *m, u64 x64, u64 y) { u32 x, cf; x = x64 & 0xff; if ((y &= 31)) { cf = (x >> ((8 - y) & 31)) & 1; x = (x << y) & 0xff; return AluFlags8(m, x, 0, (x >> 7) ^ cf, cf); } else { return x; } } i64 Shl32(struct Machine *m, u64 x64, u64 y) { u32 cf, x = x64; if ((y &= 31)) { cf = (x >> (32 - y)) & 1; x <<= y; return AluFlags32(m, x, 0, (x >> 31) ^ cf, cf); } else { return x; } } i64 Shl64(struct Machine *m, u64 x, u64 y) { u32 cf; if ((y &= 63)) { cf = (x >> (64 - y)) & 1; x <<= y; return AluFlags64(m, x, 0, (x >> 63) ^ cf, cf); } else { return x; } } i64 Sar8(struct Machine *m, u64 x64, u64 y) { u32 x, cf; x = x64 & 0xff; if ((y &= 31)) { cf = ((i32)(i8)x >> (y - 1)) & 1; x = ((i32)(i8)x >> y) & 0xff; return AluFlags8(m, x, 0, 0, cf); } else { return x; } } i64 Sar32(struct Machine *m, u64 x64, u64 y) { u32 cf, x = x64; if ((y &= 31)) { cf = ((i32)x >> (y - 1)) & 1; x = (i32)x >> y; return AluFlags32(m, x, 0, 0, cf); } else { return x; } } i64 Sar64(struct Machine *m, u64 x, u64 y) { u32 cf; if ((y &= 63)) { cf = ((i64)x >> (y - 1)) & 1; x = (i64)x >> y; return AluFlags64(m, x, 0, 0, cf); } else { return x; } } static i64 RotateFlags(struct Machine *m, u64 x, u32 cf, u32 of) { m->flags &= ~(CF | OF); m->flags |= cf << FLAGS_CF | of << FLAGS_OF; return x; } i64 Rol32(struct Machine *m, u64 x64, u64 y) { u32 x = x64; if ((y &= 31)) { x = x << y | x >> (32 - y); return RotateFlags(m, x, x & 1, ((x >> 31) ^ x) & 1); } else { return x; } } i64 Rol64(struct Machine *m, u64 x, u64 y) { if ((y &= 63)) { x = x << y | x >> (64 - y); return RotateFlags(m, x, x & 1, ((x >> 63) ^ x) & 1); } else { return x; } } i64 Ror32(struct Machine *m, u64 x64, u64 y) { u32 x = x64; if ((y &= 31)) { x = x >> y | x << (32 - y); return RotateFlags(m, x, x >> 31, ((x >> 31) ^ (x >> 30)) & 1); } else { return x; } } i64 Ror64(struct Machine *m, u64 x, u64 y) { if ((y &= 63)) { x = x >> y | x << (64 - y); return RotateFlags(m, x, x >> 63, ((x >> 63) ^ (x >> 62)) & 1); } else { return x; } } i64 Rol8(struct Machine *m, u64 x64, u64 y) { u8 x = x64; if (y & 31) { if ((y &= 7)) x = x << y | x >> (8 - y); return RotateFlags(m, x, x & 1, ((x >> 7) ^ x) & 1); } else { return x; } } i64 Ror8(struct Machine *m, u64 x64, u64 y) { u8 x = x64; if (y & 31) { if ((y &= 7)) x = x >> y | x << (8 - y); return RotateFlags(m, x, x >> 7, ((x >> 7) ^ (x >> 6)) & 1); } else { return x; } } static i64 Rcr(struct Machine *m, u64 x, u64 y, u64 xm, u64 k) { u64 cf; u32 ct; x &= xm; if (y) { cf = !!(m->flags & CF); ct = (x >> (y - 1)) & 1; if (y == 1) { x = (x >> 1 | cf << (k - 1)) & xm; } else { x = (x >> y | cf << (k - y) | x << (k + 1 - y)) & xm; } return RotateFlags(m, x, ct, (((x << 1) ^ x) >> (k - 1)) & 1); } else { return x; } } i64 Rcr8(struct Machine *m, u64 x, u64 y) { return Rcr(m, x, ((unsigned)y & 31) % 9, 0xff, 8); } i64 Rcr16(struct Machine *m, u64 x, u64 y) { return Rcr(m, x, ((unsigned)y & 31) % 17, 0xffff, 16); } i64 Rcr32(struct Machine *m, u64 x, u64 y) { return Rcr(m, x, y & 31, 0xffffffff, 32); } i64 Rcr64(struct Machine *m, u64 x, u64 y) { return Rcr(m, x, y & 63, 0xffffffffffffffff, 64); } static i64 Rcl(struct Machine *m, u64 x, u64 y, u64 xm, u64 k) { u64 cf; u32 ct; x &= xm; if (y) { cf = !!(m->flags & CF); ct = (x >> (k - y)) & 1; if (y == 1) { x = (x << 1 | cf) & xm; } else { x = (x << y | cf << (y - 1) | x >> (k + 1 - y)) & xm; } return RotateFlags(m, x, ct, ct ^ ((x >> (k - 1)) & 1)); } else { return x; } } i64 Rcl8(struct Machine *m, u64 x, u64 y) { return Rcl(m, x, ((unsigned)y & 31) % 9, 0xff, 8); } i64 Rcl16(struct Machine *m, u64 x, u64 y) { return Rcl(m, x, ((unsigned)y & 31) % 17, 0xffff, 16); } i64 Rcl32(struct Machine *m, u64 x, u64 y) { return Rcl(m, x, y & 31, 0xffffffff, 32); } i64 Rcl64(struct Machine *m, u64 x, u64 y) { return Rcl(m, x, y & 63, 0xffffffffffffffff, 64); } u64 BsuDoubleShift(struct Machine *m, int w, u64 x, u64 y, u8 b, bool isright) { bool cf, of; u64 s, k, M, z; k = 8; k <<= w; s = 1; s <<= k - 1; M = s | (s - 1); b &= w == 3 ? 63 : 31; x &= M; if (b) { if (isright) { z = x >> b | y << (k - b); cf = (x >> (b - 1)) & 1; of = b == 1 && (z & s) != (x & s); } else { z = x << b | y >> (k - b); cf = (x >> (k - b)) & 1; of = b == 1 && (z & s) != (x & s); } x = z; x &= M; return AluFlags(m, x, 0, of, cf, !!(x & s)); } else { return x; } } static i64 AluFlags16(struct Machine *m, u16 z, u32 af, u32 of, u32 cf) { return AluFlags(m, z, af, of, cf, z >> 15); } i64 Xor16(struct Machine *m, u64 x, u64 y) { return AluFlags16(m, x ^ y, 0, 0, 0); } i64 Or16(struct Machine *m, u64 x, u64 y) { return AluFlags16(m, x | y, 0, 0, 0); } i64 And16(struct Machine *m, u64 x, u64 y) { return AluFlags16(m, x & y, 0, 0, 0); } i64 Sub16(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u16 x, y, z; x = x64; y = y64; z = x - y; cf = x < z; af = (x & 15) < (z & 15); of = ((x ^ y) & (z ^ x)) >> 15; return AluFlags16(m, z, af, of, cf); } i64 Add16(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u16 x, y, z; x = x64; y = y64; z = x + y; cf = z < y; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ y)) >> 15; return AluFlags16(m, z, af, of, cf); } i64 Adc16(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u16 x, y, z, t; x = x64; y = y64; t = x + !!(m->flags & CF); z = t + y; cf = (t < x) | (z < y); of = ((z ^ x) & (z ^ y)) >> 15; af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); return AluFlags16(m, z, af, of, cf); } i64 Sbb16(struct Machine *m, u64 x64, u64 y64) { bool cf, of, af; u16 x, y, z, t; x = x64; y = y64; t = x - !!(m->flags & CF); z = t - y; cf = (x < t) | (t < z); of = ((z ^ x) & (x ^ y)) >> 15; af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); return AluFlags16(m, z, af, of, cf); } i64 Neg16(struct Machine *m, u64 x64, u64 y) { u16 x; bool cf, of, af; x = x64; af = cf = !!x; of = x == 0x8000; x = ~x + 1; return AluFlags16(m, x, af, of, cf); } i64 Inc16(struct Machine *m, u64 x64, u64 y) { u16 x, z; u32 of, sf, af; x = x64; z = x + 1; sf = z >> 15; af = (z & 15) < (y & 15); of = ((z ^ x) & (z ^ 1)) >> 15; return BumpFlags(m, z, af, of, sf); } i64 Dec16(struct Machine *m, u64 x64, u64 y) { u16 x, z; u32 of, sf, af; x = x64; z = x - 1; sf = z >> 15; af = (x & 15) < (z & 15); of = ((z ^ x) & (x ^ 1)) >> 15; return BumpFlags(m, z, af, of, sf); } i64 Shr16(struct Machine *m, u64 x64, u64 y) { u32 x, cf; x = x64 & 0xffff; if ((y &= 31)) { cf = (x >> (y - 1)) & 1; x >>= y; return AluFlags16(m, x, 0, ((x << 1) ^ x) >> 15, cf); } else { return x; } } i64 Shl16(struct Machine *m, u64 x64, u64 y) { u32 x, cf; x = x64 & 0xffff; if ((y &= 31)) { cf = (x >> ((16 - y) & 31)) & 1; x = (x << y) & 0xffff; return AluFlags16(m, x, 0, (x >> 15) ^ cf, cf); } else { return x; } } i64 Sar16(struct Machine *m, u64 x64, u64 y) { u32 x, cf; x = x64 & 0xffff; if ((y &= 31)) { cf = ((i32)(i16)x >> (y - 1)) & 1; x = ((i32)(i16)x >> y) & 0xffff; return AluFlags16(m, x, 0, 0, cf); } else { return x; } } i64 Rol16(struct Machine *m, u64 x64, u64 y) { u16 x = x64; if (y & 31) { if ((y &= 15)) x = x << y | x >> (16 - y); return RotateFlags(m, x, x & 1, ((x >> 15) ^ x) & 1); } else { return x; } } i64 Ror16(struct Machine *m, u64 x64, u64 y) { u16 x = x64; if (y & 31) { if ((y &= 15)) x = x >> y | x << (16 - y); return RotateFlags(m, x, x >> 15, ((x >> 15) ^ (x >> 14)) & 1); } else { return x; } } ================================================ FILE: blink/alu.h ================================================ #ifndef BLINK_ALU_H_ #define BLINK_ALU_H_ #include #include "blink/builtin.h" #include "blink/intrin.h" #include "blink/machine.h" #include "blink/types.h" #define ALU_ADD 0 #define ALU_OR 1 #define ALU_ADC 2 #define ALU_SBB 3 #define ALU_AND 4 #define ALU_SUB 5 #define ALU_XOR 6 #define ALU_CMP 7 #define ALU_NOT 8 #define ALU_NEG 9 #define ALU_INC 10 #define ALU_DEC 11 #define BSU_ROL 0 #define BSU_ROR 1 #define BSU_RCL 2 #define BSU_RCR 3 #define BSU_SHL 4 #define BSU_SHR 5 #define BSU_SAL 6 #define BSU_SAR 7 #define ALU_INT8 0 #define ALU_INT16 1 #define ALU_INT32 2 #define ALU_INT64 3 typedef i64 (*aluop_f)(struct Machine *, u64, u64); extern const aluop_f kAlu[12][4]; extern const aluop_f kBsu[8][4]; extern const aluop_f kJustAlu[8]; extern const aluop_f kJustBsu[8]; extern const aluop_f kFastDec[4]; extern const aluop_f kJustBsu32[8]; extern const aluop_f kAluFast[8][4]; extern const aluop_f kJustBsuCl32[8]; extern const aluop_f kJustBsuCl64[8]; i64 JustDec(u64); i64 JustNeg(u64); i64 JustAdd(struct Machine *, u64, u64); i64 JustOr(struct Machine *, u64, u64); i64 JustAdc(struct Machine *, u64, u64); i64 JustSbb(struct Machine *, u64, u64); i64 JustAnd(struct Machine *, u64, u64); i64 JustSub(struct Machine *, u64, u64); i64 JustXor(struct Machine *, u64, u64); i64 Xor8(struct Machine *, u64, u64); i64 Xor16(struct Machine *, u64, u64); i64 Xor32(struct Machine *, u64, u64); i64 Xor64(struct Machine *, u64, u64); i64 Or8(struct Machine *, u64, u64); i64 Or16(struct Machine *, u64, u64); i64 Or32(struct Machine *, u64, u64); i64 Or64(struct Machine *, u64, u64); i64 And8(struct Machine *, u64, u64); i64 And16(struct Machine *, u64, u64); i64 And32(struct Machine *, u64, u64); i64 And64(struct Machine *, u64, u64); i64 Sub8(struct Machine *, u64, u64); i64 Sbb8(struct Machine *, u64, u64); i64 Sub16(struct Machine *, u64, u64); i64 Sbb16(struct Machine *, u64, u64); i64 Sub32(struct Machine *, u64, u64); i64 Sbb32(struct Machine *, u64, u64); i64 Sub64(struct Machine *, u64, u64); i64 Sbb64(struct Machine *, u64, u64); i64 Add8(struct Machine *, u64, u64); i64 Adc8(struct Machine *, u64, u64); i64 Add16(struct Machine *, u64, u64); i64 Adc16(struct Machine *, u64, u64); i64 Add32(struct Machine *, u64, u64); i64 Adc32(struct Machine *, u64, u64); i64 Add64(struct Machine *, u64, u64); i64 Adc64(struct Machine *, u64, u64); i64 Not8(struct Machine *, u64, u64); i64 Not16(struct Machine *, u64, u64); i64 Not32(struct Machine *, u64, u64); i64 Not64(struct Machine *, u64, u64); i64 Neg8(struct Machine *, u64, u64); i64 Neg16(struct Machine *, u64, u64); i64 Neg32(struct Machine *, u64, u64); i64 Neg64(struct Machine *, u64, u64); i64 Inc8(struct Machine *, u64, u64); i64 Inc16(struct Machine *, u64, u64); i64 Inc32(struct Machine *, u64, u64); i64 Inc64(struct Machine *, u64, u64); i64 Dec8(struct Machine *, u64, u64); i64 Dec16(struct Machine *, u64, u64); i64 Dec32(struct Machine *, u64, u64); i64 Dec64(struct Machine *, u64, u64); i64 Shr8(struct Machine *, u64, u64); i64 Shr16(struct Machine *, u64, u64); i64 Shr32(struct Machine *, u64, u64); i64 Shr64(struct Machine *, u64, u64); i64 Shl8(struct Machine *, u64, u64); i64 Shl16(struct Machine *, u64, u64); i64 Shl32(struct Machine *, u64, u64); i64 Shl64(struct Machine *, u64, u64); i64 Sar8(struct Machine *, u64, u64); i64 Sar16(struct Machine *, u64, u64); i64 Sar32(struct Machine *, u64, u64); i64 Sar64(struct Machine *, u64, u64); i64 Rol8(struct Machine *, u64, u64); i64 Rol16(struct Machine *, u64, u64); i64 Rol32(struct Machine *, u64, u64); i64 Rol64(struct Machine *, u64, u64); i64 Ror8(struct Machine *, u64, u64); i64 Ror16(struct Machine *, u64, u64); i64 Ror32(struct Machine *, u64, u64); i64 Ror64(struct Machine *, u64, u64); i64 Rcr8(struct Machine *, u64, u64); i64 Rcr16(struct Machine *, u64, u64); i64 Rcr32(struct Machine *, u64, u64); i64 Rcr64(struct Machine *, u64, u64); i64 Rcl8(struct Machine *, u64, u64); i64 Rcl16(struct Machine *, u64, u64); i64 Rcl32(struct Machine *, u64, u64); i64 Rcl64(struct Machine *, u64, u64); u64 BsuDoubleShift(struct Machine *, int, u64, u64, u8, bool); i64 Adcx32(u64, u64, struct Machine *); i64 Adcx64(u64, u64, struct Machine *); i64 Adox32(u64, u64, struct Machine *); i64 Adox64(u64, u64, struct Machine *); #ifndef HAVE_JIT #define kAluFast kAlu #endif // the combinations of needed flags for which we can use kAluFast[]; // the no-flags case (0) which uses kJustAlu[] is handled separately #if defined(HAVE_JIT) && X86_INTRINSICS #define CASE_ALU_FAST \ case CF: \ case ZF: \ case CF | ZF: \ case SF: \ case SF | CF: \ case SF | ZF: \ case SF | CF | ZF: \ case AF: \ case AF | CF: \ case AF | ZF: \ case AF | CF | ZF: \ case SF | AF: \ case SF | AF | CF: \ case SF | AF | ZF: \ case SF | AF | CF | ZF: \ case OF: \ case OF | CF: \ case OF | ZF: \ case OF | CF | ZF: \ case OF | SF: \ case OF | SF | CF: \ case OF | SF | ZF: \ case OF | SF | CF | ZF: \ case OF | AF: \ case OF | AF | CF: \ case OF | AF | ZF: \ case OF | AF | CF | ZF: \ case OF | SF | AF: \ case OF | SF | AF | CF: \ case OF | SF | AF | ZF: \ case OF | SF | AF | CF | ZF #else #define CASE_ALU_FAST \ case CF: \ case ZF: \ case CF | ZF #endif #endif /* BLINK_ALU_H_ */ ================================================ FILE: blink/alu1.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/alu.h" #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/stats.h" #include "blink/swap.h" #include "blink/thread.h" static void AluEb(P, aluop_f op) { u8 x, z, *p = GetModrmRegisterBytePointerWrite1(A); if (Lock(rde)) { x = atomic_load_explicit((_Atomic(u8) *)p, memory_order_acquire); do { z = Little8(op(m, Little8(x), 0)); } while (!atomic_compare_exchange_weak_explicit( (_Atomic(u8) *)p, &x, z, memory_order_release, memory_order_relaxed)); } else { Store8(p, op(m, Load8(p), 0)); } } void OpNotEb(P) { AluEb(A, Not8); } void OpNegEb(P) { AluEb(A, Neg8); } void Op0fe(P) { switch (ModrmReg(rde)) { case 0: AluEb(A, Inc8); break; case 1: AluEb(A, Dec8); break; default: OpUdImpl(m); } } static void AluEvqp(P, const aluop_f ops[4]) { u8 *p; aluop_f f; f = ops[WordLog2(rde)]; if (Rexw(rde)) { p = GetModrmRegisterWordPointerWrite8(A); #if CAN_64BIT if (Lock(rde) && !((uintptr_t)p & 7)) { u64 x, z; x = atomic_load_explicit((_Atomic(u64) *)p, memory_order_acquire); do { z = Little64(f(m, Little64(x), 0)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u64) *)p, &x, z, memory_order_release, memory_order_relaxed)); return; } #endif if (!Lock(rde)) { Store64(p, f(m, Load64(p), 0)); } else { LockBus(p); Store64Unlocked(p, f(m, Load64Unlocked(p), 0)); UnlockBus(p); } } else if (!Osz(rde)) { u32 x, z; p = GetModrmRegisterWordPointerWrite4(A); if (Lock(rde) && !((uintptr_t)p & 3)) { x = atomic_load_explicit((_Atomic(u32) *)p, memory_order_acquire); do { z = Little32(f(m, Little32(x), 0)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u32) *)p, &x, z, memory_order_release, memory_order_relaxed)); } else { if (Lock(rde)) LockBus(p); Store32(p, f(m, Load32(p), 0)); if (Lock(rde)) UnlockBus(p); } if (IsModrmRegister(rde)) { Put32(p + 4, 0); } } else { p = GetModrmRegisterWordPointerWrite2(A); if (Lock(rde) && !((uintptr_t)p & 1)) { u16 x, z; x = atomic_load_explicit((_Atomic(u16) *)p, memory_order_acquire); do { z = Little16(f(m, Little16(x), 0)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u16) *)p, &x, z, memory_order_release, memory_order_relaxed)); } else { if (Lock(rde)) LockBus(p); Store16(p, f(m, Load16(p), 0)); if (Lock(rde)) UnlockBus(p); } } } void OpNotEvqp(P) { AluEvqp(A, kAlu[ALU_NOT]); if (IsMakingPath(m) && !Lock(rde)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = machine "m" // call function "r0D", // PutRegOrMem(RexbRm, res0) kAlu[ALU_NOT][WordLog2(rde)]); } } void OpNegEvqp(P) { AluEvqp(A, kAlu[ALU_NEG]); if (IsMakingPath(m) && !Lock(rde)) { if (!GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "t" // arg0 = res0 "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) JustNeg); } else { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = machine "c" // call function "r0D", // PutRegOrMem(RexbRm, res0) kAlu[ALU_NEG][WordLog2(rde)]); } } } void OpIncEvqp(P) { AluEvqp(A, kAlu[ALU_INC]); if (IsMakingPath(m) && !Lock(rde)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = machine "c" // call function "r0D", // PutRegOrMem(RexbRm, res0) kAlu[ALU_INC][WordLog2(rde)]); } } void OpDecEvqp(P) { AluEvqp(A, kAlu[ALU_DEC]); if (IsMakingPath(m) && !Lock(rde)) { STATISTIC(++alu_ops); switch (GetNeededFlags(m, m->ip, ZF | SF | OF | AF | PF)) { case 0: STATISTIC(++alu_unflagged); Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "t" // arg0 = res0 "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) JustDec); break; case ZF: STATISTIC(++alu_simplified); Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) kFastDec[WordLog2(rde)]); break; default: Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = machine "c" // call function "r0D", // PutRegOrMem(RexbRm, res0) kAlu[ALU_DEC][WordLog2(rde)]); break; } } } ================================================ FILE: blink/alu2.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/alu.h" #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/stats.h" #include "blink/swap.h" #include "blink/thread.h" void LoadAluArgs(P) { if (IsMakingPath(m)) { if (IsModrmRegister(rde) && RexrReg(rde) == RexbRm(rde)) { Jitter(A, "A" // res0 = GetReg(RexrReg) "r0a2=" // arg2 = res0 "r0a1="); // arg1 = res0 } else { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0s1=" // sav1 = res0 "A" // res0 = GetReg(RexrReg) "r0a2=" // arg2 = res0 "s1a1="); // arg1 = sav1 } } } void LoadAluFlipArgs(P) { if (IsMakingPath(m)) { if (IsModrmRegister(rde) && RexrReg(rde) == RexbRm(rde)) { Jitter(A, "A" // res0 = GetReg(RexrReg) "r0a2=" // arg2 = res0 "r0a1="); // arg1 = res0 } else { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0s1=" // sav1 = res0 "A" // res0 = GetReg(RexrReg) "s1a2=" // arg2 = sav1 "r0a1="); // arg1 = res0 } } } void OpAlub(P) { u8 x, y, z, *p, *q; aluop_f f; f = kAlu[(Opcode(rde) & 070) >> 3][0]; p = GetModrmRegisterBytePointerWrite1(A); q = ByteRexrReg(m, rde); if (Lock(rde)) { x = atomic_load_explicit((_Atomic(u8) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u8) *)q, memory_order_relaxed); y = Little8(y); do { z = Little8(f(m, Little8(x), y)); } while (!atomic_compare_exchange_weak_explicit( (_Atomic(u8) *)p, &x, z, memory_order_release, memory_order_relaxed)); } else { x = Load8(p); y = Get8(q); z = f(m, x, y); Store8(p, z); } } void OpAluw(P) { u8 *p, *q; aluop_f f; int t, flags; q = RegRexrReg(m, rde); t = (Opcode(rde) & 070) >> 3; f = kAlu[t][RegLog2(rde)]; if (Rexw(rde)) { p = GetModrmRegisterWordPointerWrite8(A); #if CAN_64BIT if (Lock(rde) && !((uintptr_t)p & 7)) { u64 x, y, z; x = atomic_load_explicit((_Atomic(u64) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u64) *)q, memory_order_relaxed); y = Little64(y); do { z = Little64(f(m, Little64(x), y)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u64) *)p, &x, z, memory_order_release, memory_order_relaxed)); return; } #endif u64 x, y, z; /* The integrity of a bus lock is not affected by the alignment of the memory field. ──Intel V.3 §8.1.2.2 */ if (Lock(rde)) { LockBus(p); x = Load64Unlocked(p); y = Get64(q); z = f(m, x, y); Store64Unlocked(p, z); UnlockBus(p); } else { x = Load64(p); y = Get64(q); z = f(m, x, y); Store64(p, z); } } else if (!Osz(rde)) { u32 x, y, z; p = GetModrmRegisterWordPointerWrite4(A); if (IsModrmRegister(rde)) { Put32(p + 4, 0); } if (Lock(rde) && !((uintptr_t)p & 3)) { x = atomic_load_explicit((_Atomic(u32) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u32) *)q, memory_order_relaxed); y = Little32(y); do { z = Little32(f(m, Little32(x), y)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u32) *)p, &x, z, memory_order_release, memory_order_relaxed)); } else { if (Lock(rde)) LockBus(p); x = Load32(p); y = Get32(q); z = f(m, x, y); Store32(p, z); if (Lock(rde)) UnlockBus(p); } } else { u16 x, y, z; p = GetModrmRegisterWordPointerWrite2(A); if (Lock(rde) && !((uintptr_t)p & 1)) { x = atomic_load_explicit((_Atomic(u16) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u16) *)q, memory_order_relaxed); y = Little16(y); do { z = Little16(f(m, Little16(x), y)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u16) *)p, &x, z, memory_order_release, memory_order_relaxed)); } else { if (Lock(rde)) LockBus(p); x = Load16(p); y = Get16(q); z = f(m, x, y); Store16(p, z); if (Lock(rde)) UnlockBus(p); } } if (IsMakingPath(m) && !Lock(rde)) { STATISTIC(++alu_ops); flags = GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF); if (t == ALU_XOR && // RegLog2(rde) >= 2 && // IsModrmRegister(rde) && // RexrReg(rde) == RexbRm(rde)) { if (flags) { Jitter(A, "a1i" // arg1 = register index "m", // call micro-op RexrReg(rde), ZeroRegFlags); } else { Jitter(A, "s0a1=" // arg1 = machine "a0i" // arg0 = zero "m", // call micro-op (u64)0, kPutReg64[RexrReg(rde)]); } } else { LoadAluArgs(A); switch (flags) { case 0: STATISTIC(++alu_unflagged); if (GetFlagDeps(rde)) Jitter(A, "q"); // arg0 = machine Jitter(A, "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) kJustAlu[t]); break; CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "q" // arg0 = machine "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) kAluFast[t][RegLog2(rde)]); break; default: Jitter(A, "q" // arg0 = machine "c" // call function "r0D", // PutRegOrMem(RexbRm, res0) f); break; } } } } ================================================ FILE: blink/alui.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/alu.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/flags.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/stats.h" static void AluiRo(P, const aluop_f ops[4], const aluop_f fast[4]) { ops[RegLog2(rde)](m, ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A)), uimm0); if (IsMakingPath(m)) { STATISTIC(++alu_ops); switch (GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { case 0: CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "a2i" // arg2 = uimm0 "r0a1=" // arg1 = res0 "q" // arg0 = sav0 (machine) "m", // call micro-op uimm0, fast[RegLog2(rde)]); break; default: Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "a2i" // arg2 = uimm0 "r0a1=" // arg1 = res0 "q" // arg0 = sav0 (machine) "c", // call function uimm0, ops[RegLog2(rde)]); break; } } } static void AluiUnlocked(P, u8 *p, aluop_f op) { WriteRegisterOrMemoryBW(rde, p, op(m, ReadRegisterOrMemoryBW(rde, p), uimm0)); if (IsMakingPath(m)) { STATISTIC(++alu_ops); Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "a2i", // arg2 = uimm0 uimm0); switch (GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { case 0: STATISTIC(++alu_unflagged); if (GetFlagDeps(rde)) { Jitter(A, "q"); // arg0 = sav0 (machine) } Jitter(A, "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) kJustAlu[ModrmReg(rde)]); break; CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "q" // arg0 = sav0 (machine) "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) kAluFast[ModrmReg(rde)][RegLog2(rde)]); break; default: Jitter(A, "q" // arg0 = sav0 (machine) "c" // call function "r0D", // PutRegOrMem(RexbRm, res0) op); break; } } } static void AluiLocked(P, u8 *p, aluop_f op) { switch (RegLog2(rde)) { case 3: #if CAN_64BIT if (!((uintptr_t)p & 7)) { u64 x, z; x = atomic_load_explicit((_Atomic(u64) *)p, memory_order_acquire); do { z = Little64(op(m, Little64(x), uimm0)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u64) *)p, &x, z, memory_order_release, memory_order_relaxed)); return; } #endif LockBus(p); Store64Unlocked(p, op(m, Load64Unlocked(p), uimm0)); UnlockBus(p); break; case 2: if (!((uintptr_t)p & 3)) { u32 x, z; x = atomic_load_explicit((_Atomic(u32) *)p, memory_order_acquire); do { z = Little32(op(m, Little32(x), uimm0)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u32) *)p, &x, z, memory_order_release, memory_order_relaxed)); return; } LockBus(p); Store32(p, op(m, Load32(p), uimm0)); UnlockBus(p); break; case 1: if (!((uintptr_t)p & 1)) { u16 x, z; x = atomic_load_explicit((_Atomic(u16) *)p, memory_order_acquire); do { z = Little16(op(m, Little16(x), uimm0)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u16) *)p, &x, z, memory_order_release, memory_order_relaxed)); return; } LockBus(p); Store16(p, op(m, Load16(p), uimm0)); UnlockBus(p); break; case 0: { u8 x, z; x = atomic_load_explicit((_Atomic(u8) *)p, memory_order_acquire); do { z = Little8(op(m, Little8(x), uimm0)); } while (!atomic_compare_exchange_weak_explicit( (_Atomic(u8) *)p, &x, z, memory_order_release, memory_order_relaxed)); break; } default: __builtin_unreachable(); } } static void Alui(P) { u8 *p; aluop_f op; p = GetModrmWriteBW(A); op = kAlu[ModrmReg(rde)][RegLog2(rde)]; if (Lock(rde) && !IsModrmRegister(rde)) { AluiLocked(A, p, op); } else { AluiUnlocked(A, p, op); } } void OpAlui(P) { if (ModrmReg(rde) == ALU_CMP) { if (IsMakingPath(m) && FuseBranchCmp(A, true)) { kAlu[ALU_SUB][RegLog2(rde)]( m, ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A)), uimm0); } else { AluiRo(A, kAlu[ALU_SUB], kAluFast[ALU_SUB]); } } else { Alui(A); } } void OpTest(P) { AluiRo(A, kAlu[ALU_AND], kAluFast[ALU_AND]); } ================================================ FILE: blink/ancillary.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/ancillary.h" #include #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/fds.h" #include "blink/linux.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/util.h" #include "blink/vfs.h" #ifndef DISABLE_SOCKETS #ifndef DISABLE_ANCILLARY #ifndef CMSG_LEN static socklen_t CMSG_LEN(size_t len) { return (CMSG_DATA((struct cmsghdr *)0) - (unsigned char *)0) + len; } #endif #ifndef CMSG_SPACE static socklen_t CMSG_SPACE(size_t len) { struct msghdr msg; struct cmsghdr cmsg; msg.msg_control = &cmsg; msg.msg_controllen = -1; cmsg.cmsg_len = CMSG_LEN(len); return (char *)CMSG_NXTHDR(&msg, &cmsg) - (char *)&cmsg; } #endif /** * @fileoverview Ancillary Socket Data Marshalling * * This module marshals `msg_control` for sendmsg() and recvmsg(), which * is used by UNIX domain sockets to perform tricks such as sharing file * descriptors between processes and X11 server authentication. */ static int AppendCmsg(struct Machine *m, struct msghdr *msg, int level, int type, const void *data, size_t size) { struct cmsghdr *cmsg; if (!msg->msg_control && !(msg->msg_control = AddToFreeList(m, calloc(1, kMaxAncillary)))) { return -1; } if (msg->msg_controllen + CMSG_SPACE(size) > kMaxAncillary) { LOGF("kMaxAncillary exceeded"); return enomem(); } cmsg = (struct cmsghdr *)((u8 *)msg->msg_control + msg->msg_controllen); cmsg->cmsg_len = CMSG_LEN(size); cmsg->cmsg_level = level; cmsg->cmsg_type = type; memcpy(CMSG_DATA(cmsg), data, size); msg->msg_controllen += CMSG_SPACE(size); return 0; } #ifdef HAVE_SCM_CREDENTIALS static int SendScmCredentials(struct Machine *m, struct msghdr *msg, const struct ucred_linux *payload, size_t elements) { struct ucred ucred; if (elements != 1) return einval(); ucred.pid = Read32(payload->pid); ucred.uid = Read32(payload->uid); ucred.gid = Read32(payload->gid); SYS_LOGF("SendScmCredentials(pid=%d, uid=%d, gid=%d)", ucred.pid, ucred.uid, ucred.gid); return AppendCmsg(m, msg, SOL_SOCKET, SCM_CREDENTIALS, &ucred, sizeof(ucred)); } #endif #ifdef SCM_RIGHTS static int SendScmRights(struct Machine *m, struct msghdr *msg, const u8 *payload, size_t elements) { size_t i; int fd[SCM_MAX_FD_LINUX]; if (elements > SCM_MAX_FD_LINUX) { LOGF("too many scm_rights fds"); return einval(); } for (i = 0; i < elements; ++i) { fd[i] = Read32(payload + i * 4); SYS_LOGF("SendScmRights(fd=%d)", fd[i]); } return AppendCmsg(m, msg, SOL_SOCKET, SCM_RIGHTS, &fd, i * sizeof(int)); } #endif static ssize_t GetAncillaryElementLength(const struct cmsghdr_linux *gcmsg) { switch (Read32(gcmsg->level)) { case SOL_SOCKET_LINUX: switch (Read32(gcmsg->type)) { #ifdef SCM_RIGHTS case SCM_RIGHTS_LINUX: return 4; #endif #ifdef HAVE_SCM_CREDENTIALS #ifndef DISABLE_NONPOSIX case SCM_CREDENTIALS_LINUX: return sizeof(struct ucred_linux); #endif #endif default: break; } default: break; } LOGF("%s ancillary level=%d type=%d", "unsupported", Read32(gcmsg->level), Read32(gcmsg->type)); return einval(); } int SendAncillary(struct Machine *m, struct msghdr *msg, const struct msghdr_linux *gm) { ssize_t rc; u32 len, need; void *payload; size_t avail, i, space, elements; const struct cmsghdr_linux *gcmsg; for (i = 0; (avail = Read64(gm->controllen) - i); i += space) { if (sizeof(*gcmsg) > avail) { LOGF("ancillary corrupted"); return einval(); } if (!(gcmsg = (const struct cmsghdr_linux *)SchlepR( m, Read64(gm->control) + i, sizeof(*gcmsg)))) { return -1; } len = Read32(gcmsg->len); if (len > ROUNDUP(sizeof(*gcmsg), 8)) { len -= ROUNDUP(sizeof(*gcmsg), 8); } else { len = 0; } need = ROUNDUP(sizeof(*gcmsg), 8) + len; space = ROUNDUP(sizeof(*gcmsg), 8) + ROUNDUP(len, 8); if (space > avail) space = avail; if (need > avail) { ThisCorruption: LOGF("ancillary corrupted len=%u level=%u type=%u avail=%zu need=%u", len, Read32(gcmsg->level), Read32(gcmsg->type), avail, (unsigned)need); return einval(); } if ((rc = GetAncillaryElementLength(gcmsg)) == -1) { return -1; } if (len) { if (!(payload = SchlepR(m, Read64(gm->control) + i + ROUNDUP(sizeof(*gcmsg), 8), ROUNDUP(len, 8)))) { return -1; } if ((need = rc) && need <= len) { elements = len / need; if (len % need != 0) { goto ThisCorruption; } } else { goto ThisCorruption; } } else { payload = 0; elements = 0; } switch (Read32(gcmsg->level)) { case SOL_SOCKET_LINUX: switch (Read32(gcmsg->type)) { #ifdef SCM_RIGHTS case SCM_RIGHTS_LINUX: if (SendScmRights(m, msg, (const u8 *)payload, elements) == -1) return -1; break; #endif #ifdef HAVE_SCM_CREDENTIALS #ifndef DISABLE_NONPOSIX case SCM_CREDENTIALS_LINUX: if (SendScmCredentials(m, msg, (const struct ucred_linux *)payload, elements) == -1) return -1; break; #endif #endif default: unassert(!"inconsistent ancillary type"); __builtin_unreachable(); } break; default: unassert(!"inconsistent ancillary level"); __builtin_unreachable(); } } return 0; } static i64 CopyCmsg(struct Machine *m, struct msghdr_linux *gm, int level, int type, void *data, size_t len, u64 i) { i64 control; size_t hdrspace; struct cmsghdr_linux gcmsg; hdrspace = ROUNDUP(sizeof(gcmsg), 8); Write64(gcmsg.len, hdrspace + len); Write32(gcmsg.level, level); Write32(gcmsg.type, type); control = Read64(gm->control); unassert(CopyToUserWrite(m, control + i, &gcmsg, sizeof(gcmsg)) != -1); unassert(CopyToUserWrite(m, control + i + hdrspace, data, len) != -1); return hdrspace + ROUNDUP(len, 8); } static void TrackScmRightsFd(struct Machine *m, int fildes, int flags) { int oflags; SYS_LOGF("ReceiveScmRights(fd=%d)", fildes); unassert((oflags = VfsFcntl(fildes, F_GETFL, 0)) != -1); InheritFd(AddFd( &m->system->fds, fildes, oflags | O_RDWR | (flags & MSG_CMSG_CLOEXEC_LINUX ? O_CLOEXEC : 0))); #ifndef MSG_CMSG_CLOEXEC if (flags & MSG_CMSG_CLOEXEC_LINUX) { unassert(!VfsFcntl(fildes, F_SETFD, FD_CLOEXEC)); } #endif } #ifdef SCM_RIGHTS static i64 ReceiveScmRights(struct Machine *m, struct msghdr_linux *gm, struct cmsghdr *cmsg, u64 offset, int flags) { const int *p, *e; size_t space, avail; size_t i, received, relayable; u8 fd[SCM_MAX_FD_LINUX][4]; // determine how many file descriptors we received from the host p = (const int *)CMSG_DATA(cmsg); e = (const int *)((const u8 *)cmsg + cmsg->cmsg_len); received = e - p; unassert(received > 0); avail = Read64(gm->controllen) - offset; space = ROUNDUP(sizeof(struct cmsghdr_linux), 8); // determine how many file descriptors we can relay to the guest if (space + 4 < avail) { relayable = MIN(MIN(received, (avail - space) / 4), SCM_MAX_FD_LINUX); if (relayable != received) { LOGF("truncated %zd scm_rights fds", received - relayable); Write32(gm->flags, Read32(gm->flags) | MSG_CTRUNC_LINUX); } // serialize fds for (i = 0; i < relayable; ++i) { Write32(fd[i], p[i]); TrackScmRightsFd(m, p[i], flags); } // close excess fds for (i = relayable; i < received; ++i) { close(p[i]); } return CopyCmsg(m, gm, SOL_SOCKET_LINUX, SCM_RIGHTS_LINUX, fd, relayable * 4, offset); } else { // truncate the control message because there wasn't enough // room in the guest's memory for a single file descriptor. for (i = 0; i < received; ++i) { close(p[i]); } return 0; } } #endif #ifdef HAVE_SCM_CREDENTIALS static i64 ReceiveScmCredentials(struct Machine *m, struct msghdr_linux *gm, struct cmsghdr *cmsg, u64 offset) { struct ucred_linux gucred; const struct ucred *ucred; ucred = (const struct ucred *)CMSG_DATA(cmsg); SYS_LOGF("ReceiveScmCredentials(pid=%d, uid=%d, gid=%d)", ucred->pid, ucred->uid, ucred->gid); if (offset + ROUNDUP(sizeof(struct cmsghdr_linux), 8) + ROUNDUP(sizeof(gucred), 8) <= Read64(gm->controllen)) { Write32(gucred.pid, ucred->pid); Write32(gucred.uid, ucred->uid); Write32(gucred.gid, ucred->gid); return CopyCmsg(m, gm, SOL_SOCKET_LINUX, SCM_CREDENTIALS_LINUX, &gucred, sizeof(gucred), offset); } else { return 0; } } #endif static i64 ReceiveControlMessage(struct Machine *m, struct msghdr_linux *gm, struct cmsghdr *cmsg, u64 offset, int flags) { if (cmsg->cmsg_level == SOL_SOCKET) { #ifdef SCM_RIGHTS if (cmsg->cmsg_type == SCM_RIGHTS) { return ReceiveScmRights(m, gm, cmsg, offset, flags); } #endif #ifdef HAVE_SCM_CREDENTIALS #ifndef DISABLE_NONPOSIX if (cmsg->cmsg_type == SCM_CREDENTIALS) { return ReceiveScmCredentials(m, gm, cmsg, offset); } #endif #endif } LOGF("%s ancillary level=%d type=%d", "unsupported", cmsg->cmsg_level, cmsg->cmsg_type); return enotsup(); } int ReceiveAncillary(struct Machine *m, struct msghdr_linux *gm, struct msghdr *msg, int flags) { ssize_t rc; u64 offset = 0; struct cmsghdr *cmsg; if ((cmsg = CMSG_FIRSTHDR(msg))) { do { switch ((rc = ReceiveControlMessage(m, gm, cmsg, offset, flags))) { case -1: return -1; case 0: LOGF("%s ancillary level=%d type=%d", "truncated", cmsg->cmsg_level, cmsg->cmsg_type); Write32(gm->flags, Read32(gm->flags) | MSG_CTRUNC_LINUX); offset = Read64(gm->controllen); break; default: offset += rc; break; } } while ((cmsg = CMSG_NXTHDR(msg, cmsg))); } Write64(gm->controllen, offset); return 0; } #endif /* DISABLE_ANCILLARY */ #endif /* DISABLE_SOCKETS */ ================================================ FILE: blink/ancillary.h ================================================ #ifndef COSMOPOLITAN_BLINK_ANCILLARY_H_ #define COSMOPOLITAN_BLINK_ANCILLARY_H_ #include #include "blink/machine.h" int SendAncillary(struct Machine *, struct msghdr *, const struct msghdr_linux *); int ReceiveAncillary(struct Machine *, struct msghdr_linux *, struct msghdr *, int); #endif /* COSMOPOLITAN_BLINK_ANCILLARY_H_ */ ================================================ FILE: blink/argv.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/assert.h" #include "blink/endian.h" #include "blink/flag.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/map.h" #include "blink/syscall.h" #include "blink/util.h" #define STACKALIGN 16 #define PUSH_AUXV(k, v) \ --naux; \ *--p = v; \ *--p = k static size_t GetArgListLen(char **p) { size_t n; for (n = 0; *p; ++p) ++n; return n; } static i64 PushBuffer(struct Machine *m, void *s, size_t n) { i64 sp = Get64(m->sp) - n; Put64(m->sp, sp); unassert(!CopyToUser(m, sp, s, n)); return sp; } static i64 PushString(struct Machine *m, char *s) { if (s) { return PushBuffer(m, s, strlen(s) + 1); } else { return 0; } } static long GetGuestPageSize(struct Machine *m) { if (HasLinearMapping()) { return FLAG_pagesize; } else { return 4096; } } void LoadArgv(struct Machine *m, char *execfn, char *prog, char **args, char **vars, u8 rng[16]) { u8 *bytes; struct Elf *elf; i64 sp, dx, *p, *bloc; size_t i, narg, nenv, naux, nall; elf = &m->system->elf; naux = 10; if (elf->at_entry) { naux += 4; if (elf->at_base != -1) { naux += 1; } } nenv = GetArgListLen(vars); narg = GetArgListLen(args); nall = 1 + narg + 1 + nenv + 1 + naux * 2; bloc = (i64 *)malloc(sizeof(i64) * nall); p = bloc + nall; dx = PushString(m, prog); PUSH_AUXV(0, 0); PUSH_AUXV(AT_UID_LINUX, getuid()); PUSH_AUXV(AT_EUID_LINUX, geteuid()); PUSH_AUXV(AT_GID_LINUX, getgid()); PUSH_AUXV(AT_EGID_LINUX, getegid()); PUSH_AUXV(AT_SECURE_LINUX, IsProcessTainted()); PUSH_AUXV(AT_PAGESZ_LINUX, GetGuestPageSize(m)); PUSH_AUXV(AT_CLKTCK_LINUX, sysconf(_SC_CLK_TCK)); PUSH_AUXV(AT_RANDOM_LINUX, PushBuffer(m, rng, 16)); PUSH_AUXV(AT_EXECFN_LINUX, PushString(m, execfn)); if (elf->at_entry) { PUSH_AUXV(AT_PHDR_LINUX, elf->at_phdr); PUSH_AUXV(AT_PHENT_LINUX, elf->at_phent); PUSH_AUXV(AT_PHNUM_LINUX, elf->at_phnum); PUSH_AUXV(AT_ENTRY_LINUX, elf->at_entry); if (elf->at_base != -1) { PUSH_AUXV(AT_BASE_LINUX, elf->at_base); } } unassert(!naux); for (*--p = 0, i = nenv; i--;) *--p = PushString(m, vars[i]); for (*--p = 0, i = narg; i--;) *--p = PushString(m, args[i]); *--p = narg; sp = Read64(m->sp); while ((sp - nall * sizeof(i64)) & (STACKALIGN - 1)) --sp; sp -= nall * sizeof(i64); Write64(m->sp, sp); Write64(m->dx, dx); Write64(m->di, 0); /* or ape detects freebsd */ bytes = (u8 *)malloc(nall * 8); for (i = 0; i < nall; ++i) { Write64(bytes + i * 8, bloc[i]); } unassert(!CopyToUser(m, sp, bytes, nall * 8)); free(bytes); free(bloc); } ================================================ FILE: blink/assert.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/assert.h" #include #include #include "blink/debug.h" #include "blink/flag.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/thread.h" #include "blink/util.h" void AssertFailed(const char *file, int line, const char *msg) { _Thread_local static bool noreentry; _Thread_local static char bp[20000]; WriteErrorString("assertion failed\n"); if (!noreentry) { noreentry = true; FLAG_nologstderr = false; RestoreIp(g_machine); snprintf(bp, sizeof(bp), "%s:%d:%d assertion failed: %s (%s)\n" "\t%s\n" "\t%s\n", file, line, g_machine ? g_machine->tid : 666, msg, DescribeHostErrno(errno), GetBacktrace(g_machine), GetBlinkBacktrace()); WriteErrorString(bp); } Abort(); } ================================================ FILE: blink/assert.h ================================================ #ifndef BLINK_ASSERT_H_ #define BLINK_ASSERT_H_ #include "blink/builtin.h" #ifndef NDEBUG #define unassert(x) \ do { \ if (__builtin_expect(!(x), 0)) { \ AssertFailed(__FILE__, __LINE__, #x); \ } \ } while (0) #elif (__clang__ + __INTEL_COMPILER + _MSC_VER + 0 || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405) #define unassert(x) \ do { \ if (__builtin_expect(!(x), 0)) { \ __builtin_unreachable(); \ } \ } while (0) #else #define unassert(x) ((void)(x)) #endif _Noreturn void AssertFailed(const char *, int, const char *); #endif /* BLINK_ASSERT_H_ */ ================================================ FILE: blink/atomic.h ================================================ #ifndef BLINK_ATOMIC_H_ #define BLINK_ATOMIC_H_ #include "blink/builtin.h" #include "blink/thread.h" #if defined(HAVE_FORK) || defined(HAVE_THREADS) #include #else #include "blink/types.h" #define _Atomic(t) t #define atomic_thread_fence(order) (void)0 #define atomic_load_explicit(ptr, order) *(ptr) #define atomic_store_explicit(ptr, val, order) (*(ptr) = (val)) #define atomic_exchange(ptr, val) \ (sizeof(*(ptr)) == 8 ? Exchange64((u64 *)(ptr), val) \ : sizeof(*(ptr)) == 4 ? Exchange32((u32 *)(ptr), val) \ : sizeof(*(ptr)) == 2 ? Exchange16((u16 *)(ptr), val) \ : Exchange8((u8 *)(ptr), val)) #define atomic_exchange_explicit(ptr, val, order) atomic_exchange(ptr, val) #define atomic_compare_exchange_strong_explicit( \ ifthing, isequaltome, replaceitwithme, success_order, failure_order) \ (*(ifthing) == *(isequaltome) \ ? (*(isequaltome) = *(ifthing), *(ifthing) = (replaceitwithme), true) \ : (*(isequaltome) = *(ifthing), false)) #define atomic_compare_exchange_weak_explicit(x, y, z, s, f) \ atomic_compare_exchange_strong_explicit(x, y, z, s, f) #define atomic_fetch_add_explicit(ptr, delta, order) \ (sizeof(*(ptr)) == 8 ? FetchAdd64((u64 *)(ptr), delta) \ : sizeof(*(ptr)) == 4 ? FetchAdd32((u32 *)(ptr), delta) \ : FetchAddAbort()) static inline u64 Exchange64(u64 *ptr, u64 val) { u64 tmp = *ptr; *ptr = val; return tmp; } static inline u32 Exchange32(u32 *ptr, u32 val) { u32 tmp = *ptr; *ptr = val; return tmp; } static inline u16 Exchange16(u16 *ptr, u16 val) { u16 tmp = *ptr; *ptr = val; return tmp; } static inline u8 Exchange8(u8 *ptr, u8 val) { u8 tmp = *ptr; *ptr = val; return tmp; } static inline u64 FetchAdd64(u64 *ptr, u64 val) { u64 res = *ptr; *ptr += val; return res; } static inline u32 FetchAdd32(u32 *ptr, u32 val) { u32 res = *ptr; *ptr += val; return res; } static inline u32 FetchAddAbort(void) { volatile u32 x = 0; return 1 / x; } #endif /* !HAVE_FORK && !HAVE_THREADS */ #endif /* BLINK_ATOMIC_H_ */ ================================================ FILE: blink/bcd.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/builtin.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/machine.h" #include "blink/x86.h" static relegated dontinline void BcdFlags(struct Machine *m, bool af, bool cf) { m->flags = SetFlag(m->flags, FLAGS_CF, cf); m->flags = SetFlag(m->flags, FLAGS_AF, af); m->flags = SetFlag(m->flags, FLAGS_ZF, !m->al); m->flags = SetFlag(m->flags, FLAGS_SF, (i8)m->al < 0); m->flags = SetLazyParityByte(m->flags, m->al); } relegated void OpDas(P) { u8 al; bool af, cf; al = m->al; af = cf = 0; if ((al & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) { cf = m->al < 6 || GetFlag(m->flags, FLAGS_CF); m->al -= 0x06; af = 1; } if (al > 0x99 || GetFlag(m->flags, FLAGS_CF)) { m->al -= 0x60; cf = 1; } BcdFlags(m, af, cf); } relegated void OpAaa(P) { bool af, cf; af = cf = 0; if ((m->al & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) { cf = m->al < 6 || GetFlag(m->flags, FLAGS_CF); Put16(m->ax, Get16(m->ax) + 0x106); af = cf = 1; } m->al &= 0x0f; BcdFlags(m, af, cf); } relegated void OpAas(P) { bool af, cf; af = cf = 0; if ((m->al & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) { cf = m->al < 6 || GetFlag(m->flags, FLAGS_CF); Put16(m->ax, Get16(m->ax) - 0x106); af = cf = 1; } m->al &= 0x0f; BcdFlags(m, af, cf); } relegated void OpAam(P) { u8 imm = m->xedd->op.uimm0; if (!imm) RaiseDivideError(m); m->ah = m->al / imm; m->al = m->al % imm; BcdFlags(m, 0, 0); } relegated void OpAad(P) { u8 imm = m->xedd->op.uimm0; Put16(m->ax, (m->ah * imm + m->al) & 255); BcdFlags(m, 0, 0); } // http://www.righto.com/2023/01/understanding-x86s-decimal-adjust-after.html relegated void OpDaa(P) { u8 old_al; old_al = m->al; if ((m->al & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) { m->al += 6; m->flags = SetFlag(m->flags, FLAGS_AF, true); } if ((old_al > 0x99) || GetFlag(m->flags, FLAGS_CF)) { m->al += 0x60; m->flags = SetFlag(m->flags, FLAGS_CF, true); } } ================================================ FILE: blink/bda.h ================================================ #ifndef BLINK_BDA_H_ #define BLINK_BDA_H_ #include "blink/blinkenlights.h" #include "blink/machine.h" #include "blink/endian.h" #define GetBda8(o) Read8(m->system->real + 0x400 + (o)) #define SetBda8(o, v) Write8(m->system->real + 0x400 + (o), (v)) #define GetBda16(o) Read16(m->system->real + 0x400 + (o)) #define SetBda16(o, v) Write16(m->system->real + 0x400 + (o), (v)) #define GetBda32(o) Read32(m->system->real + 0x400 + (o)) #define SetBda32(o, v) Write32(m->system->real + 0x400 + (o), (v)) #define BdaCom1 GetBda16(0x00) #define SetBdaCom1(v) SetBda16(0x00, (v)) #define BdaEbda GetBda16(0x0E) #define SetBdaEbda(v) SetBda16(0x0E, (v)) #define BdaEquip GetBda16(0x10) #define SetBdaEquip(v) SetBda16(0x10, (v)) #define BdaMemsz GetBda16(0x13) #define SetBdaMemsz(v) SetBda16(0x13, (v)) #define BdaVmode GetBda8(0x49) #define SetBdaVmode(v) SetBda8(0x49, (v)) #define BdaCols GetBda16(0x4A) // returns actual # columns #define SetBdaCols(v) SetBda16(0x4A, (v)) // BIOS stores # columns #define BdaPagesz GetBda16(0x4C) #define SetBdaPagesz(v) SetBda16(0x4C, (v)) #define BdaCurx GetBda8(0x50) #define SetBdaCurx(v) SetBda8(0x50, (v)) #define BdaCury GetBda8(0x51) #define SetBdaCury(v) SetBda8(0x51, (v)) #define BdaCurend GetBda8(0x60) #define SetBdaCurend(v) SetBda8(0x60, (v)) #define BdaCurstart GetBda8(0x61) #define SetBdaCurstart(v) SetBda8(0x61, (v)) #define BdaCurhidden ((BdaCurstart & 0x20) || (BdaCurstart > BdaCurend)) #define BdaCurpage GetBda8(0x62) #define SetBdaCurpage(v) SetBda8(0x62, (v)) #define BdaCrtc GetBda16(0x64) #define SetBdaCrtc(v) SetBda16(0x64, (v)) #define BdaTimer GetBda32(0x6C) #define SetBdaTimer(v) SetBda32(0x6C, (v)) #define Bda24hr GetBda8(0x70) #define SetBda24hr(v) SetBda8(0x70, (v)) #define BdaLines (GetBda8(0x84) + 1) // returns actual # lines #define SetBdaLines(v) SetBda8(0x84, (v) - 1) // BIOS stores # lines - 1 #endif /* BLINK_BDA_H_ */ ================================================ FILE: blink/bios.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/bda.h" #include "blink/biosrom.h" #include "blink/blinkenlights.h" #include "blink/bus.h" #include "blink/cga.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/loader.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/mda.h" #include "blink/pty.h" #include "blink/timespec.h" #include "blink/util.h" #include "blink/vfs.h" static const struct Chs { ssize_t imagesize; short c, h, s; bool isfloppy; } kChs[] = { {163840, 40, 1, 8, true}, // {184320, 40, 1, 9, true}, // {327680, 40, 2, 8, true}, // {368640, 40, 2, 9, true}, // {737280, 80, 2, 9, true}, // {1228800, 80, 2, 15, true}, // {1474560, 80, 2, 18, true}, // {2949120, 80, 2, 36, true}, // }; static off_t diskimagesize = 0; static int diskcyls = 1023; static int diskheads = 16; // default to 16 heads/cylinder, following QEMU static int disksects = 63; static bool diskisfloppy = false; static u64 prevday = 0; // day number of last call to int 0x1A, ah = 0, for // calculating elapsed midnight count static size_t GetLastIndex(size_t size, unsigned unit, int i, unsigned limit) { unsigned q, r; if (!size) return 0; q = size / unit; r = size % unit; if (!r) --q; q += i; if (q > limit) q = limit; return q; } static void OnDiskServiceReset(void) { m->ah = 0x00; SetCarry(false); } static void OnDiskServiceBadCommand(void) { m->ah = 0x01; SetCarry(true); } static void DetermineChs(void) { int i; struct stat st; off_t size = diskimagesize; if (size) return; // do nothing if disk geometry already detected unassert(!VfsStat(AT_FDCWD, m->system->elf.prog, &st, 0)); diskimagesize = size = st.st_size; for (i = 0; i < ARRAYLEN(kChs); ++i) { if (size == kChs[i].imagesize) { diskcyls = kChs[i].c; diskheads = kChs[i].h; disksects = kChs[i].s; diskisfloppy = kChs[i].isfloppy; return; } } } static bool DetermineChsAndSanityCheck(u8 drive) { DetermineChs(); if (diskisfloppy) { if ((drive & 0x80) != 0) { // reading from hard disk drive, but image is floppy image m->ah = 0x80; // drive not ready SetCarry(true); return false; } } else { if ((drive & 0x80) == 0) { // reading from floppy drive, but image is hard disk image m->ah = 0x80; // drive not ready SetCarry(true); return false; } } return true; } static void OnDiskServiceGetParams(void) { size_t lastsector, lastcylinder, lasthead; u8 drive = m->dl; if (!DetermineChsAndSanityCheck(drive)) return; lastcylinder = GetLastIndex(diskimagesize, 512 * disksects * diskheads, 0, 1023); lasthead = GetLastIndex(diskimagesize, 512 * disksects, 0, diskheads - 1); lastsector = GetLastIndex(diskimagesize, 512, 1, disksects); m->dl = 1; m->dh = lasthead; m->cl = lastcylinder >> 8 << 6 | lastsector; m->ch = lastcylinder; m->bl = 4; // CMOS drive type: 1.4M floppy m->ah = 0; if ((drive & 0x80) == 0) { u32 ddpt = GetDefaultBiosDisketteParamTable(); m->es.sel = ddpt >> 16; m->es.base = ddpt >> 16 << 4; Put16(m->di, (u16)ddpt); } SetCarry(false); } static void OnDiskServiceReadSectors(void) { int fd; i64 addr, size, rsize, ursize; i64 sectors, drive, head, cylinder, sector, offset; sectors = m->al; drive = m->dl; if (!DetermineChsAndSanityCheck(drive)) { m->al = 0x00; return; } head = m->dh; cylinder = (m->cl & 192) << 2 | m->ch; sector = (m->cl & 63) - 1; size = sectors * 512; offset = sector * 512 + head * 512 * disksects + cylinder * 512 * disksects * diskheads; ELF_LOGF("bios read sectors %" PRId64 " " "@ sector %" PRId64 " cylinder %" PRId64 " head %" PRId64 " drive %" PRId64 " offset %#" PRIx64 " from %s", sectors, sector, cylinder, head, drive, offset, m->system->elf.prog); addr = m->es.base + Get16(m->bx); if (addr >= kRealSize || size > kRealSize || addr + size > kRealSize) { LOGF("bios disk read exceeded real memory"); m->al = 0x00; m->ah = 0x02; // cannot find address mark SetCarry(true); return; } errno = 0; if ((fd = VfsOpen(AT_FDCWD, m->system->elf.prog, O_RDONLY, 0)) != -1 && (rsize = VfsPread(fd, m->system->real + addr, size, offset)) >= 0) { ursize = ROUNDUP(rsize, 512); if (ursize != rsize) { memset(m->system->real + addr + rsize, 0, ursize - rsize); } SetWriteAddr(m, addr, ursize); if (ursize == size) { m->ah = 0x00; // success SetCarry(false); } else { sectors = ursize / 512; LOGF("bios read sectors: partial read %" PRId64 " sectors", sectors); m->al = sectors; m->ah = 0x04; // sector not found SetCarry(true); } } else { LOGF("bios read sectors failed: %s", DescribeHostErrno(errno)); m->al = 0x00; m->ah = 0x0d; // invalid number of sector SetCarry(true); } VfsClose(fd); } static void OnDiskServiceProbeExtended(void) { u8 drive = m->dl; u16 magic = Get16(m->bx); (void)drive; if (magic == 0x55AA) { Put16(m->bx, 0xAA55); m->ah = 0x30; SetCarry(false); } else { m->ah = 0x01; SetCarry(true); } } static void OnDiskServiceReadSectorsExtended(void) { int fd; u8 drive = m->dl; i64 pkt_addr = m->ds.base + Get16(m->si), addr, sectors, size, lba, offset, rsize, ursize; u8 pkt_size, *pkt; SetReadAddr(m, pkt_addr, 1); pkt = m->system->real + pkt_addr; pkt_size = Get8(pkt); if ((pkt_size != 0x10 && pkt_size != 0x18) || Get8(pkt + 1) != 0) { m->ah = 0x01; SetCarry(true); } else { SetReadAddr(m, pkt_addr, pkt_size); addr = Read32(pkt + 4); if (addr == 0xFFFFFFFF && pkt_size == 0x18) { addr = Read64(pkt + 0x10); } else { addr = (addr >> 16 << 4) + (addr & 0xFFFF); } sectors = Read16(pkt + 2); size = sectors * 512; lba = Read32(pkt + 8); offset = lba * 512; ELF_LOGF("bios read sector ext " "lba=%" PRId64 " " "offset=%" PRIx64 " " "size=%" PRIx64, lba, offset, size); if (!DetermineChsAndSanityCheck(drive)) { Write16(pkt + 2, 0); return; } if (addr >= kRealSize || size > kRealSize || addr + size > kRealSize) { LOGF("bios disk read exceeded real memory"); SetWriteAddr(m, pkt_addr + 2, 2); Write16(pkt + 2, 0); m->ah = 0x02; // cannot find address mark SetCarry(true); return; } errno = 0; if ((fd = VfsOpen(AT_FDCWD, m->system->elf.prog, O_RDONLY, 0)) != -1 && (rsize = VfsPread(fd, m->system->real + addr, size, offset)) >= 0) { ursize = ROUNDUP(rsize, 512); if (ursize != rsize) { memset(m->system->real + addr + rsize, 0, ursize - rsize); } SetWriteAddr(m, addr, ursize); if (ursize == size) { m->ah = 0x00; // success SetCarry(false); } else { sectors = ursize / 512; LOGF("bios read sectors: partial read %" PRId64 " sectors", sectors); Write16(pkt + 2, sectors); m->ah = 0x04; // sector not found SetCarry(true); } } else { LOGF("bios read sector failed: %s", DescribeHostErrno(errno)); SetWriteAddr(m, pkt_addr + 2, 2); Write16(pkt + 2, 0); m->ah = 0x0d; // invalid number of sectors SetCarry(true); } VfsClose(fd); } } static void OnDiskService(void) { switch (m->ah) { case 0x00: OnDiskServiceReset(); break; case 0x02: OnDiskServiceReadSectors(); break; case 0x08: OnDiskServiceGetParams(); break; case 0x41: OnDiskServiceProbeExtended(); break; case 0x42: OnDiskServiceReadSectorsExtended(); break; default: OnDiskServiceBadCommand(); break; } } #define page_offsetw() 0 // TODO(ghaerr): implement screen pages #define video_ram() (m->system->real + ((vidya == 7) ? 0xb0000 : 0xb8000)) #define ATTR_DEFAULT 0x07 /* clear screen from x1,y1 up to but not including x2, y2 */ static void VidyaServiceClearScreen(int x1, int y1, int x2, int y2, u8 attr) { int x, y, xn; u16 *vram; unassert(x1 >= 0 && x1 <= BdaCols); unassert(x2 >= 0 && x2 <= BdaCols); unassert(y1 >= 0 && y1 <= BdaLines); unassert(y2 >= 0 && y2 <= BdaLines); vram = (u16 *)video_ram(); xn = BdaCols; for (y = y1; y < y2; y++) { for (x = x1; x < x2; x++) { vram[page_offsetw() + y * xn + x] = ' ' | (attr << 8); } } } /* clear line y from x1 up to and including x2 to attribute attr */ static void VidyaServiceClearLine(int x1, int x2, int y, u8 attr) { int x, xn; u16 *vram; unassert(x1 >= 0 && x1 < BdaCols); unassert(x2 >= 0 && x2 < BdaCols); unassert(y >= 0 && y < BdaLines); vram = (u16 *)video_ram(); xn = BdaCols; for (x = x1; x <= x2; x++) { vram[page_offsetw() + y * xn + x] = ' ' | (attr << 8); } } /* scroll video ram up from line y1 up to and including line y2 */ static void VidyaServiceScrollUp(int y1, int y2, u8 attr) { int xn, pitch; u8 *vid; unassert(y1 >= 0 && y1 < BdaLines); unassert(y2 >= 0 && y2 < BdaLines); xn = BdaCols; vid = video_ram() + (page_offsetw() + y1 * xn) * 2; pitch = xn * 2; memcpy(vid, vid + pitch, (BdaLines - y1) * pitch); VidyaServiceClearLine(0, xn - 1, y2, attr); } /* scroll adapter RAM down from line y1 up to and including line y2 */ static void VidyaServiceScrollDown(int y1, int y2, u8 attr) { int y, xn, pitch; u8 *vid; unassert(y1 >= 0 && y1 < BdaLines); unassert(y2 >= 0 && y2 < BdaLines); xn = BdaCols; vid = video_ram() + (page_offsetw() + (BdaLines - 1) * xn) * 2; pitch = xn * 2; y = y2; while (--y >= y1) { memcpy(vid, vid - pitch, pitch); vid -= pitch; } VidyaServiceClearLine(0, xn - 1, y1, attr); } static void OnVidyaServiceScrollUp(void) { unsigned i, n; unassert(m->cl < BdaCols); unassert(m->ch < BdaLines); unassert(m->dl < BdaCols); unassert(m->dh < BdaLines); n = m->al; if (n > BdaLines) n = BdaLines; if (n == 0) { VidyaServiceClearScreen(m->cl, m->ch, m->dl + 1, m->dh + 1, m->bh); } else { for (i = n; i; i--) { VidyaServiceScrollUp(m->ch, m->dh, m->bh); } } } static void OnVidyaServiceScrollDown(void) { unsigned i, n; unassert(m->cl < BdaCols); unassert(m->ch < BdaLines); unassert(m->dl < BdaCols); unassert(m->dh < BdaLines); n = m->al; if (n > BdaLines) n = BdaLines; if (n == 0) { VidyaServiceClearScreen(m->cl, m->ch, m->dl + 1, m->dh + 1, m->bh); } else { for (i = n; i; i--) { VidyaServiceScrollDown(m->ch, m->dh, m->bh); } } } /* write char/attr to video adapter ram */ static void VidyaServiceWriteCharacter(u8 ch, u8 attr, int n, bool useattr) { int x, y, xn, offset; u8 *vram; x = BdaCurx; y = BdaCury; unassert(y < BdaLines); unassert(x < BdaCols); xn = BdaCols; vram = video_ram(); while (n-- > 0) { offset = page_offsetw() + (y * xn + x) * 2; vram[offset] = ch; if (useattr) { vram[offset + 1] = attr; } if (++x >= xn) { x = 0; y++; } } } /* write char only (no attribute) as teletype output */ static void VidyaServiceWriteTeletype(u8 ch) { u8 attr; u8 *vram; int x, y, xn; x = BdaCurx; y = BdaCury; unassert(y < BdaLines); unassert(x < BdaCols); xn = BdaCols; vram = video_ram(); switch (ch) { case '\r': x = 0; goto update; case '\n': goto scroll; case '\b': if (x > 0) { x--; } goto update; case '\0': case '\a': return; } vram[page_offsetw() + (y * xn + x) * 2] = ch; if (++x >= xn) { x = 0; scroll: if (++y >= BdaLines) { y = BdaLines - 1; attr = vram[page_offsetw() + ((y * xn + BdaCols - 1) * 2) + 1]; VidyaServiceScrollUp(0, BdaLines - 1, attr); } } update: SetBdaCurx(x); SetBdaCury(y); } void VidyaServiceSetMode(int mode) { int cols, lines; vidya = mode; if (SpyAddress(m, 0xB0000)) { ptyisenabled = true; lines = 25; switch (mode) { case 0: // CGA 40x25 16-gray case 1: // CGA 40x25 16-color cols = 40; break; case 2: // CGA 80x25 16-gray case 3: // CGA 80x25 16-color case 7: // MDA 80x25 4-gray cols = 80; break; default: unassert(mode == kModePty); pty->conf &= ~kPtyNocursor; break; } if (mode == kModePty) return; SetBdaVmode(mode); SetBdaLines(lines); // EGA BIOS - max valid line # SetBdaCols(cols); SetBdaPagesz(cols * BdaLines * 2); SetBdaCurpage(0); SetBdaCurx(0); SetBdaCury(0); SetBdaCurstart(5); // cursor ▂ scan lines 5..7 of 0..7 SetBdaCurend(7); SetBdaCrtc(0x3D4); VidyaServiceClearScreen(0, 0, cols, BdaLines, ATTR_DEFAULT); } else { LOGF("maybe you forgot -r flag"); } } static void OnVidyaServiceGetMode(void) { m->al = vidya; m->ah = BdaCols; m->bh = 0; // page } static void OnVidyaServiceSetCursorType(void) { if (vidya == kModePty) { if (m->ch & 0x20) { pty->conf |= kPtyNocursor; } else { pty->conf &= ~kPtyNocursor; } } else { SetBdaCurstart(m->ch); SetBdaCurend(m->cl); } } static void OnVidyaServiceSetCursorPosition(void) { int x, y; x = m->dl; y = m->dh; if (vidya == kModePty) { PtySetX(pty, x); PtySetY(pty, y); } else { SetBdaCurx(x); SetBdaCury(y); } } static void OnVidyaServiceGetCursorPosition(void) { if (vidya == kModePty) { m->dh = pty->y; m->dl = pty->x; // cursor ▂ scan lines 5..7 of 0..7 and hidden bit 0x20 m->ch = 5 | !!(pty->conf & kPtyNocursor) << 5; m->cl = 7; } else { m->dh = BdaCury; m->dl = BdaCurx; m->ch = BdaCurstart; m->cl = BdaCurend; } } static void OnVidyaServiceReadCharacter(void) { u16 *vram; u16 chattr; int x, y, xn; x = BdaCurx; y = BdaCury; xn = BdaCols; vram = (u16 *)video_ram(); chattr = vram[page_offsetw() + y * xn + x]; Put16(m->ax, chattr); } /* write character and possibly attribute, no cursor change */ static void OnVidyaServiceWriteCharacter(bool useattr) { int i, n; u64 w; char *p, buf[32]; if (vidya != kModePty) { n = Get16(m->cx); unassert(n > 0 && n + BdaCurx <= BdaCols); unassert(BdaCury < BdaLines); VidyaServiceWriteCharacter(m->al, m->bl, n, useattr); return; } p = buf; p += FormatCga(m->bl, p); p = stpcpy(p, "\0337"); w = tpenc(GetVidyaByte(m->al)); do { *p++ = w; } while ((w >>= 8)); p = stpcpy(p, "\0338"); for (i = Get16(m->cx); i; --i) { PtyWrite(pty, buf, p - buf); } } static wint_t VidyaServiceXlatTeletype(u8 c) { switch (c) { case '\a': case '\b': case '\r': case '\n': case 0177: return c; default: return GetVidyaByte(c); } } static void OnVidyaServiceWriteTeletype(void) { int n; u64 w; char buf[12]; if (!ptyisenabled) { ptyisenabled = true; ReactiveDraw(); } if (vidya != kModePty) { VidyaServiceWriteTeletype(m->al); return; } n = 0 /* FormatCga(ATTR_DEFAULT, buf) */; w = tpenc(VidyaServiceXlatTeletype(m->al)); do { buf[n++] = w; } while ((w >>= 8)); PtyWrite(pty, buf, n); } static void OnVidyaService(void) { switch (m->ah) { case 0x00: VidyaServiceSetMode(m->al); break; case 0x01: OnVidyaServiceSetCursorType(); break; case 0x02: OnVidyaServiceSetCursorPosition(); break; case 0x03: OnVidyaServiceGetCursorPosition(); break; case 0x06: OnVidyaServiceScrollUp(); break; case 0x07: OnVidyaServiceScrollDown(); break; case 0x08: OnVidyaServiceReadCharacter(); break; case 0x09: OnVidyaServiceWriteCharacter(true); Redraw(false); DrawDisplayOnly(); break; case 0x0A: OnVidyaServiceWriteCharacter(false); Redraw(false); DrawDisplayOnly(); break; case 0x0E: OnVidyaServiceWriteTeletype(); Redraw(false); DrawDisplayOnly(); break; case 0x0F: OnVidyaServiceGetMode(); break; default: LOGF("Unimplemented vidya service 0x%x\n", m->ah); break; } } static void OnSerialServiceReset(void) { if (Get16(m->dx) == 0) { m->al = 0xb0; // following QEMU m->ah = 0x60; } else { m->al = 0x00; // Ralf Brown's Interrupt List says "AX = 9E00h if m->ah = 0x9e; // disconnected (ArtiCom)" } } static void OnSerialService(void) { switch (m->ah) { case 0x00: OnSerialServiceReset(); break; default: m->al = 0x00; m->ah = 0x9e; break; } } /* Convert from ANSI keyboard sequence to scancode */ int AnsiToScancode(char *buf, int n) { if (n >= 1 && buf[0] == 033) { if (buf[1] == '[') { if (n == 3) { /* xterm sequences */ switch (buf[2]) { /* ESC [ A etc */ case 'A': return 0x48; // kUpArrow case 'B': return 0x50; // kDownArrow case 'C': return 0x4D; // kRightArrow case 'D': return 0x4B; // kLeftArrow case 'F': return 0x4F; // kEnd case 'H': return 0x47; // kHome } } else if (n == 4 && buf[2] == '1') { /* ESC [ 1 P etc */ switch (buf[3]) { case 'P': return 0x3B; // kF1 case 'Q': return 0x3C; // kF2 case 'R': return 0x3D; // kF3 case 'S': return 0x3E; // kF4 } } if (n > 3 && buf[n - 1] == '~') { /* vt sequences */ switch (atoi(buf + 2)) { case 1: return 0x47; // kHome case 2: return 0x52; // kInsert case 3: return 0x53; // kDelete case 4: return 0x4F; // kEnd case 5: return 0x49; // kPageUp case 6: return 0x51; // kPageDown case 7: return 0x47; // kHome case 8: return 0x4F; // kEnd case 11: return 0x3B; // kF1 case 12: return 0x3C; // kF2 case 13: return 0x3D; // kF3 case 14: return 0x3E; // kF4 case 15: return 0x3F; // kF5 case 17: return 0x40; // kF6 case 18: return 0x41; // kF7 case 19: return 0x42; // kF8 case 20: return 0x43; // kF9 case 21: return 0x44; // kF10 case 23: return 0x85; // kF11 case 24: return 0x86; // kF12 } } } } return 0; } static bool savechar; // TODO(ghaerr): implement kbd input queue static u8 saveah; static u8 saveal; static void OnKeyboardServiceReadKeyPress(void) { uint8_t b; ssize_t rc; static char buf[32]; static size_t pending; LOGF("OnKeyboardServiceReadKeyPress"); if (savechar) { savechar = false; m->ah = saveah; m->al = saveal; return; } if (!ptyisenabled) { ptyisenabled = true; ReactiveDraw(); } pty->conf |= kPtyBlinkcursor; if (!pending) { rc = ReadAnsi(ttyin, buf, sizeof(buf)); if (rc > 0) { pending = rc; } else { HandleAppReadInterrupt(rc != -1 || errno != EINTR); return; } } pty->conf &= ~kPtyBlinkcursor; unassert((int)pending > 0 && pending < 32); ReactiveDraw(); if (m->metal) { int r = AnsiToScancode(buf, pending); if (r) { m->al = 0; m->ah = r; pending = 0; return; } } b = buf[0]; if (pending > 1) { memmove(buf, buf + 1, pending - 1); } --pending; if (b == 0177) b = '\b'; m->al = b; m->ah = 0; } static void OnKeyboardServiceCheckKeyPress(void) { if (savechar) { m->ah = saveah; m->al = saveal; return; } bool b = HasPendingKeyboard(); m->flags = SetFlag(m->flags, FLAGS_ZF, !b); /* ZF=0 if key pressed */ if (b) { OnKeyboardServiceReadKeyPress(); savechar = true; saveah = m->ah; saveal = m->al; } else { m->ah = 0; m->al = 0; } } static void OnKeyboardService(void) { switch (m->ah) { case 0x00: OnKeyboardServiceReadKeyPress(); break; case 0x01: OnKeyboardServiceCheckKeyPress(); break; default: break; } } static void OnApmService(void) { if (Get16(m->ax) == 0x5300 && Get16(m->bx) == 0x0000) { Put16(m->bx, 'P' << 8 | 'M'); SetCarry(false); } else if (Get16(m->ax) == 0x5301 && Get16(m->bx) == 0x0000) { SetCarry(false); } else if (Get16(m->ax) == 0x5307 && m->bl == 1 && m->cl == 3) { LOGF("APM SHUTDOWN"); exit(EXIT_SUCCESS); } else { SetCarry(true); } } static void OnE820(void) { i64 addr; u8 p[20]; addr = m->es.base + Get16(m->di); if (Get32(m->dx) == 0x534D4150 && Get32(m->cx) == 24 && addr + (int)sizeof(p) <= kRealSize) { if (!Get32(m->bx)) { Store64(p + 0, 0); Store64(p + 8, kRealSize); Store32(p + 16, 1); memcpy(m->system->real + addr, p, sizeof(p)); SetWriteAddr(m, addr, sizeof(p)); Put32(m->cx, sizeof(p)); Put32(m->bx, 1); } else { Put32(m->bx, 0); Put32(m->cx, 0); } Put32(m->ax, 0x534D4150); SetCarry(false); } else { SetCarry(true); } } static void OnInt15h(void) { int timeout; if (Get32(m->ax) == 0xE820) { OnE820(); } else if (m->ah == 0x53) { OnApmService(); } else if (m->ah == 0x86) { // microsecond delay timeout = (((Get16(m->cx) << 16) | Get16(m->dx)) + 999) / 1000; poll(0, 0, timeout); } else { SetCarry(true); } } static void OnEquipmentListService(void) { Put16(m->ax, BdaEquip); } static void OnBaseMemSizeService(void) { Put16(m->ax, BdaMemsz); } static void OnPrinterService(void) { m->ah = 0xb0; // "no printer": not busy, out of paper, selected } static void OnTimeServiceGetSystemTime(void) { u64 DAY_SECS = 24UL * 60 * 60; struct timespec now = GetTime(); u64 currday, daytime; u8 midnights = 0; unassert(now.tv_sec >= DAY_SECS); currday = (u64)now.tv_sec / DAY_SECS; // calculate the number of midnights elapsed since the last call here // this will also reset the midnight count if (prevday != 0) { if (currday > prevday) midnights = currday - prevday; } prevday = currday; // calculate nanoseconds from day start daytime = (u64)now.tv_sec - currday * DAY_SECS; daytime = daytime * 1000000000L + now.tv_nsec; // calculate BIOS system timer ticks from day start daytime = daytime * (0x1800B0L / 80) / (DAY_SECS * 1000000000L / 80); Put16(m->cx, daytime >> 16); Put16(m->dx, daytime); m->al = midnights; } static u8 ToBcdByte(u8 binary) { static const u8 bcd[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99}; unassert(binary <= 99); return bcd[binary]; } static void OnTimeServiceGetRtcTime(void) { struct timespec now = GetTime(); struct tm tm; unassert(gmtime_r(&now.tv_sec, &tm)); m->ch = ToBcdByte(tm.tm_hour); m->cl = ToBcdByte(tm.tm_min); m->dh = ToBcdByte(tm.tm_sec); m->dl = tm.tm_isdst; SetCarry(false); } static void OnTimeServiceGetRtcDate(void) { struct timespec now = GetTime(); struct tm tm; unassert(gmtime_r(&now.tv_sec, &tm)); m->ch = ToBcdByte((tm.tm_year / 100U + 19) % 100U); m->cl = ToBcdByte(tm.tm_year % 100U); m->dh = ToBcdByte(tm.tm_mon + 1U); m->dl = ToBcdByte(tm.tm_mday); SetCarry(false); } static void OnTimeService(void) { switch (m->ah) { case 0x00: OnTimeServiceGetSystemTime(); break; case 0x02: OnTimeServiceGetRtcTime(); break; case 0x04: OnTimeServiceGetRtcDate(); break; default: SetCarry(true); } } bool OnCallBios(int interrupt) { switch (interrupt) { case 0x10: OnVidyaService(); return true; case 0x13: OnDiskService(); return true; case 0x14: OnSerialService(); return true; case 0x15: OnInt15h(); return true; case 0x16: OnKeyboardService(); return true; case 0x11: OnEquipmentListService(); return true; case 0x12: OnBaseMemSizeService(); return true; case 0x17: OnPrinterService(); return true; case 0x19: DetermineChs(); BootProgram(m, &m->system->elf, diskisfloppy ? 0x00 : 0x80); VidyaServiceSetMode(vidya); return true; case 0x1A: OnTimeService(); Redraw(false); return true; } return false; } ================================================ FILE: blink/biosrom.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ This is free and unencumbered software released into the public domain. │ │ │ │ Anyone is free to copy, modify, publish, use, compile, sell, or │ │ distribute this software, either in source code form or as a compiled │ │ binary, for any purpose, commercial or non-commercial, and by any │ │ means. │ │ │ │ In jurisdictions that recognize copyright laws, the author or authors │ │ of this software dedicate any and all copyright interest in the │ │ software to the public domain. We make this dedication for the benefit │ │ of the public at large and to the detriment of our heirs and │ │ successors. We intend this dedication to be an overt act of │ │ relinquishment in perpetuity of all present and future rights to this │ │ software under copyright law. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ │ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ │ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ │ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │ │ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ │ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │ │ OTHER DEALINGS IN THE SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/biosrom.h" #include #include #include #include #include "blink/bda.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/overlays.h" #include "blink/util.h" #include "blink/vfs.h" #define kBiosArrayBase ROUNDDOWN(kBiosEntry - (0x1D * 4 + 12 + 8 * 4), 0x10) #define kBiosDefInt0x00 kBiosArrayBase #define kBiosDefInt0x01 (kBiosDefInt0x00 + 4) #define kBiosDefInt0x02 (kBiosDefInt0x01 + 4) #define kBiosDefInt0x03 (kBiosDefInt0x02 + 4) #define kBiosDefInt0x04 (kBiosDefInt0x03 + 4) #define kBiosDefInt0x05 (kBiosDefInt0x04 + 4) #define kBiosDefInt0x06 (kBiosDefInt0x05 + 4) #define kBiosDefInt0x07 (kBiosDefInt0x06 + 4) #define kBiosDefInt0x08 (kBiosDefInt0x07 + 4) #define kBiosDefInt0x09 (kBiosDefInt0x08 + 4) #define kBiosDefInt0x0A (kBiosDefInt0x09 + 4) #define kBiosDefInt0x0B (kBiosDefInt0x0A + 4) #define kBiosDefInt0x0C (kBiosDefInt0x0B + 4) #define kBiosDefInt0x0D (kBiosDefInt0x0C + 4) #define kBiosDefInt0x0E (kBiosDefInt0x0D + 4) #define kBiosDefInt0x0F (kBiosDefInt0x0E + 4) #define kBiosDefInt0x10 (kBiosDefInt0x0F + 4) #define kBiosDefInt0x11 (kBiosDefInt0x10 + 4) #define kBiosDefInt0x12 (kBiosDefInt0x11 + 4) #define kBiosDefInt0x13 (kBiosDefInt0x12 + 4) #define kBiosDefInt0x14 (kBiosDefInt0x13 + 4) #define kBiosDefInt0x15 (kBiosDefInt0x14 + 4) #define kBiosDefInt0x16 (kBiosDefInt0x15 + 4) #define kBiosDefInt0x17 (kBiosDefInt0x16 + 4) #define kBiosDefInt0x18 (kBiosDefInt0x17 + 4) #define kBiosDefInt0x19 (kBiosDefInt0x18 + 4) #define kBiosDefInt0x1A (kBiosDefInt0x19 + 4) #define kBiosDefInt0x1B (kBiosDefInt0x1A + 4) #define kBiosDefInt0x1C (kBiosDefInt0x1B + 4) #define kBiosDefInt0x1E (kBiosDefInt0x1C + 4) #define kBiosDefInt0x70 (kBiosDefInt0x1E + 12) #define kBiosDefInt0x71 (kBiosDefInt0x70 + 4) #define kBiosDefInt0x72 (kBiosDefInt0x71 + 4) #define kBiosDefInt0x73 (kBiosDefInt0x72 + 4) #define kBiosDefInt0x74 (kBiosDefInt0x73 + 4) #define kBiosDefInt0x75 (kBiosDefInt0x74 + 4) #define kBiosDefInt0x76 (kBiosDefInt0x75 + 4) #define kBiosDefInt0x77 (kBiosDefInt0x76 + 4) #define BIOS_BYTES_AT(addr, ...) [((addr)) - kBiosArrayBase] = __VA_ARGS__ static const u8 kDefBios[] = { BIOS_BYTES_AT(kBiosDefInt0x00, 0x0F, 0xFF, 0067), // hvtailcall 0x00 BIOS_BYTES_AT(kBiosDefInt0x01, 0x0F, 0xFF, 0167, 0x01), // hvtailcall 0x01 BIOS_BYTES_AT(kBiosDefInt0x02, 0x0F, 0xFF, 0167, 0x02), // hvtailcall 0x02 BIOS_BYTES_AT(kBiosDefInt0x03, 0x0F, 0xFF, 0167, 0x03), // hvtailcall 0x03 BIOS_BYTES_AT(kBiosDefInt0x04, 0x0F, 0xFF, 0167, 0x04), // hvtailcall 0x04 BIOS_BYTES_AT(kBiosDefInt0x05, 0x0F, 0xFF, 0167, 0x05), // hvtailcall 0x05 BIOS_BYTES_AT(kBiosDefInt0x06, 0x0F, 0xFF, 0167, 0x06), // hvtailcall 0x06 BIOS_BYTES_AT(kBiosDefInt0x07, 0x0F, 0xFF, 0167, 0x07), // hvtailcall 0x07 BIOS_BYTES_AT(kBiosDefInt0x08, 0x0F, 0xFF, 0167, 0x08), // hvtailcall 0x08 BIOS_BYTES_AT(kBiosDefInt0x09, 0x0F, 0xFF, 0167, 0x09), // hvtailcall 0x09 BIOS_BYTES_AT(kBiosDefInt0x0A, 0x0F, 0xFF, 0167, 0x0A), // hvtailcall 0x0A BIOS_BYTES_AT(kBiosDefInt0x0B, 0x0F, 0xFF, 0167, 0x0B), // hvtailcall 0x0B BIOS_BYTES_AT(kBiosDefInt0x0C, 0x0F, 0xFF, 0167, 0x0C), // hvtailcall 0x0C BIOS_BYTES_AT(kBiosDefInt0x0D, 0x0F, 0xFF, 0167, 0x0D), // hvtailcall 0x0D BIOS_BYTES_AT(kBiosDefInt0x0E, 0x0F, 0xFF, 0167, 0x0E), // hvtailcall 0x0E BIOS_BYTES_AT(kBiosDefInt0x0F, 0x0F, 0xFF, 0167, 0x0F), // hvtailcall 0x0F BIOS_BYTES_AT(kBiosDefInt0x10, 0x0F, 0xFF, 0167, 0x10), // hvtailcall 0x10 BIOS_BYTES_AT(kBiosDefInt0x11, 0x0F, 0xFF, 0167, 0x11), // hvtailcall 0x11 BIOS_BYTES_AT(kBiosDefInt0x12, 0x0F, 0xFF, 0167, 0x12), // hvtailcall 0x12 BIOS_BYTES_AT(kBiosDefInt0x13, 0x0F, 0xFF, 0167, 0x13), // hvtailcall 0x13 BIOS_BYTES_AT(kBiosDefInt0x14, 0x0F, 0xFF, 0167, 0x14), // hvtailcall 0x14 BIOS_BYTES_AT(kBiosDefInt0x15, 0x0F, 0xFF, 0167, 0x15), // hvtailcall 0x15 BIOS_BYTES_AT(kBiosDefInt0x16, 0x0F, 0xFF, 0167, 0x16), // hvtailcall 0x16 BIOS_BYTES_AT(kBiosDefInt0x17, 0x0F, 0xFF, 0167, 0x17), // hvtailcall 0x17 BIOS_BYTES_AT(kBiosDefInt0x18, 0x0F, 0xFF, 0167, 0x18), // hvtailcall 0x18 BIOS_BYTES_AT(kBiosDefInt0x19, 0x0F, 0xFF, 0167, 0x19), // hvtailcall 0x19 BIOS_BYTES_AT(kBiosDefInt0x1A, 0x0F, 0xFF, 0167, 0x1A), // hvtailcall 0x1A BIOS_BYTES_AT(kBiosDefInt0x1B, 0x0F, 0xFF, 0167, 0x1B), // hvtailcall 0x1B BIOS_BYTES_AT(kBiosDefInt0x1C, 0x0F, 0xFF, 0167, 0x1C), // hvtailcall 0x1C // default diskette parameter table per Jun 1985 PC AT BIOS; see p. 5-192 @ // https://archive.org/details/IBMPCATIBM5170TechnicalReference6280070SEP85 BIOS_BYTES_AT(kBiosDefInt0x1E, // 0xDF, 2, 37, 2, 15, // 0x1B, 0xFF, 0x54, 0xF6, 15, 8), // BIOS_BYTES_AT(kBiosDefInt0x70, 0x0F, 0xFF, 0167, 0x70), // hvtailcall 0x70 BIOS_BYTES_AT(kBiosDefInt0x71, 0x0F, 0xFF, 0167, 0x71), // hvtailcall 0x71 BIOS_BYTES_AT(kBiosDefInt0x72, 0x0F, 0xFF, 0167, 0x72), // hvtailcall 0x72 BIOS_BYTES_AT(kBiosDefInt0x73, 0x0F, 0xFF, 0167, 0x73), // hvtailcall 0x73 BIOS_BYTES_AT(kBiosDefInt0x74, 0x0F, 0xFF, 0167, 0x74), // hvtailcall 0x74 BIOS_BYTES_AT(kBiosDefInt0x75, 0x0F, 0xFF, 0167, 0x75), // hvtailcall 0x75 BIOS_BYTES_AT(kBiosDefInt0x76, 0x0F, 0xFF, 0167, 0x76), // hvtailcall 0x76 BIOS_BYTES_AT(kBiosDefInt0x77, 0x0F, 0xFF, 0167, 0x77), // hvtailcall 0x77 BIOS_BYTES_AT(kBiosEntry, // 0x0F, 0xFF, 0177, 0x19, // hvcall 0x19 0xEB, 0xFA), // jmp .-4 BIOS_BYTES_AT(kBiosEnd - 1, 0x00)}; void LoadBios(struct Machine *m, const char *biosprog) { off_t size; if (biosprog) { off_t kBiosMinSize = kBiosEnd - kBiosEntry, kBiosMaxSize = kBiosEnd - kBiosOptBase; int fd; struct stat st; char tmp[64]; if ((fd = VfsOpen(AT_FDCWD, biosprog, O_RDONLY, 0)) == -1 || VfsFstat(fd, &st) == -1) { WriteErrorString(biosprog); WriteErrorString(": failed to load alternate BIOS (errno "); FormatInt64(tmp, errno); WriteErrorString(tmp); WriteErrorString(")\n"); exit(EXIT_FAILURE_EXEC_FAILED); } else if ((size = st.st_size) < kBiosMinSize) { WriteErrorString(biosprog); WriteErrorString(": failed to load alternate BIOS (file too small)\n"); exit(EXIT_FAILURE_EXEC_FAILED); } else if (size > kBiosMaxSize) { WriteErrorString(biosprog); WriteErrorString(": failed to load alternate BIOS (file too large)\n"); exit(EXIT_FAILURE_EXEC_FAILED); } else if (VfsRead(fd, m->system->real + kBiosEnd - size, size) != size) { WriteErrorString(biosprog); WriteErrorString(": failed to load alternate BIOS (errno "); FormatInt64(tmp, errno); WriteErrorString(tmp); WriteErrorString(")\n"); exit(EXIT_FAILURE_EXEC_FAILED); } } else { // if no BIOS image file name is given, then load a default BIOS image size = sizeof(kDefBios); memcpy(m->system->real + kBiosEnd - size, kDefBios, size); } #ifndef DISABLE_ROM // try to protect the BIOS ROM area // BeginStore() & EndStore() will avoid scribbling in this area of // memory: so writes to the guest ROM area are effectively ignored size_t protstart, protend; protstart = ROUNDUP(kBiosOptBase, FLAG_pagesize); protend = ROUNDDOWN(kBiosEnd, FLAG_pagesize); if (protstart < protend) { Mprotect(m->system->real + protstart, protend - protstart, PROT_READ, "bios"); } #endif // load %cs:%rip m->cs.sel = kBiosSeg; m->cs.base = kBiosBase; m->ip = kBiosEntry - kBiosBase; } void SetDefaultBiosIntVectors(struct Machine *m) { struct System *s = m->system; s->idt_base = 0; s->idt_limit = 0x100 * 4 - 1; memset(s->real + 0x1D * 4, 0, (0x100 - 0x1D) * 4); Put32(s->real + 0x00 * 4, kBiosSeg << 16 | (kBiosDefInt0x00 - kBiosBase)); Put32(s->real + 0x01 * 4, kBiosSeg << 16 | (kBiosDefInt0x01 - kBiosBase)); Put32(s->real + 0x02 * 4, kBiosSeg << 16 | (kBiosDefInt0x02 - kBiosBase)); Put32(s->real + 0x03 * 4, kBiosSeg << 16 | (kBiosDefInt0x03 - kBiosBase)); Put32(s->real + 0x04 * 4, kBiosSeg << 16 | (kBiosDefInt0x04 - kBiosBase)); Put32(s->real + 0x05 * 4, kBiosSeg << 16 | (kBiosDefInt0x05 - kBiosBase)); Put32(s->real + 0x06 * 4, kBiosSeg << 16 | (kBiosDefInt0x06 - kBiosBase)); Put32(s->real + 0x07 * 4, kBiosSeg << 16 | (kBiosDefInt0x07 - kBiosBase)); Put32(s->real + 0x08 * 4, kBiosSeg << 16 | (kBiosDefInt0x08 - kBiosBase)); Put32(s->real + 0x09 * 4, kBiosSeg << 16 | (kBiosDefInt0x09 - kBiosBase)); Put32(s->real + 0x0A * 4, kBiosSeg << 16 | (kBiosDefInt0x0A - kBiosBase)); Put32(s->real + 0x0B * 4, kBiosSeg << 16 | (kBiosDefInt0x0B - kBiosBase)); Put32(s->real + 0x0C * 4, kBiosSeg << 16 | (kBiosDefInt0x0C - kBiosBase)); Put32(s->real + 0x0D * 4, kBiosSeg << 16 | (kBiosDefInt0x0D - kBiosBase)); Put32(s->real + 0x0E * 4, kBiosSeg << 16 | (kBiosDefInt0x0E - kBiosBase)); Put32(s->real + 0x0F * 4, kBiosSeg << 16 | (kBiosDefInt0x0F - kBiosBase)); Put32(s->real + 0x10 * 4, kBiosSeg << 16 | (kBiosDefInt0x10 - kBiosBase)); Put32(s->real + 0x11 * 4, kBiosSeg << 16 | (kBiosDefInt0x11 - kBiosBase)); Put32(s->real + 0x12 * 4, kBiosSeg << 16 | (kBiosDefInt0x12 - kBiosBase)); Put32(s->real + 0x13 * 4, kBiosSeg << 16 | (kBiosDefInt0x13 - kBiosBase)); Put32(s->real + 0x14 * 4, kBiosSeg << 16 | (kBiosDefInt0x14 - kBiosBase)); Put32(s->real + 0x15 * 4, kBiosSeg << 16 | (kBiosDefInt0x15 - kBiosBase)); Put32(s->real + 0x16 * 4, kBiosSeg << 16 | (kBiosDefInt0x16 - kBiosBase)); Put32(s->real + 0x17 * 4, kBiosSeg << 16 | (kBiosDefInt0x17 - kBiosBase)); Put32(s->real + 0x18 * 4, kBiosSeg << 16 | (kBiosDefInt0x18 - kBiosBase)); Put32(s->real + 0x19 * 4, kBiosSeg << 16 | (kBiosDefInt0x19 - kBiosBase)); Put32(s->real + 0x1A * 4, kBiosSeg << 16 | (kBiosDefInt0x1A - kBiosBase)); Put32(s->real + 0x1B * 4, kBiosSeg << 16 | (kBiosDefInt0x1B - kBiosBase)); Put32(s->real + 0x1C * 4, kBiosSeg << 16 | (kBiosDefInt0x1C - kBiosBase)); Put32(s->real + 0x1E * 4, kBiosSeg << 16 | (kBiosDefInt0x1E - kBiosBase)); Put32(s->real + 0x70 * 4, kBiosSeg << 16 | (kBiosDefInt0x70 - kBiosBase)); Put32(s->real + 0x71 * 4, kBiosSeg << 16 | (kBiosDefInt0x71 - kBiosBase)); Put32(s->real + 0x72 * 4, kBiosSeg << 16 | (kBiosDefInt0x72 - kBiosBase)); Put32(s->real + 0x73 * 4, kBiosSeg << 16 | (kBiosDefInt0x73 - kBiosBase)); Put32(s->real + 0x74 * 4, kBiosSeg << 16 | (kBiosDefInt0x74 - kBiosBase)); Put32(s->real + 0x75 * 4, kBiosSeg << 16 | (kBiosDefInt0x75 - kBiosBase)); Put32(s->real + 0x76 * 4, kBiosSeg << 16 | (kBiosDefInt0x76 - kBiosBase)); Put32(s->real + 0x77 * 4, kBiosSeg << 16 | (kBiosDefInt0x77 - kBiosBase)); } void SetDefaultBiosDataArea(struct Machine *m) { memset(m->system->real + 0x400, 0, 0x100); SetBdaCom1(0x3F8); SetBdaEbda(0xB0000 >> 4); SetBdaEquip(1 << 0 | // floppy drive 1 << 1 | // math coprocessor 3 << 4 | // initial video mode 0 << 6 | // no. of floppy drives - 1 1 << 9); // no. of serial devices SetBdaMemsz(0xB0000 / 1024); SetBdaCols(80); SetBdaLines(25); } u32 GetDefaultBiosDisketteParamTable(void) { return kBiosSeg << 16 | (kBiosDefInt0x1E - kBiosBase); } ================================================ FILE: blink/biosrom.h ================================================ #ifndef BLINK_BIOSROM_H_ #define BLINK_BIOSROM_H_ #define kBiosBase 0x000F0000 // nominal base address of BIOS image #define kBiosSeg (kBiosBase >> 4) // nominal base segment of BIOS image #define kBiosEnd 0x00100000 // address immediately after BIOS image #define kBiosEntry 0x000FFFF0 // entry point #define kBiosOptBase 0x000C0000 // lowest possible base address of // BIOS image, including option ROMs #if !(__ASSEMBLER__ + __LINKER__ + 0) #include "blink/builtin.h" #include "blink/endian.h" #include "blink/likely.h" #include "blink/machine.h" MICRO_OP_SAFE bool IsRomAddress(struct Machine *m, u8 *r) { #ifndef DISABLE_ROM if (m->metal) { struct System *s = m->system; u8 *real = s->real; #if CAN_ABUSE_POINTERS ptrdiff_t d = r - real; // gcc optimizes this conjunction into subtraction followed by comparison // FIXME: find better way to figure out if we can abuse ptrdiff_t like so if (UNLIKELY(kBiosOptBase <= d && d < kBiosEnd)) #else if (UNLIKELY(&real[kBiosOptBase] <= r && r < &real[kBiosEnd])) #endif { if (s->onromwriteattempt) s->onromwriteattempt(m, r); return true; } } #endif return false; } void LoadBios(struct Machine *, const char *); void SetDefaultBiosIntVectors(struct Machine *); void SetDefaultBiosDataArea(struct Machine *); u32 GetDefaultBiosDisketteParamTable(void); #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* BLINK_BIOSROM_H_ */ ================================================ FILE: blink/bit.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bus.h" #include "blink/flags.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/rde.h" static u64 Bts(u64 x, u64 y) { return x | y; } static u64 Btr(u64 x, u64 y) { return x & ~y; } static u64 Btc(u64 x, u64 y) { return (x & ~y) | (~x & y); } void OpBit(P) { u8 *p; int op; i64 bitdisp; unsigned bit; u64 v, x, y, z; u8 w, W[2][2] = {{2, 3}, {1, 3}}; w = W[Osz(rde)][Rexw(rde)]; if (Opcode(rde) == 0xBA) { op = ModrmReg(rde); bit = uimm0 & ((8 << w) - 1); bitdisp = 0; } else { op = (Opcode(rde) & 070) >> 3; bitdisp = ReadRegisterSigned(rde, RegRexrReg(m, rde)); bit = bitdisp & ((8 << w) - 1); bitdisp &= -(8 << w); bitdisp >>= 3; } if (IsModrmRegister(rde)) { p = RegRexbRm(m, rde); } else { v = MaskAddress(Eamode(rde), ComputeAddress(A) + bitdisp); p = ReserveAddress(m, v, 1 << w, op != 4); } if (Lock(rde)) LockBus(p); y = 1; y <<= bit; if (Lock(rde)) { x = ReadMemoryUnlocked(rde, p); } else { x = ReadMemory(rde, p); } m->flags = SetFlag(m->flags, FLAGS_CF, !!(y & x)); switch (op) { case 4: return; case 5: z = Bts(x, y); break; case 6: z = Btr(x, y); break; case 7: z = Btc(x, y); break; default: OpUdImpl(m); } WriteRegisterOrMemory(rde, p, z); if (Lock(rde)) UnlockBus(p); } ================================================ FILE: blink/bitscan.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bitscan.h" static const char kDebruijn[64] = { 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, 54, 58, 35, 52, 50, 42, 21, 44, 38, 32, 29, 23, 17, 11, 4, 62, 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43, 31, 22, 10, 45, 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63, }; int(bsr)(u64 x) { x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32; return kDebruijn[(x * 0x03f79d71b4cb0a89) >> 58]; } int(bsf)(u64 x) { u32 l, r; x &= -x; l = x | x >> 32; r = !!(x >> 32), r <<= 1; r += !!((l & 0xffff0000)), r <<= 1; r += !!((l & 0xff00ff00)), r <<= 1; r += !!((l & 0xf0f0f0f0)), r <<= 1; r += !!((l & 0xcccccccc)), r <<= 1; r += !!((l & 0xaaaaaaaa)); return r; } ================================================ FILE: blink/bitscan.h ================================================ #ifndef BLINK_BITSCAN_H_ #define BLINK_BITSCAN_H_ #include "blink/builtin.h" #include "blink/types.h" #ifndef __GNUC__ int bsr(u64); int bsf(u64); int popcount(u64); #else #define bsf(x) __builtin_ctzll(x) #define bsr(x) (__builtin_clzll(x) ^ 63) #define popcount(x) __builtin_popcountll(x) #endif /* GNUC */ #endif /* BLINK_BITSCAN_H_ */ ================================================ FILE: blink/blink-shell.html ================================================ blink online preview
Downloading...
Resize canvas Lock/hide mouse pointer    
{{{ SCRIPT }}} ================================================ FILE: blink/blink.1 ================================================ .\" Copyright 2023 Justine Alexandra Roberts Tunney .\" .\" Permission to use, copy, modify, and/or distribute this software for .\" any purpose with or without fee is hereby granted, provided that the .\" above copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL .\" WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE .\" AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER .\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" .Dd March 6, 2023 .Dt BLINK 1 .Os .Sh NAME .Nm blink .Nd headless blinkenlights x86-64-linux virtual machine .Sh SYNOPSIS .Nm .Op Fl hvjemZs .Op Fl L Ar logfile .Op Fl C Ar chroot .Ar program .Op Ar argv1... .Nm .Op Fl hvjemZs .Op Fl L Ar logfile .Op Fl C Ar chroot .Fl 0 .Ar program .Op Ar argv0... .Sh DESCRIPTION .Nm is a JITing virtual machine that uses x86_64 as its byte code language and implements the Linux Kernel ABI. .Nm may be used to run prebuilt binaries intended for x86_64 Linux on other POSIX platforms. .Sh ARGUMENTS .Pp The .Ar program argument is a .Ev PATH searched command, which may be: .Pp .Bl -dash -compact .It An x86_64-linux ELF executable (either static or dynamic) .It An Actually Portable Executable (either MZqFpD or jartsr magic) .It A flat executable (if .Ar program ends with .bin, .img, or .raw) .It A shell script whose #!interpreter meets the above criteria .El .Pp The .Fl 0 flag allows .Li argv[0] to be specified on the command line. Under normal circumstances, .Bd -literal -offset indent blink cmd arg1 .Ed .Pp is equivalent to .Bd -literal -offset indent execve("cmd", {"cmd", "arg1"}) .Ed .Pp since that's how most programs are launched. However if you need the full power of execve() process spawning, you can say .Bd -literal -offset indent blink -0 cmd arg0 arg1 .Ed .Pp which is equivalent to .Bd -literal -offset indent execve("cmd", {"arg0", "arg1"}) .Ed .Pp .Sh OPTIONS The following options are available: .Bl -tag -width indent .It Fl h Prints condensed help. .It Fl v Shows .Nm version and build configuration details. .It Fl e Log to standard error (fd 2) in addition to the log file. If logging to .Em only standard error is desired, then .Li -eL/dev/null may be passed as flags. .It Fl s Enables system call logging (repeatable). .Pp This will emit to the log file the names of system calls each time a SYSCALL instruction in executed, along with its arguments and result. System calls are logged once they've completed, so that the result can be shown. .Pp System calls are also sometimes logged upon entry too, in which case .Li syscall(arg) -> ... will be logged to show that the system call has not yet completed. Whether or not this happens depends on how many times the .Fl s flag is supplied. .Pp .Bl -dash -compact .It Passing .Fl s (once) will only log the entries of system calls that are defined as having read + write parameters (e.g. poll, select) .It Passing .Fl ss (twice) will also log the entries of cancellation points that are likely to block (e.g. read, accept, wait, pause). .It Passing .Fl sss (thrice) will log the entries of system calls that POSIX defines as cancellation points but are unlikely to block (e.g. write, close, open) which we try to avoid doing in order to reduce log noise. .It Passing .Fl ssss (4x) will log the entry of every single system call, even harmless ones that have no business being emitted to the log twice (e.g. sigaction). This should only be useful for the Blink dev team when the rare need arises to troubleshoot a system call that's crashing. .El .Pp System call logging isn't available in .Li MODE=rel and .Li MODE=tiny builds, in which case this flag is ignored. .It Fl m Enables full memory virtualization. Under normal circumstances, .Nm aims to share the same address space as the guest program. Depending on the program's memory requirements (i.e. if it uses MAP_FIXED) and the constraints imposed by the host platform, this so-called linear memory optimization may lead to an mmap() crisis that causes Blink to not work properly. Using this option will cause .Nm to virtualize the x86_64 address space precicely and reliably, however the use of this flag carries the tradeoff of causing .Nm to go at least 2x slower. .It Fl j Disables Just-In-Time (JIT) compilation. Using this option will cause .Nm to go ~10x or possibly even ~100x slower. .It Fl L Ar path Specifies the log path. The default log path is .Ar blink.log in the current directory at startup. This log file won't be created until something is actually logged. If logging to a file isn't desired, then -L /dev/null may be used. See also the .Fl e flag for logging to standard error. .It Fl C Ar path Launch .Ar program in a chroot'd environment. This flag is both equivalent to and overrides the .Ev BLINK_OVERLAYS environment variable. .It Fl Z Prints internal statistics to standard error on exit. Each line will display a monitoring metric. Most metrics will either be integer counters or floating point running averages. Most but not all integer counters are monotonic. In the interest of not negatively impacting Blink's performance, statistics are computed on a best effort basis which currently isn't guaranteed to be atomic in a multi-threaded environment. Statistics aren't available in MODE=rel and MODE=tiny builds, in which case this flag is ignored. .El .Sh ENVIRONMENT The following environment variables are recognized: .Bl -tag -width indent .It Ev BLINK_LOG_FILENAME may be specified to supply a log path to be used in cases where the .Fl L Ar path flag isn't specified. This value should be an absolute path. If logging to standard error is desired, use the .Fl e flag. .It Ev BLINK_OVERLAYS specifies one or more directories to use as the root filesystem. Similar to .Ev PATH this is a colon delimited list of pathnames. If relative paths are specified, they'll be resolved to an absolute path at startup time. Overlays only apply to IO system calls that specify an absolute path. The empty string overlay means use the normal / root filesystem. The default value is .Li :o which means if the absolute path .Li /$f is opened, then first check if .Li /$f exists, and if it doesn't, then check if .Li o/$f exists, in which case open that instead. Blink uses this convention to open shared object tests. It favors the system version if it exists, but also downloads .Li ld-musl-x86_64.so.1 to .Li o/lib/ld-musl-x86_64.so.1 so the dynamic linker can transparently find it on platforms like Apple, that don't let users put files in the root folder. On the other hand, it's possible to say .Li BLINK_OVERLAYS=o: so that .Li o/... takes precedence over .Li /... (noting again that empty string means root). If a single overlay is specified that isn't empty string, then it'll effectively act as a restricted chroot environment. .El .Sh QUIRKS Here's the current list of Blink's known quirks and tradeoffs. .Ss "Flags" Flag dependencies may not carry across function call boundaries under long mode. This is because when Blink's JIT is speculating whether or not it's necessary for an arithmetic instruction to compute flags, it considers .Li RET and .Li CALL terminal ops that break the chain. As such 64-bit code shouldn't do things we did in the DOS days, such as using carry flag as a return value to indicate error. This should work fine when .Li STC is used to set the carry flag, but if the code computes it cleverly using instructions like .Li SUB then EFLAGS might not change. .Ss "Faults" Blink may not report the precise program counter where a fault occurred in .Li ucontext_t::uc_mcontext::rip when signalling a segmentation fault. This is currently only possible when .Li PUSH or .Li POP access bad memory. That's because Blink's JIT tries to avoid updating .Li Machine::ip on ops it considers "pure" such as those that only access registers, which for reasons of performance is defined to include pushing and popping. .Ss "Threads" Blink doesn't have a working implementation of .Li set_robust_list() yet, which means robust mutexes might not get unlocked if a process crashes. .Ss "Coherency" POSIX.1 provides almost no guarantees of coherency, synchronization, and durability when it comes to .Li MAP_SHARED mappings and recommends that msync() be explicitly used to synchronize memory with file contents. The Linux Kernel implements shared memory so well, that this is rarely necessary. However some platforms like OpenBSD lack write coherency. This means if you change a shared writable memory map and then call pread() on the associated file region, you might get stale data. Blink isn't able to polyfill incoherent platforms to be as coherent as Linux, therefore apps that run in Blink should assume the POSIX rules apply. .Ss "Signal Handling" Blink uses .Li SIGSYS to deliver signals internally. This signal is precious to Blink. It's currently not possible for guest applications to capture it from external processes. .Ss "Memory Protection" Blink offers guest programs a 48-bit virtual address space with a 4096-byte page size. When programs are run on (1) host systems that have a larger page (e.g. Apple M1, Cygwin), and (2) the linear memory optimization is enabled (i.e. you're *not* using .Li blink -m ) then Blink may need to relax memory protections in cases where the memory intervals defined by the guest aren't aligned to the host system page size. Is is recommended, when calling functions like mmap() and mprotect(), that both .Li addr and .Li addr + size be aliged to the true page size, which Blink reports to the guest in .Li getauxval(AT_PAGESZ). This value should be obtainable via the portable API .Li sysconf(_SC_PAGESIZE) assuming the C library implements it correctly. Please note that when Blink is running in its fully virtualized mode (i.e. .Li blink -m ) this concern does not apply. That's because Blink will allocate a full system page for every 4096 byte page that gets mapped from a file. .Sh EXIT STATUS The .Nm command passes along the exit code of the .Ar program which by convention is 0 on success or >0 on failure. In the event that .Nm fails to launch .Ar program the status 127 shall be returned. .Sh SEE ALSO .Xr blinkenlights 1 .Sh STANDARDS The .Nm command implements a superset of the .St -p1003.1-2008 specification, intended to emulate the behaviors of the Linux Kernel. .Sh AUTHORS .An "Justine Alexandra Roberts Tunney" Aq jtunney@gmail.com ================================================ FILE: blink/blink.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/case.h" #include "blink/debug.h" #include "blink/dll.h" #include "blink/endian.h" #include "blink/flag.h" #include "blink/jit.h" #include "blink/loader.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/overlays.h" #include "blink/pml4t.h" #include "blink/signal.h" #include "blink/sigwinch.h" #include "blink/stats.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/tunables.h" #include "blink/util.h" #include "blink/vfs.h" #include "blink/web.h" #include "blink/x86.h" #include "blink/xlat.h" #ifndef BUILD_TIMESTAMP #define BUILD_TIMESTAMP __TIMESTAMP__ #endif #ifndef BUILD_MODE #define BUILD_MODE "BUILD_MODE_UNKNOWN" #warning "-DBUILD_MODE=... should be passed to blink/blink.c" #endif #ifndef BUILD_TOOLCHAIN #define BUILD_TOOLCHAIN "BUILD_TOOLCHAIN_UNKNOWN" #warning "-DBUILD_TOOLCHAIN=... should be passed to blink/blink.c" #endif #ifndef BLINK_VERSION #define BLINK_VERSION "BLINK_VERSION_UNKNOWN" #warning "-DBLINK_VERSION=... should be passed to blink/blink.c" #endif #ifndef BLINK_COMMITS #define BLINK_COMMITS "BLINK_COMMITS_UNKNOWN" #warning "-DBLINK_COMMITS=... should be passed to blink/blink.c" #endif #ifndef BLINK_GITSHA #define BLINK_GITSHA "BLINK_GITSHA_UNKNOWN" #warning "-DBLINK_GITSHA=... should be passed to blink/blink.c" #endif #ifndef CONFIG_ARGUMENTS #define CONFIG_ARGUMENTS "CONFIG_ARGUMENTS_UNKNOWN" #warning "-DCONFIG_ARGUMENTS=... should be passed to blink/blink.c" #endif #define VERSION \ "Blink Virtual Machine " BLINK_VERSION " (" BUILD_TIMESTAMP ")\n\ Copyright (c) 2023 Justine Alexandra Roberts Tunney\n\ Blink comes with absolutely NO WARRANTY of any kind.\n\ You may redistribute copies of Blink under the ISC License.\n\ For more information, see the file named LICENSE.\n\ Toolchain: " BUILD_TOOLCHAIN "\n\ Revision: #" BLINK_COMMITS " " BLINK_GITSHA "\n\ Config: ./configure MODE=" BUILD_MODE " " CONFIG_ARGUMENTS "\n" #define OPTS "hvjemZs0L:C:" _Alignas(1) static const char USAGE[] = " [-" OPTS "] PROG [ARGS...]\n" "Options:\n" " -h help\n" #ifndef DISABLE_JIT " -j disable jit\n" #endif " -v show version\n" #ifndef NDEBUG " -e also log to stderr\n" #endif " -0 to specify argv[0]\n" " -m enable memory safety\n" #if !defined(DISABLE_STRACE) && !defined(TINY) " -s enable system call logging\n" #endif #ifndef NDEBUG " -Z print internal statistics on exit\n" " -L PATH log filename (default is blink.log)\n" #endif #if !defined(DISABLE_OVERLAYS) || !defined(DISABLE_VFS) " -C PATH sets chroot dir or overlay spec [default \":o\"]\n" #endif #if !defined(DISABLE_OVERLAYS) || !defined(NDEBUG) "Environment:\n" #endif #ifndef DISABLE_OVERLAYS " $BLINK_OVERLAYS file system roots [default \":o\"]\n" #endif #ifndef DISABLE_VFS " $BLINK_PREFIX file system root [default \"/\"]\n" #endif #ifndef NDEBUG " $BLINK_LOG_FILENAME log filename (same as -L flag)\n" #endif ; extern char **environ; static bool FLAG_nojit; static char g_pathbuf[PATH_MAX]; static void OnSigSys(int sig) { // do nothing } static void PrintDiagnostics(struct Machine *m) { ERRF("additional information\n" "\t%s\n" "%s\n" "%s", GetBacktrace(m), FormatPml4t(m), GetBlinkBacktrace()); } void TerminateSignal(struct Machine *m, int sig, int code) { int syssig; struct sigaction sa; unassert(!IsSignalIgnoredByDefault(sig)); KillOtherThreads(m->system); #ifdef HAVE_JIT DisableJit(&m->system->jit); // unmapping exec pages is slow #endif if (IsSignalSerious(sig)) { ERRF("terminating due to %s (" "rip=%#" PRIx64 " " "code=%d " "faultaddr=%#" PRIx64 ")", DescribeSignal(sig), m->ip, code, m->faultaddr); PrintDiagnostics(m); } if ((syssig = XlatSignal(sig)) == -1) syssig = SIGKILL; FreeMachine(m); #ifdef HAVE_JIT ShutdownJit(); #endif sa.sa_flags = 0; sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); if (syssig != SIGKILL && syssig != SIGSTOP) { unassert(!sigaction(syssig, &sa, 0)); } unassert(!kill(getpid(), syssig)); Abort(); } static void OnFatalSystemSignal(int sig, siginfo_t *si, void *ptr) { struct Machine *m = g_machine; #ifdef __APPLE__ sig = FixXnuSignal(m, sig, si); #elif defined(__powerpc__) && CAN_64BIT sig = FixPpcSignal(m, sig, si); #endif SIG_LOGF("OnFatalSystemSignal(%s, %p)", DescribeSignal(UnXlatSignal(sig)), si->si_addr); #ifndef DISABLE_JIT if (IsSelfModifyingCodeSegfault(m, si)) return; #endif g_siginfo = *si; unassert(m); unassert(m->canhalt); siglongjmp(m->onhalt, kMachineFatalSystemSignal); } static void ProgramLimit(struct System *s, int hresource, int gresource) { struct rlimit rlim; if (!getrlimit(hresource, &rlim)) { XlatRlimitToLinux(s->rlim + gresource, &rlim); } } static int Exec(char *execfn, char *prog, char **argv, char **envp) { int i; sigset_t oldmask; struct Machine *m, *old; if ((old = g_machine)) KillOtherThreads(old->system); unassert((g_machine = m = NewMachine(NewSystem(XED_MACHINE_MODE_LONG), 0))); #ifdef HAVE_JIT if (FLAG_nojit) DisableJit(&m->system->jit); #endif m->system->exec = Exec; if (!old) { // this is the first time a program is being loaded LoadProgram(m, execfn, prog, argv, envp, NULL); SetupCod(m); for (i = 0; i < 10; ++i) { AddStdFd(&m->system->fds, i); } ProgramLimit(m->system, RLIMIT_NOFILE, RLIMIT_NOFILE_LINUX); } else { #ifdef HAVE_JIT DisableJit(&old->system->jit); // unmapping exec pages is slow #endif unassert(!m->sysdepth); unassert(!m->pagelocks.i); unassert(!FreeVirtual(old->system, -0x800000000000, 0x1000000000000)); for (i = 1; i <= 64; ++i) { if (Read64(old->system->hands[i - 1].handler) == SIG_IGN_LINUX) { Write64(m->system->hands[i - 1].handler, SIG_IGN_LINUX); } } memcpy(m->system->rlim, old->system->rlim, sizeof(old->system->rlim)); LoadProgram(m, execfn, prog, argv, envp, NULL); m->system->fds.list = old->system->fds.list; old->system->fds.list = 0; // releasing the execve() lock must come after unlocking fds memcpy(&oldmask, &old->system->exec_sigmask, sizeof(oldmask)); UNLOCK(&old->system->exec_lock); // freeing the last machine in a system will free its system too FreeMachine(old); // restore the signal mask we had before execve() was called unassert(!pthread_sigmask(SIG_SETMASK, &oldmask, 0)); } Blink(m); } static void Print(int fd, const char *s) { (void)!write(fd, s, strlen(s)); } _Noreturn static void PrintUsage(int argc, char *argv[], int rc, int fd) { Print(fd, "Usage: "); Print(fd, argc > 0 && argv[0] ? argv[0] : "blink"); Print(fd, USAGE); exit(rc); } _Noreturn static void PrintVersion(void) { Print(1, VERSION); exit(EXIT_SUCCESS); } static void GetOpts(int argc, char *argv[]) { int opt; FLAG_nolinear = !CanHaveLinearMemory(); #ifndef DISABLE_OVERLAYS FLAG_overlays = getenv("BLINK_OVERLAYS"); if (!FLAG_overlays) FLAG_overlays = DEFAULT_OVERLAYS; #endif #ifndef DISABLE_VFS FLAG_prefix = getenv("BLINK_PREFIX"); #endif #if LOG_ENABLED FLAG_logpath = getenv("BLINK_LOG_FILENAME"); #endif while ((opt = GetOpt(argc, argv, OPTS)) != -1) { switch (opt) { case '0': FLAG_zero = true; break; case 'j': FLAG_nojit = true; break; case 's': ++FLAG_strace; break; case 'm': FLAG_nolinear = true; break; case 'Z': FLAG_statistics = true; break; case 'e': FLAG_alsologtostderr = true; break; case 'L': FLAG_logpath = optarg_; break; case 'C': #if !defined(DISABLE_OVERLAYS) FLAG_overlays = optarg_; #elif !defined(DISABLE_VFS) FLAG_prefix = optarg_; #else WriteErrorString( "error: overlays and vfs support were both disabled\n"); #endif break; case 'v': PrintVersion(); case 'h': PrintUsage(argc, argv, 0, 1); default: PrintUsage(argc, argv, 48, 2); } } #if LOG_ENABLED LogInit(FLAG_logpath); #endif } static void HandleSigs(void) { struct sigaction sa; signal(SIGPIPE, SIG_IGN); sigfillset(&sa.sa_mask); sa.sa_flags = 0; #ifdef HAVE_THREADS sa.sa_handler = OnSigSys; unassert(!sigaction(SIGSYS, &sa, 0)); #endif sa.sa_sigaction = OnSignal; unassert(!sigaction(SIGINT, &sa, 0)); unassert(!sigaction(SIGQUIT, &sa, 0)); unassert(!sigaction(SIGHUP, &sa, 0)); unassert(!sigaction(SIGTERM, &sa, 0)); unassert(!sigaction(SIGXCPU, &sa, 0)); unassert(!sigaction(SIGXFSZ, &sa, 0)); #if !defined(__SANITIZE_THREAD__) && !defined(__SANITIZE_ADDRESS__) && \ !defined(__FILC__) sa.sa_sigaction = OnFatalSystemSignal; sa.sa_flags = SA_SIGINFO; unassert(!sigaction(SIGBUS, &sa, 0)); unassert(!sigaction(SIGILL, &sa, 0)); unassert(!sigaction(SIGTRAP, &sa, 0)); unassert(!sigaction(SIGSEGV, &sa, 0)); #endif } #if defined(__EMSCRIPTEN__) void exit(int status) { // main is called multiple times - don't perform cleanup _exit(status); } #endif int main(int argc, char *argv[]) { SetupWeb(); GetStartDir(); #ifndef NDEBUG AtAbort(PrintStats); #endif #ifndef DISABLE_STRACE setlocale(LC_ALL, ""); #endif // Ensure utf-8 is printed correctly on windows, this method // has issues(http://stackoverflow.com/a/10884364/4279) but // should work for at least windows 7 and newer. #if defined(_WIN32) && !defined(__CYGWIN__) SetConsoleOutputCP(CP_UTF8); #endif g_blink_path = argc > 0 ? argv[0] : 0; WriteErrorInit(); InitMap(); GetOpts(argc, argv); if (optind_ == argc) { PrintUsage(argc, argv, 48, 2); } #ifndef DISABLE_OVERLAYS if (SetOverlays(FLAG_overlays, true)) { WriteErrorString("bad blink overlays spec; see log for details\n"); exit(EXIT_FAILURE); } #endif #ifndef DISABLE_VFS if (VfsInit(FLAG_prefix)) { WriteErrorString("error: vfs initialization failed\n"); exit(EXIT_FAILURE); } #endif HandleSigs(); InitBus(); if (!Commandv(argv[optind_], g_pathbuf, sizeof(g_pathbuf))) { WriteErrorString(argv[0]); WriteErrorString(": command not found: "); WriteErrorString(argv[optind_]); WriteErrorString("\n"); exit(EXIT_FAILURE_EXEC_FAILED); } argv[optind_] = g_pathbuf; return Exec(g_pathbuf, g_pathbuf, argv + optind_ + FLAG_zero, environ); } ================================================ FILE: blink/blink.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ PKGS += BLINK BLINK_FILES := $(wildcard blink/*) BLINK_SRCS = $(filter %.c,$(BLINK_FILES)) BLINK_HDRS = $(filter %.h,$(BLINK_FILES)) BLINK_SRCS = $(filter %.c,$(BLINK_FILES)) BLINK_OBJS = $(BLINK_SRCS:%.c=o/$(MODE)/%.o) BLINK_NEED_BUILDINFO_SRCS = \ blink/blink.c \ blink/syscall.c \ blink/blinkenlights.c BLINK_NEED_BUILDINFO_OBJS = \ $(BLINK_NEED_BUILDINFO_SRCS:%.c=o/$(MODE)/%.o) \ $(foreach ARCH,$(ARCHITECTURES),$(foreach SRC,$(BLINK_NEED_BUILDINFO_SRCS),$(SRC:%.c=o/$(MODE)/$(ARCH)/%.o))) $(BLINK_NEED_BUILDINFO_OBJS): private CPPFLAGS += $(CONFIG_CPPFLAGS) # micro-ops need to be compiled with the greatest of care o/$(MODE)/blink/uop.o: private CFLAGS += $(UOPFLAGS) # avoid impossible to address errors in ./configure --posix mode ifeq ($(HOST_SYSTEM), Darwin) o/$(MODE)/blink/jit.o: private CPPFLAGS += -D_DARWIN_C_SOURCE o/$(MODE)/blink/syscall.o: private CPPFLAGS += -D_DARWIN_C_SOURCE o/$(MODE)/blink/xlat.o: private CPPFLAGS += -D_DARWIN_C_SOURCE endif # Actually Portable Executable # make m=cosmo o/cosmo/blink/blink.com # needs cosmopolitan/tool/scripts/cosmocc o/cosmo/blink/blink.com: o/$(MODE)/blink/blink objcopy -S -O binary $< $@ o/cosmo/blink/blinkenlights.com: o/$(MODE)/blink/blinkenlights objcopy -S -O binary $< $@ # vectorization makes code smaller o/$(MODE)/blink/sse2.o: private CFLAGS += -O3 o/$(MODE)/x86_64/blink/sse2.o: private CFLAGS += -O3 o/$(MODE)/x86_64-gcc49/blink/sse2.o: private CFLAGS += -O3 o/$(MODE)/aarch64/blink/sse2.o: private CFLAGS += -O3 # these files have big switch statements o/tiny/x86_64/blink/cvt.o: private CFLAGS += -fpie o/tiny/x86_64-gcc49/blink/cvt.o: private CFLAGS += -fpie o/tiny/aarch64/blink/cvt.o: private CFLAGS += -fpie o/tiny/x86_64/blink/xlat.o: private CFLAGS += -fpie o/tiny/x86_64-gcc49/blink/xlat.o: private CFLAGS += -fpie o/tiny/aarch64/blink/xlat.o: private CFLAGS += -fpie o/tiny/x86_64/blink/fpu.o: private CFLAGS += -fpie o/tiny/x86_64-gcc49/blink/fpu.o: private CFLAGS += -fpie o/tiny/aarch64/blink/fpu.o: private CFLAGS += -fpie o/tiny/x86_64/blink/flags.o: private CFLAGS += -fpie o/tiny/x86_64-gcc49/blink/flags.o: private CFLAGS += -fpie o/tiny/aarch64/blink/flags.o: private CFLAGS += -fpie o/tiny/x86_64/blink/x86.o: private CFLAGS += -fno-jump-tables o/tiny/x86_64-gcc49/blink/x86.o: private CFLAGS += -fno-jump-tables o/tiny/aarch64/blink/x86.o: private CFLAGS += -fno-jump-tables o/tiny/x86_64/blink/uop.o: private CFLAGS += -fno-jump-tables o/tiny/x86_64-gcc49/blink/uop.o: private CFLAGS += -fno-jump-tables o/tiny/aarch64/blink/uop.o: private CFLAGS += -fno-jump-tables o/tiny/x86_64/blink/syscall.o: private CFLAGS += -fpie o/tiny/x86_64-gcc49/blink/syscall.o: private CFLAGS += -fpie o/tiny/aarch64/blink/syscall.o: private CFLAGS += -fpie o/$(MODE)/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_OBJS))) o/$(MODE)/i486/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/i486/%.o))) o/$(MODE)/m68k/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/m68k/%.o))) o/$(MODE)/x86_64/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/x86_64/%.o))) o/$(MODE)/x86_64-gcc49/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/x86_64-gcc49/%.o))) o/$(MODE)/arm/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/arm/%.o))) o/$(MODE)/aarch64/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/aarch64/%.o))) o/$(MODE)/riscv64/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/riscv64/%.o))) o/$(MODE)/mips/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/mips/%.o))) o/$(MODE)/mipsel/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/mipsel/%.o))) o/$(MODE)/mips64/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/mips64/%.o))) o/$(MODE)/mips64el/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/mips64el/%.o))) o/$(MODE)/s390x/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/s390x/%.o))) o/$(MODE)/microblaze/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/microblaze/%.o))) o/$(MODE)/powerpc/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/powerpc/%.o))) o/$(MODE)/powerpc64le/blink/blink.a: $(filter-out %/blink.o,$(filter-out %/blinkenlights.o,$(BLINK_SRCS:%.c=o/$(MODE)/powerpc64le/%.o))) o/$(MODE)/blink/blink: o/$(MODE)/blink/blink.o o/$(MODE)/blink/blink.a $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/i486/blink/blink: o/$(MODE)/i486/blink/blink.o o/$(MODE)/i486/blink/blink.a $(VM) o/third_party/gcc/i486/bin/i486-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/m68k/blink/blink: o/$(MODE)/m68k/blink/blink.o o/$(MODE)/m68k/blink/blink.a $(VM) o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/x86_64/blink/blink: o/$(MODE)/x86_64/blink/blink.o o/$(MODE)/x86_64/blink/blink.a $(VM) o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/x86_64-gcc49/blink/blink: o/$(MODE)/x86_64-gcc49/blink/blink.o o/$(MODE)/x86_64-gcc49/blink/blink.a $(VM) o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/arm/blink/blink: o/$(MODE)/arm/blink/blink.o o/$(MODE)/arm/blink/blink.a $(VM) o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/aarch64/blink/blink: o/$(MODE)/aarch64/blink/blink.o o/$(MODE)/aarch64/blink/blink.a $(VM) o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/riscv64/blink/blink: o/$(MODE)/riscv64/blink/blink.o o/$(MODE)/riscv64/blink/blink.a $(VM) o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mips/blink/blink: o/$(MODE)/mips/blink/blink.o o/$(MODE)/mips/blink/blink.a $(VM) o/third_party/gcc/mips/bin/mips-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mipsel/blink/blink: o/$(MODE)/mipsel/blink/blink.o o/$(MODE)/mipsel/blink/blink.a $(VM) o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mips64/blink/blink: o/$(MODE)/mips64/blink/blink.o o/$(MODE)/mips64/blink/blink.a $(VM) o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mips64el/blink/blink: o/$(MODE)/mips64el/blink/blink.o o/$(MODE)/mips64el/blink/blink.a $(VM) o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/s390x/blink/blink: o/$(MODE)/s390x/blink/blink.o o/$(MODE)/s390x/blink/blink.a $(VM) o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/microblaze/blink/blink: o/$(MODE)/microblaze/blink/blink.o o/$(MODE)/microblaze/blink/blink.a $(VM) o/third_party/gcc/microblaze/bin/microblaze-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/powerpc/blink/blink: o/$(MODE)/powerpc/blink/blink.o o/$(MODE)/powerpc/blink/blink.a $(VM) o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/powerpc64le/blink/blink: o/$(MODE)/powerpc64le/blink/blink.o o/$(MODE)/powerpc64le/blink/blink.a $(VM) o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/blink/blinkenlights.html: o/$(MODE)/blink/blinkenlights.o o/$(MODE)/blink/blink.a $(ZLIB) $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/blink/blinkenlights: o/$(MODE)/blink/blinkenlights.o o/$(MODE)/blink/blink.a $(ZLIB) $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/i486/blink/blinkenlights: o/$(MODE)/i486/blink/blinkenlights.o o/$(MODE)/i486/blink/blink.a o/$(MODE)/i486/third_party/libz/zlib.a $(VM) o/third_party/gcc/i486/bin/i486-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/m68k/blink/blinkenlights: o/$(MODE)/m68k/blink/blinkenlights.o o/$(MODE)/m68k/blink/blink.a o/$(MODE)/m68k/third_party/libz/zlib.a $(VM) o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/x86_64/blink/blinkenlights: o/$(MODE)/x86_64/blink/blinkenlights.o o/$(MODE)/x86_64/blink/blink.a o/$(MODE)/x86_64/third_party/libz/zlib.a $(VM) o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/x86_64-gcc49/blink/blinkenlights: o/$(MODE)/x86_64-gcc49/blink/blinkenlights.o o/$(MODE)/x86_64-gcc49/blink/blink.a o/$(MODE)/x86_64-gcc49/third_party/libz/zlib.a $(VM) o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/arm/blink/blinkenlights: o/$(MODE)/arm/blink/blinkenlights.o o/$(MODE)/arm/blink/blink.a o/$(MODE)/arm/third_party/libz/zlib.a $(VM) o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/aarch64/blink/blinkenlights: o/$(MODE)/aarch64/blink/blinkenlights.o o/$(MODE)/aarch64/blink/blink.a o/$(MODE)/aarch64/third_party/libz/zlib.a $(VM) o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/riscv64/blink/blinkenlights: o/$(MODE)/riscv64/blink/blinkenlights.o o/$(MODE)/riscv64/blink/blink.a o/$(MODE)/riscv64/third_party/libz/zlib.a $(VM) o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mips/blink/blinkenlights: o/$(MODE)/mips/blink/blinkenlights.o o/$(MODE)/mips/blink/blink.a o/$(MODE)/mips/third_party/libz/zlib.a $(VM) o/third_party/gcc/mips/bin/mips-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mipsel/blink/blinkenlights: o/$(MODE)/mipsel/blink/blinkenlights.o o/$(MODE)/mipsel/blink/blink.a o/$(MODE)/mipsel/third_party/libz/zlib.a $(VM) o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mips64/blink/blinkenlights: o/$(MODE)/mips64/blink/blinkenlights.o o/$(MODE)/mips64/blink/blink.a o/$(MODE)/mips64/third_party/libz/zlib.a $(VM) o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/mips64el/blink/blinkenlights: o/$(MODE)/mips64el/blink/blinkenlights.o o/$(MODE)/mips64el/blink/blink.a o/$(MODE)/mips64el/third_party/libz/zlib.a $(VM) o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/s390x/blink/blinkenlights: o/$(MODE)/s390x/blink/blinkenlights.o o/$(MODE)/s390x/blink/blink.a o/$(MODE)/s390x/third_party/libz/zlib.a $(VM) o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/microblaze/blink/blinkenlights: o/$(MODE)/microblaze/blink/blinkenlights.o o/$(MODE)/microblaze/blink/blink.a o/$(MODE)/microblaze/third_party/libz/zlib.a $(VM) o/third_party/gcc/microblaze/bin/microblaze-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/powerpc/blink/blinkenlights: o/$(MODE)/powerpc/blink/blinkenlights.o o/$(MODE)/powerpc/blink/blink.a o/$(MODE)/powerpc/third_party/libz/zlib.a $(VM) o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/powerpc64le/blink/blinkenlights: o/$(MODE)/powerpc64le/blink/blinkenlights.o o/$(MODE)/powerpc64le/blink/blink.a o/$(MODE)/powerpc64le/third_party/libz/zlib.a $(VM) o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc $(LDFLAGS_STATIC) $^ -o $@ o/$(MODE)/blink/oneoff.com: o/$(MODE)/blink/oneoff.o o/$(MODE)/blink/blink.a $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/blink: \ o/$(MODE)/blink/blinkenlights \ o/$(MODE)/blink/blink \ $(BLINK_HDRS:%=o/$(MODE)/%.ok) ================================================ FILE: blink/blinkenlights.1 ================================================ .\" Copyright 2023 Justine Alexandra Roberts Tunney .\" .\" Permission to use, copy, modify, and/or distribute this software for .\" any purpose with or without fee is hereby granted, provided that the .\" above copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL .\" WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE .\" AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER .\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" .Dd March 6, 2023 .Dt BLINKENLIGHTS 1 .Os .Sh NAME .Nm blinkenlights .Nd x86-64-linux visualizer .Sh SYNOPSIS .Nm .Op Ar options .Ar program .Op Ar argv1... .Nm .Op Ar options .Fl 0 .Ar program .Op Ar argv0... .Sh DESCRIPTION .Nm is a terminal user interface for debugging x86_64-linux (or i8086) programs on POSIX platforms. It focuses on visualizing how program execution impacts memory. It uses UNICODE IBM Code Page 437 characters to display binary memory panels, which change as you step through your program's assembly code. These memory panels may be scrolled and zoomed using your mouse wheel. .Nm also permits reverse debugging, where scroll wheeling over the assembly display allows the rewinding of execution history. .Sh ARGUMENTS .Pp The .Ar program argument is a .Ev PATH searched command, which may be: .Pp .Bl -dash -compact .It An x86_64-linux ELF executable (either static or dynamic) .It An Actually Portable Executable (either MZqFpD or jartsr magic) .It A flat executable (if .Ar program ends with .bin, .img, or .raw) .It A shell script whose #!interpreter meets the above criteria .El .Pp The .Fl 0 flag allows .Li argv[0] to be specified on the command line. Under normal circumstances, .Bd -literal -offset indent blinkenlights cmd arg1 .Ed .Pp is equivalent to .Bd -literal -offset indent execve("cmd", {"cmd", "arg1"}) .Ed .Pp since that's how most programs are launched. However if you need the full power of execve() process spawning, you can say .Bd -literal -offset indent blinkenlights -0 cmd arg0 arg1 .Ed .Pp which is equivalent to .Bd -literal -offset indent execve("cmd", {"arg0", "arg1"}) .Ed .Pp .Sh OPTIONS The following options are available: .Bl -tag -width indent .It Fl h Prints condensed help. .It Fl v Shows .Nm version and build configuration details. .It Fl N Enables natural scrolling. .It Fl H Disables syntax highlighting. .It Fl r Puts your virtual machine in real mode. This may be used to run 16-bit i8086 programs, such as SectorLISP. It's also used for booting programs from Blinkenlights's simulated BIOS. .It Fl b Ar addr Pushes a breakpoint, which may be specified as a raw hexadecimal address, or a symbolic name that's defined by your ELF binary (or its associated .Li .dbg file). When pressing .Li c (continue) or .Li C (continue harder) in the TUI, Blink will immediately stop upon reaching an instruction that's listed as a breakpoint, after which a modal dialog is displayed. The modal dialog may be cleared by .Li ENTER after which the TUI resumes its normal state. .It Fl w Ar addr Pushes a watchpoint, which may be specified as a raw hexadecimal address, or a symbolic name that's defined by your ELF binary (or its associated .Li .dbg file). When pressing .Li c (continue) or .Li C (continue harder) in the TUI, Blink will immediately stop upon reaching an instruction that either (a) has a ModR/M encoding that references an address that's listed as a watchpoint, or (b) manages to mutate the memory stored at a watchpoint address by some other means. When Blinkenlights is stopped at a watchpoint, a modal dialog will be displayed which may be cleared by pressing .Li ENTER after which the TUI resumes its normal state. .It Fl t May be used to disable Blinkenlights TUI mode. This makes the program behave similarly to the .Xr blink 1 command, however not as good. We're currently using this flag for unit testing real mode programs, which are encouraged to use the .Li SYSCALL instruction to report their exit status. .It Fl s Enables system call logging (repeatable). .Pp This will emit to the log file the names of system calls each time a SYSCALL instruction in executed, along with its arguments and result. System calls are logged once they've completed, so that the result can be shown. .Pp System calls are also sometimes logged upon entry too, in which case .Li syscall(arg) -> ... will be logged to show that the system call has not yet completed. Whether or not this happens depends on how many times the .Fl s flag is supplied. .Pp .Bl -dash -compact .It Passing .Fl s (once) will only log the entries of system calls that are defined as having read + write parameters (e.g. poll, select) .It Passing .Fl ss (twice) will also log the entries of cancellation points that are likely to block (e.g. read, accept, wait, pause). .It Passing .Fl sss (thrice) will log the entries of system calls that POSIX defines as cancellation points but are unlikely to block (e.g. write, close, open) which we try to avoid doing in order to reduce log noise. .It Passing .Fl ssss (4x) will log the entry of every single system call, even harmless ones that have no business being emitted to the log twice (e.g. sigaction). This should only be useful for the Blink dev team when the rare need arises to troubleshoot a system call that's crashing. .El .Pp System call logging isn't available in .Li MODE=rel and .Li MODE=tiny builds, in which case this flag is ignored. .It Fl j Enables Just-In-Time (JIT) compilation. This will make Blinkenlights go significantly faster, at the cost of taking away the ability to step through each instruction. The TUI will visualize JIT path formation in the assembly display; see the JIT Path Glyphs section below to learn more. Please note this flag has the opposite meaning as it does in the .Xr blink 1 command. .It Fl m Enables the linear memory optimization. This makes .Nm capable of faster emulation, at the cost of losing some statistics. It no longer becomes possible to display which percentage of a memory map has been activated. Blinkenlights will also remove the commit / reserve / free page statistics from the status panel on the bottom right of the display. Please note this flag has the opposite meaning as it does in the .Xr blink 1 command. .It Fl L Ar path Specifies the log path. The default log path is .Ar blink.log in the current directory at startup. This log file won't be created until something is actually logged. If logging to a file isn't desired, then -L /dev/null may be used. See also the .Fl e flag for logging to standard error. .It Fl C Ar path Launch .Ar program in a chroot'd environment. This flag is both equivalent to and overrides the .Ev BLINK_OVERLAYS environment variable. .It Fl z [repeatable] May be specified to zoom the memory panels, so they display a larger amount of memory in a smaller space. By default, one terminal cell corresponds to a single byte of memory. When memory has been zoomed the magic kernel is used (similar to Lanczos) to decimate the number of bytes by half, for each .Fl z that's specified. Normally this would be accomplished by using .Li CTRL+MOUSEWHEEL where the mouse cursor is hovered over the panel that should be zoomed. However, many terminal emulators (especially on Windows), do not support this xterm feature and as such, this flag is provided as an alternative. .It Fl Z Prints internal statistics to standard error on exit. Each line will display a monitoring metric. Most metrics will either be integer counters or floating point running averages. Most but not all integer counters are monotonic. In the interest of not negatively impacting Blink's performance, statistics are computed on a best effort basis which currently isn't guaranteed to be atomic in a multi-threaded environment. Statistics aren't available in MODE=rel and MODE=tiny builds, in which case this flag is ignored. .It Fl V [repeatable] Increases verbosity. .It Fl R Disables reactive error mode. .El .Sh KEYBOARD SHORTCUTS The following keystrokes are recognized by the user interface: .Bl -tag -width indent .It Li ? Shows help dialog. .It Nm q Quit. .It Nm s Step. This executes a single instruction, stepping forward by one. .It Nm n Next. This is the same as .Nm s (Step) except it won't recurse into .Li CALL instructions. .It Nm c Continue. This will step automatically and display an animation of the program execution as it progresses. In continue mode, Blinkenlights will execute as many instructions as possible, and only render a limited number of 60 frames per second to the terminal. Snapshots are captured in the background of the in-between steps that aren't displayed. They may still be viewed by pausing execution using .Nm CTRL-C (Interrupt) and then pressing UP arrow to scroll backwards through execution history. For large programs, this animation can be sped up (at the cost of losing frames) by using the .Nm CTRL-T (Turbo) shortcut. .It Nm C Continue Harder. This will execute the program in the background as quickly as possible until some kind of halting event occurs, such as exit_group() being called, or a segmentation fault. No animation is displayed during this time. .It Nm CTRL-C Interrupt. Pressing this key will interrupt the TUI animation when in .Nm c (Continue) mode. Control will then return to the main interface, and keyboard shortcuts such as .Nm s (Step) may once again be used. Pressing .Nm CTRL-C also has the same effect if the embedded teletypewriter is blocked on a read() call, awaiting keyboard input. .It Nm CTRL-T Turbo. The turbo key may be pressed multiple times to specify how many steps should happen per frame in .Nm c (Continue) mode. Each time this key is pressed, the status bar on the bottom left-hand side of the display will be updated with the current speed, which defaults to 1. .It Nm ALT-T Slowmo. The slowmo keyboard shortcut has the opposite effect of .Nm CTRL-T (Turbo) in the sense that it slows down the speed of the .Nm c (Continue) mode animation. Each time this key is pressed, the status bar on the bottom left-hand side of the display will be updated with the current speed, which defaults to 1, and descends into negative numbers. Positive values are defined as the number of steps per frame. Negative numbers will result in sleep delays being inserted between steps. .It Nm p Profiling Mode. Pressing the .Nm p key will cause the TUI to cycle between the profiling and backtrace panels. When .Nm blinkenlights is running, it maintains a naive count of the number of assembly opcodes executed at each memory address. When the profiling panel is displayed, those counters will be grouped by function, ranked, and displayed as a percentage of the total. This is intended to help identify, in real time as execution progresses, which functions are execution hotspots. .It Nm t SSE Type. When the SSE panel is being displayed, the TUI will determine the type of each XMM register based on the instructions used. The three different types defined for this purpose are (1) integral, (2) single, and (3) double. .It Nm T SSE Size. When the SSE panel is being displayed, pressing this key will cycle the vector element size of XMM registers in integral mode. The following sizes are defined: 1 (byte), 2 (word), 4 (dword), 8 (qword). .It Nm x SSE Radix. When the SSE panel is being displayed, pressing this key will cycle the display of XMM registers currently in integral mode, so that they're displayed as either (1) hexadecimal, (2) characters (CP437), or (3) decimal. Floating point XMM registers aren't impacted, unless the .Nm t (Sse Type) key is pressed beforehand to cycle them into integral mode. .It Nm M The .Nm M key may be pressed to toggle xterm mouse tracking. This may be useful for terminals that do not allow copying and pasting terminal content when mouse tracking is enabled (try shift+drag too). .It Nm MOUSEWHEEL Scroll. Using the mouse wheel has a different effect depending on which panel the mouse cursor is currently hovering over. When the mouse is above the disassembly panel, scrolling the mouse wheel will rewind and replay the history of program execution. When above memory panels, mouse wheel will display different memory addresses. .It Nm CTRL-MOUSEWHEEL Zoom. On platforms such as Linux that support the necessary xterm escape code for doing this, using mousewheel while holding down the control key when the mouse cursor is hovering above one of the memory panels, will cause that memory panel to become zoomed. Under normal circumstances, each TTY cell corresponds to a single byte of memory. Zooming by one notch will cause each cell to display two bytes of memory. Then four. Then eight. This is accomplished by successively applying an image scaling algorithm to the adjacent memory. .It Nm CTRL-Z Stop. Pressing this shortcut will place .Nm in the background and return control to the shell. You may resume your debugging session later by running the .Nm fg command. .It Nm CTRL-L Refresh. Pressing this keyboard shortcut will cause the display to be redrawn. This may be useful on the oft chance the terminal state becomes corrupted. .It Nm CTRL-D EOF (End Of File). This keystroke has two different meanings depending on context. When control is held by the debugger TUI, this will ask .Nm to exit. When control is held by the guest program invoking read() in the teletypewriter, this will close the standard input handle. .El .Sh ENVIRONMENT The following environment variables are recognized: .Bl -tag -width indent .It Ev BLINK_LOG_FILENAME may be specified to supply a log path to be used in cases where the .Fl L Ar path flag isn't specified. This value should be an absolute path. If logging to standard error is desired, use the .Fl e flag. .It Ev BLINK_OVERLAYS specifies one or more directories to use as the root filesystem. Similar to .Ev PATH this is a colon delimited list of pathnames. If relative paths are specified, they'll be resolved to an absolute path at startup time. Overlays only apply to IO system calls that specify an absolute path. The empty string overlay means use the normal / root filesystem. The default value is .Li :o which means if the absolute path .Li /$f is opened, then first check if .Li /$f exists, and if it doesn't, then check if .Li o/$f exists, in which case open that instead. Blink uses this convention to open shared object tests. It favors the system version if it exists, but also downloads .Li ld-musl-x86_64.so.1 to .Li o/lib/ld-musl-x86_64.so.1 so the dynamic linker can transparently find it on platforms like Apple, that don't let users put files in the root folder. On the other hand, it's possible to say .Li BLINK_OVERLAYS=o: so that .Li o/... takes precedence over .Li /... (noting again that empty string means root). If a single overlay is specified that isn't empty string, then it'll effectively act as a restricted chroot environment. .El .Sh EXIT STATUS The .Nm command passes along the exit code of the .Ar program which by convention is 0 on success or >0 on failure. In the event that .Nm fails to launch .Ar program the status 127 shall be returned. .Sh SEE ALSO .Xr blink 1 .Sh AUTHORS .An "Justine Alexandra Roberts Tunney" Aq jtunney@gmail.com .Sh QUIRKS Blinkenlights TUI currently isn't suitable for debugging programs that spawn threads / processes. While such programs may be debugged, separate threads and processes can not be controlled reliably by the keyboard. ================================================ FILE: blink/blinkenlights.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/blinkenlights.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/bda.h" #include "blink/biosrom.h" #include "blink/bitscan.h" #include "blink/breakpoint.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/case.h" #include "blink/cga.h" #include "blink/debug.h" #include "blink/dis.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/fds.h" #include "blink/flag.h" #include "blink/flags.h" #include "blink/fpu.h" #include "blink/high.h" #include "blink/linux.h" #include "blink/loader.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/mda.h" #include "blink/overlays.h" #include "blink/panel.h" #include "blink/pml4t.h" #include "blink/pty.h" #include "blink/rde.h" #include "blink/signal.h" #include "blink/sigwinch.h" #include "blink/stats.h" #include "blink/strwidth.h" #include "blink/syscall.h" #include "blink/thompike.h" #include "blink/timespec.h" #include "blink/tsan.h" #include "blink/types.h" #include "blink/util.h" #include "blink/vfs.h" #include "blink/watch.h" #include "blink/web.h" #include "blink/xlat.h" #include "blink/xmmtype.h" #ifndef BUILD_TIMESTAMP #define BUILD_TIMESTAMP __TIMESTAMP__ #endif #ifndef BUILD_MODE #define BUILD_MODE "BUILD_MODE_UNKNOWN" #warning "-DBUILD_MODE=... should be passed to blink/blinkenlights.c" #endif #ifndef BUILD_TOOLCHAIN #define BUILD_TOOLCHAIN "BUILD_TOOLCHAIN_UNKNOWN" #warning "-DBUILD_TOOLCHAIN=... should be passed to blink/blinkenlights.c" #endif #ifndef BLINK_VERSION #define BLINK_VERSION "BLINK_VERSION_UNKNOWN" #warning "-DBLINK_VERSION=... should be passed to blink/blinkenlights.c" #endif #ifndef BLINK_COMMITS #define BLINK_COMMITS "BLINK_COMMITS_UNKNOWN" #warning "-DBLINK_COMMITS=... should be passed to blink/blinkenlights.c" #endif #ifndef BLINK_GITSHA #define BLINK_GITSHA "BLINK_GITSHA_UNKNOWN" #warning "-DBLINK_GITSHA=... should be passed to blink/blinkenlights.c" #endif #ifndef CONFIG_ARGUMENTS #define CONFIG_ARGUMENTS "CONFIG_ARGUMENTS_UNKNOWN" #warning "-DCONFIG_ARGUMENTS=... should be passed to blink/blinkenlights.c" #endif #define VERSION \ "Blinkenlights " BLINK_VERSION " (" BUILD_TIMESTAMP ")\n\ Copyright (c) 2023 Justine Alexandra Roberts Tunney\n\ Blinkenlights comes with absolutely NO WARRANTY of any kind.\n\ You may redistribute copies of Blinkenlights under the ISC License.\n\ For more information, see the file named LICENSE.\n\ Toolchain: " BUILD_TOOLCHAIN "\n\ Revision: #" BLINK_COMMITS " " BLINK_GITSHA "\n\ Config: ./configure MODE=" BUILD_MODE " " CONFIG_ARGUMENTS "\n" #define USAGE \ " [-?HhrRsZtv] [ROM] [ARGS...]\n\ \n\ DESCRIPTION\n\ \n\ blinkenlights - x86_64-linux virtual machine tui\n\ \n\ FLAGS\n\ \n\ -h help\n\ -z zoom\n\ -v version\n\ -r real mode (i8086)\n\ -s system call trace\n\ -H disable highlight\n\ -t disable tui mode\n\ -R disable reactive\n\ -b ADDR push a breakpoint\n\ -w ADDR push a watchpoint\n\ -L PATH log file location\n\ -B PATH alternate BIOS image\n\ -Z internal statistics\n\ \n\ ARGUMENTS\n\ \n\ ROM files may be ELF, Actually Portable Executable, or flat.\n\ It should use x86_64 in accordance with the System Five ABI.\n\ The SYSCALL ABI is defined as it is written in Linux Kernel.\n\ \n\ FEATURES\n\ \n\ 8086, 8087, i386, x86_64, SSE3, SSSE3, POPCNT, MDA, CGA, TTY\n\ Type ? for keyboard shortcuts and CLI flags inside emulator.\n\ \n" #define FPS 60 // frames per second written to tty #define TURBO true // to keep executing between frames #define HISTORY 65536 // number of rewind renders to ring #define WHEELDELTA 1 // how much impact scroll wheel has #define MAXZOOM 16 // lg2 maximum memory panel scaling #define DISPWIDTH 80 // size of the embedded tty display #define DUMPWIDTH 64 // columns of bytes in memory panel #define ASMWIDTH 40 // seed the width of assembly panel #define ASMRAWMIN (m->mode.omode == XED_MODE_REAL ? 50 : 65) #define RESTART 0x001 #define REDRAW 0x002 #define CONTINUE 0x004 #define STEP 0x008 #define NEXT 0x010 #define FINISH 0x020 #define MODAL 0x040 #define WINCHED 0x080 #define INT 0x100 #define QUIT 0x200 #define EXIT 0x400 #define ALARM 0x800 #define kXmmDecimal 0 #define kXmmHex 1 #define kXmmChar 2 #define kMouseLeftDown 0 #define kMouseMiddleDown 1 #define kMouseRightDown 2 #define kMouseLeftUp 4 #define kMouseMiddleUp 5 #define kMouseRightUp 6 #define kMouseLeftDrag 32 #define kMouseMiddleDrag 33 #define kMouseRightDrag 34 #define kMouseWheelUp 64 #define kMouseWheelDown 65 #define kMouseCtrlWheelUp 80 #define kMouseCtrlWheelDown 81 #define kAsanScale 3 #define kAsanMagic 0x7fff8000 #define kAsanHeapFree -1 #define kAsanStackFree -2 #define kAsanRelocated -3 #define kAsanHeapUnderrun -4 #define kAsanHeapOverrun -5 #define kAsanGlobalOverrun -6 #define kAsanGlobalUnregistered -7 #define kAsanStackUnderrun -8 #define kAsanStackOverrun -9 #define kAsanAllocaUnderrun -10 #define kAsanAllocaOverrun -11 #define kAsanUnscoped -12 #define kAsanUnmapped -13 #define Ctrl(C) ((C) ^ 0100) #ifdef IUTF8 #define HR L'─' #define BULB "◎" #else #define HR '-' #define BULB "@" #endif struct Mouse { short y; short x; int e; }; struct MemoryView { i64 start; int zoom; }; struct Keystrokes { unsigned i; char p[4][32]; struct timespec s[4]; }; struct Panels { union { struct { struct Panel disassembly; struct Panel breakpointshr; struct Panel breakpoints; struct Panel mapshr; struct Panel maps; struct Panel frameshr; struct Panel frames; struct Panel displayhr; struct Panel display; struct Panel registers; struct Panel ssehr; struct Panel sse; struct Panel codehr; struct Panel code; struct Panel readhr; struct Panel readdata; struct Panel writehr; struct Panel writedata; struct Panel stackhr; struct Panel stack; struct Panel status; }; struct Panel p[21]; }; }; struct Rendering { u64 cycle; void *data; unsigned compsize; unsigned origsize; }; struct History { unsigned index; unsigned count; unsigned viewing; struct Rendering p[HISTORY]; }; struct ProfSym { int sym; // dis->syms.p[sym] unsigned long hits; }; struct ProfSyms { int i, n; unsigned long toto; struct ProfSym *p; }; static const char kHelp[] = "\ \033[1mBlinkenlights " BLINK_VERSION "\033[22m\ https://github.com/jart/blink/\n\ \n\ KEYBOARD SHORTCUTS CLI FLAGS\n\ \n\ ctrl-c interrupt -t no tui\n\ s step -r real mode\n\ n next -Z statistics\n\ c continue -b ADDR push breakpoint\n\ C continue harder -w ADDR push watchpoint\n\ q quit -L PATH log file location\n\ f finish -R deliver crash sigs\n\ R restart -H disable highlighting\n\ ? help -v blinkenlights version\n\ x sse radix -j enables jit\n\ t sse type -m disables memory safety\n\ T sse size -N natural scroll wheel\n\ b push breakpoint -s system call logging\n\ B pop breakpoint\n\ p profiling mode -C PATH chroot directory\n\ ctrl-t turbo -B PATH alternate BIOS image\n\ alt-t slowmo -z zoom\n\ 2 toggle column 2 -h help\n\ 3 toggle column 3"; static const char kRipName[3][4] = {"IP", "EIP", "RIP"}; static const char kRegisterNames[3][16][4] = { {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"}, {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"}, {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", // "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"}, }; extern char **environ; /* shared variables with bios.c */ bool tuimode; bool ptyisenabled; int vidya; int ttyin; struct Pty *pty; struct Machine *m; static bool belay; static bool react; static bool alarmed; static bool natural; static bool mousemode; static bool wantmetal; static bool displayexec; /* 'D' -> DrawDisplayOnly during Exec() */ static bool showhighsse; static bool showprofile; static bool readingteletype; static bool showcolumn2 = true; static bool showcolumn3 = true; static int tyn; static int txn; static int tick; static int speed; static int action; static int ttyout; static int opline; static int xmmdisp; static int verbose; static int exitcode; static long ips; static u64 cycle; static i64 opstart; static int lastfds; static i64 lastrss; static i64 lastvss; static u64 readaddr; static u64 readsize; static u64 writeaddr; static u64 writesize; static i64 mapsstart; static u64 last_cycle; static char *codepath; static i64 framesstart; static jmp_buf *onbusted; static const char *dialog; static char *statusmessage; static i64 breakpointsstart; static unsigned long *ophits; static struct ProfSyms profsyms; static struct Panels pan; static struct Keystrokes keystrokes; static struct Breakpoints breakpoints; static struct Watchpoints watchpoints; static struct MemoryView codeview; static struct MemoryView readview; static struct MemoryView writeview; static struct MemoryView stackview; static struct MachineState laststate; static struct MachineMemstat lastmemstat; static struct XmmType xmmtype; static struct Dis dis[1]; static struct timespec last_draw; static struct timespec statusexpires; static struct termios oldterm; static char systemfailure[128]; static struct sigaction oldsig[4]; static char pathbuf[PATH_MAX]; struct History g_history; static void SetupDraw(void); static void HandleKeyboard(const char *); const char kXedErrorNames[] = "\ none\0\ buffer too short\0\ general error\0\ invalid for chip\0\ bad register\0\ bad lock prefix\0\ bad rep prefix\0\ bad legacy prefix\0\ bad rex prefix\0\ bad evex ubit\0\ bad map\0\ bad evex v prime\0\ bad evex z no masking\0\ no output pointer\0\ no agen call back registered\0\ bad memop index\0\ callback problem\0\ gather regs\0\ instr too long\0\ invalid mode\0\ bad evex ll\0\ unimplemented\0\ "; static char *xasprintf(const char *fmt, ...) { char *s; va_list va; va_start(va, fmt); unassert(vasprintf(&s, fmt, va) != -1); va_end(va); return s; } static char *FormatDouble(char buf[32], double x) { snprintf(buf, 32, "%g", x); return buf; } static char *FormatLongDouble(char buf[32], long double x) { snprintf(buf, 32, "%Lg", x); return buf; } static i64 SignExtend(u64 x, char b) { char k; unassert(1 <= b && b <= 64); k = 64 - b; return (i64)(x << k) >> k; } void SetCarry(bool cf) { m->flags = SetFlag(m->flags, FLAGS_CF, cf); } static bool IsCall(void) { switch (Mopcode(m->xedd->op.rde)) { case 0x0CC: case 0x0CD: case 0x0CE: case 0x0E8: return true; case 0x0FF: return ModrmReg(m->xedd->op.rde) == 2; default: return false; } } static bool IsDebugBreak(void) { return m->trapno == 3 && Mopcode(m->xedd->op.rde) == 0x0CC; } static bool IsRet(void) { switch (Mopcode(m->xedd->op.rde)) { case 0x0C2: case 0x0C3: case 0x0CA: case 0x0CB: case 0x0CF: return true; default: return false; } } static int GetXmmTypeCellCount(int r) { switch (xmmtype.type[r]) { case kXmmIntegral: return 16 / xmmtype.size[r]; case kXmmFloat: return 4; case kXmmDouble: return 2; default: __builtin_unreachable(); } } static u8 CycleXmmType(u8 t) { switch (t) { default: case kXmmIntegral: return kXmmFloat; case kXmmFloat: return kXmmDouble; case kXmmDouble: return kXmmIntegral; } } static u8 CycleXmmDisp(u8 t) { switch (t) { default: case kXmmDecimal: return kXmmHex; case kXmmHex: return kXmmChar; case kXmmChar: return kXmmDecimal; } } static u8 CycleXmmSize(u8 w) { switch (w) { default: case 1: return 2; case 2: return 4; case 4: return 8; case 8: return 1; } } static int GetPointerWidth(void) { return 2 << m->mode.omode; } static i64 GetSp(void) { switch (GetPointerWidth()) { default: case 8: return Read64(m->sp); case 4: return m->ss.base + Read32(m->sp); case 2: return m->ss.base + Read16(m->sp); } } static void AppendPanel(struct Panel *p, i64 line, const char *s) { if (0 <= line && line < p->bottom - p->top) { AppendStr(&p->lines[line], s); } } static int CompareProfSyms(const void *p, const void *q) { const struct ProfSym *a = (const struct ProfSym *)p; const struct ProfSym *b = (const struct ProfSym *)q; if (a->hits > b->hits) return -1; if (a->hits < b->hits) return +1; return 0; } static void SortProfSyms(void) { qsort(profsyms.p, profsyms.i, sizeof(*profsyms.p), CompareProfSyms); } static int AddProfSym(int sym, unsigned long hits) { if (!hits) return -1; if (profsyms.i == profsyms.n) { profsyms.p = (struct ProfSym *)realloc(profsyms.p, ++profsyms.n * sizeof(*profsyms.p)); } profsyms.p[profsyms.i].sym = sym; profsyms.p[profsyms.i].hits = hits; return profsyms.i++; } static unsigned long TallyHits(i64 addr, int size) { i64 pc; unsigned long hits; for (hits = 0, pc = addr; pc < addr + size; ++pc) { hits += ophits[pc - m->system->codestart]; } return hits; } static void GenerateProfile(void) { int sym; profsyms.i = 0; if (!ophits) return; profsyms.toto = TallyHits(m->system->codestart, m->system->codesize); for (sym = 0; sym < dis->syms.i; ++sym) { if (dis->syms.p[sym].addr >= m->system->codestart && dis->syms.p[sym].addr + dis->syms.p[sym].size < m->system->codestart + m->system->codesize) { AddProfSym(sym, TallyHits(dis->syms.p[sym].addr, dis->syms.p[sym].size)); } } SortProfSyms(); profsyms.i = MIN(50, profsyms.i); } static void DrawProfile(struct Panel *p) { int i; char line[256]; GenerateProfile(); for (i = 0; i < profsyms.i; ++i) { snprintf(line, sizeof(line), "%7.3f%% %s", (double)profsyms.p[i].hits / profsyms.toto * 100, dis->syms.p[profsyms.p[i].sym].name); AppendPanel(p, i - framesstart, line); } } static void CopyMachineState(struct MachineState *ms) { ms->ip = m->ip; ms->cs = m->cs; ms->ss = m->ss; ms->es = m->es; ms->ds = m->ds; ms->fs = m->fs; ms->gs = m->gs; memcpy(ms->weg, m->weg, sizeof(m->weg)); memcpy(ms->xmm, m->xmm, sizeof(m->xmm)); memcpy(&ms->fpu, &m->fpu, sizeof(m->fpu)); memcpy(&ms->mxcsr, &m->mxcsr, sizeof(m->mxcsr)); } /** * Handles file mapped page faults in valid page but past eof. */ static void OnSigBusted(int sig) { longjmp(*onbusted, 1); } /** * Returns true if 𝑣 is a shadow memory virtual address. */ static bool IsShadow(i64 v) { return 0x7fff8000 <= v && v < 0x100080000000; } /** * Returns glyph representing byte at virtual address 𝑣. */ static int VirtualBing(i64 v) { u8 *p; int rc; jmp_buf busted; onbusted = &busted; if ((p = SpyAddress(m, v))) { if (!setjmp(busted)) { rc = kCp437[p[0] & 255]; } else { rc = L'≀'; } } else { rc = L'⋅'; } onbusted = NULL; return rc; } /** * Returns ASAN shadow uint8 concomitant to address 𝑣 or -1. */ static int VirtualShadow(i64 v) { int rc; char *p; jmp_buf busted; if (IsShadow(v)) return -2; onbusted = &busted; if ((p = (char *)SpyAddress(m, (v >> 3) + 0x7fff8000))) { if (!setjmp(busted)) { rc = p[0] & 0xff; } else { rc = -1; } } else { rc = -1; } onbusted = NULL; return rc; } static void ScrollOp(struct Panel *p, i64 op) { i64 n; opline = op; if ((n = p->bottom - p->top) > 1) { if (!(opstart + 1 <= op && op < opstart + n)) { opstart = MIN(MAX(0, op - n / 8), MAX(0, dis->ops.i - n)); } } } static int TtyWriteString(const char *s) { return VfsWrite(ttyout, s, strlen(s)); } static void OnFeed(void) { TtyWriteString("\033[K\033[2J"); } static void HideCursor(void) { TtyWriteString("\033[?25l"); } static void ShowCursor(void) { if (tuimode) { TtyWriteString("\033[?25h"); } } static void EnableMouseTracking(void) { mousemode = true; TtyWriteString("\033[?1000;1002;1015;1006h"); } static void DisableMouseTracking(void) { if (mousemode) { TtyWriteString("\033[?1000;1002;1015;1006l"); mousemode = false; } } static void ToggleMouseTracking(void) { if (mousemode) { DisableMouseTracking(); } else { EnableMouseTracking(); } } static void LeaveScreen(void) { char buf[64]; if (tuimode) { sprintf(buf, "\033[%d;%dH\033[S\n", tyn, txn); TtyWriteString(buf); } } static void GetTtySize(int fd) { struct winsize wsize; wsize.ws_row = tyn; wsize.ws_col = txn; VfsIoctl(fd, TIOCGWINSZ, &wsize); tyn = wsize.ws_row; txn = wsize.ws_col; } static void TuiRejuvinate(void) { struct termios term; struct sigaction sa; LOGF("TuiRejuvinate"); GetTtySize(ttyout); HideCursor(); memcpy(&term, &oldterm, sizeof(term)); term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 1; term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); term.c_iflag &= ~(IXOFF | PARMRK | INLCR | IGNCR | IGNPAR); term.c_iflag |= IGNBRK; term.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHOE | ECHONL | NOFLSH | TOSTOP | ECHOK); term.c_lflag |= ISIG; term.c_cflag &= ~(CSIZE | PARENB); term.c_cflag |= CS8 | CREAD; term.c_oflag |= OPOST | ONLCR; term.c_lflag &= ~ECHOK; #ifdef IMAXBEL term.c_iflag &= ~IMAXBEL; #endif #ifdef PENDIN term.c_lflag &= ~PENDIN; #endif #ifdef IUTF8 term.c_iflag |= IUTF8; #endif VfsTcsetattr(ttyout, TCSANOW, &term); memset(&sa, 0, sizeof(sa)); sa.sa_handler = OnSigBusted; sa.sa_flags = SA_NODEFER; sigaction(SIGBUS, &sa, 0); EnableMouseTracking(); } static void OnQ(void) { action |= EXIT; } static void OnV(void) { int mode; mode = vidya == kModePty ? 3 : kModePty; VidyaServiceSetMode(mode); } static void OnSigSys(int sig) { // do nothing } static void OnSigWinch(int sig) { EnqueueSignal(m, SIGWINCH_LINUX); action |= WINCHED; } static void OnSigInt(int sig) { action |= INT; } static void OnSigAlrm(int sig) { action |= ALARM; } static void TtyRestore(void) { LOGF("TtyRestore"); TtyWriteString("\033[0m"); DisableMouseTracking(); ShowCursor(); VfsTcsetattr(ttyout, TCSANOW, &oldterm); } static void TuiCleanup(void) { LOGF("TuiCleanup"); sigaction(SIGCONT, oldsig + 2, 0); TtyRestore(); } static void OnSigTstp(int sig) { TtyRestore(); raise(SIGSTOP); } static void OnSigCont(int sig) { if (tuimode) { TuiRejuvinate(); Redraw(true); } EnqueueSignal(m, SIGCONT); } static void ResolveBreakpoints(void) { long i, sym; for (i = 0; i < breakpoints.i; ++i) { if (breakpoints.p[i].symbol && !breakpoints.p[i].addr) { if ((sym = DisFindSymByName(dis, breakpoints.p[i].symbol)) != -1) { breakpoints.p[i].addr = dis->syms.p[sym].addr; } } } } static void ResolveWatchpoints(void) { long i, sym; for (i = 0; i < watchpoints.i; ++i) { if (watchpoints.p[i].symbol && !watchpoints.p[i].addr) { if ((sym = DisFindSymByName(dis, watchpoints.p[i].symbol)) != -1) { watchpoints.p[i].addr = dis->syms.p[sym].addr; } } } } static void BreakAtNextInstruction(void) { struct Breakpoint b; memset(&b, 0, sizeof(b)); b.addr = GetPc(m) + m->xedd->length; b.oneshot = true; PushBreakpoint(&breakpoints, &b); } static void BreakAtCurrentInstruction(void) { struct Breakpoint b; if (IsAtBreakpoint(&breakpoints, m->ip) != -1) return; memset(&b, 0, sizeof(b)); b.addr = m->ip; PushBreakpoint(&breakpoints, &b); } static int DrainInput(int fd) { char buf[32]; struct pollfd fds[1]; for (;;) { fds[0].fd = fd; fds[0].events = POLLIN; if (VfsPoll(fds, ARRAYLEN(fds), 0) == -1) return -1; if (!(fds[0].revents & POLLIN)) break; if (VfsRead(fd, buf, sizeof(buf)) == -1) return -1; } return 0; } static int ReadCursorPosition(int *out_y, int *out_x) { int y, x; char *p, buf[32]; if (readansi(ttyin, buf, sizeof(buf)) == 1) return -1; p = buf; if (*p == 033) ++p; if (*p == '[') ++p; y = strtol(p, &p, 10); if (*p == ';') ++p; x = strtol(p, &p, 10); if (*p != 'R') { errno = EBADMSG; return -1; } if (out_y) *out_y = MAX(1, y) - 1; if (out_x) *out_x = MAX(1, x) - 1; return 0; } static int GetCursorPosition(int *out_y, int *out_x) { TtyWriteString("\033[6n"); return ReadCursorPosition(out_y, out_x); } void OnSymbols(struct System *s) { ResolveBreakpoints(); ResolveWatchpoints(); } void CommonSetup(void) { static bool once; if (!once) { if (tuimode || breakpoints.i || watchpoints.i) { m->system->dis = dis; m->system->onsymbols = OnSymbols; LoadDebugSymbols(m->system); } once = true; } } void TuiSetup(void) { int y; bool report; char buf[64]; static bool once; struct itimerval it; struct sigaction sa; report = false; if (!once) { LOGF("loaded program %s\n%s", codepath, FormatPml4t(m)); CommonSetup(); VfsTcgetattr(ttyout, &oldterm); atexit(TtyRestore); AtAbort(TtyRestore); once = true; report = true; } memset(&it, 0, sizeof(it)); setitimer(ITIMER_REAL, &it, 0); memset(&sa, 0, sizeof(sa)); sa.sa_handler = OnSigCont; sa.sa_flags = SA_RESTART | SA_NODEFER; sigaction(SIGCONT, &sa, oldsig + 2); sa.sa_handler = OnSigTstp; sigaction(SIGTSTP, &sa, 0); CopyMachineState(&laststate); TuiRejuvinate(); if (report) { DrainInput(ttyin); y = 0; if (GetCursorPosition(&y, NULL) != -1) { sprintf(buf, "\033[%dS", y); TtyWriteString(buf); } } } static void ExecSetup(void) { struct itimerval it; CommonSetup(); it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 1. / FPS * 1e6; it.it_value.tv_sec = 0; it.it_value.tv_usec = 1. / FPS * 1e6; if (!m->metal) setitimer(ITIMER_REAL, &it, 0); } static void pcmpeqb(u8 x[16], const u8 y[16]) { for (int i = 0; i < 16; ++i) x[i] = -(x[i] == y[i]); } static unsigned pmovmskb(const u8 p[16]) { unsigned i, m; for (m = i = 0; i < 16; ++i) m |= !!(p[i] & 0x80) << i; return m; } static bool IsXmmNonZero(i64 start, i64 end) { i64 i; u8 v1[16], vz[16]; for (i = start; i < end; ++i) { memset(vz, 0, 16); memcpy(v1, m->xmm[i], 16); pcmpeqb(v1, vz); if (pmovmskb(v1) != 0xffff) { return true; } } return false; } static bool IsSegNonZero(void) { unsigned i; for (i = 0; i < 6; ++i) { if (GetSegmentBase(DISPATCH_NOTHING, i)) { return true; } } return false; } static int PickNumberOfXmmRegistersToShow(void) { if (IsXmmNonZero(0, 8) || IsXmmNonZero(8, 16)) { if (showhighsse || IsXmmNonZero(8, 16)) { showhighsse = true; return 16; } else { return 8; } } else { showhighsse = false; return 0; } } static int GetRegHexWidth(void) { switch (m->mode.omode) { case XED_MODE_LONG: return 16; case XED_MODE_LEGACY: return 8; case XED_MODE_REAL: if ((Read64(m->ax) >> 16) || (Read64(m->cx) >> 16) || (Read64(m->dx) >> 16) || (Read64(m->bx) >> 16) || (Read64(m->sp) >> 16) || (Read64(m->bp) >> 16) || (Read64(m->si) >> 16) || (Read64(m->di) >> 16)) { return 8; } else { return 4; } default: __builtin_unreachable(); } } static int GetAddrHexWidth(void) { switch (m->mode.omode) { case XED_MODE_LONG: return 12; case XED_MODE_LEGACY: return 8; case XED_MODE_REAL: if (m->fs.base >= 0x10fff0 || m->gs.base >= 0x10fff0) { return 8; } else { return 6; } default: __builtin_unreachable(); } } bool ShouldShowDisplay(void) { if (vidya != kModePty) return true; // in bios video mode if (displayexec) return true; return ptyisenabled; } static void SetupDraw(void) { int i, j, n, a, b, yn, fit, cpuy, ssey, dx[2], c2y[3], c3y[5]; cpuy = 9; if (IsSegNonZero()) cpuy += 2; ssey = PickNumberOfXmmRegistersToShow(); if (ssey) ++ssey; int column[3] = { GetAddrHexWidth() + 1 + ASMWIDTH, DISPWIDTH, GetAddrHexWidth() + 1 + DUMPWIDTH, }; if (!showcolumn2) column[1] = 0; if (!showcolumn3) column[2] = 0; bool growable[3] = { true, false, false, }; bool shrinkable[3] = { true, true, false, }; for (i = 0;; ++i) { for (fit = j = 0; j < ARRAYLEN(column); ++j) { fit += column[j]; } if (fit > txn) { if (shrinkable[i % ARRAYLEN(column)]) { --column[i % ARRAYLEN(column)]; } } else if (fit < txn) { if (growable[i % ARRAYLEN(column)]) { ++column[i % ARRAYLEN(column)]; } } else { break; } } dis->noraw = column[0] < ASMRAWMIN; dx[0] = column[0]; dx[1] = column[0] + column[1]; yn = tyn - 1; a = 1 / 8. * yn; b = 3 / 8. * yn; if (ShouldShowDisplay()) { c2y[0] = breakpoints.i || watchpoints.i ? a * .7 : 0; c2y[1] = a * 2.3; c2y[2] = a * 2 + b; if (yn - c2y[2] > 26) { c2y[1] -= yn - c2y[2] - 26; c2y[2] = yn - 26; } if (yn - c2y[2] < 26) { c2y[2] = yn - 26; } } else { c2y[0] = breakpoints.i || watchpoints.i ? a * .7 : 0; c2y[1] = yn / 20 * 12; c2y[2] = yn; } a = (yn - (cpuy + ssey) - 3) / 4; c3y[0] = cpuy; c3y[1] = cpuy + ssey; c3y[2] = cpuy + ssey + 1 + 1 + a * 1; c3y[3] = cpuy + ssey + 1 + 1 + a * 2 + 1; c3y[4] = cpuy + ssey + 1 + 1 + 1 + a * 3 + 1; /* COLUMN #1: DISASSEMBLY */ pan.disassembly.top = 0; pan.disassembly.left = 0; pan.disassembly.bottom = yn; pan.disassembly.right = dx[0] - 1; /* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE, DISPLAY */ pan.breakpointshr.top = 0; pan.breakpointshr.left = dx[0]; pan.breakpointshr.bottom = breakpoints.i || watchpoints.i; pan.breakpointshr.right = dx[1] - 1; pan.breakpoints.top = 1; pan.breakpoints.left = dx[0]; pan.breakpoints.bottom = c2y[0]; pan.breakpoints.right = dx[1] - 1; pan.mapshr.top = c2y[0]; pan.mapshr.left = dx[0]; pan.mapshr.bottom = c2y[0] + 1; pan.mapshr.right = dx[1] - 1; pan.maps.top = c2y[0] + 1; pan.maps.left = dx[0]; pan.maps.bottom = c2y[1]; pan.maps.right = dx[1] - 1; pan.frameshr.top = c2y[1]; pan.frameshr.left = dx[0]; pan.frameshr.bottom = c2y[1] + 1; pan.frameshr.right = dx[1] - 1; pan.frames.top = c2y[1] + 1; pan.frames.left = dx[0]; pan.frames.bottom = c2y[2]; pan.frames.right = dx[1] - 1; pan.displayhr.top = c2y[2]; pan.displayhr.left = dx[0]; pan.displayhr.bottom = c2y[2] + ShouldShowDisplay(); pan.displayhr.right = dx[1] - 1; pan.display.top = c2y[2] + 1; pan.display.left = dx[0]; pan.display.bottom = yn; pan.display.right = dx[1] - 1; if (wantmetal) { unassert(pan.display.right - pan.display.left <= 80); unassert(pan.display.bottom - pan.display.top == 25); } /* COLUMN #3: REGISTERS, VECTORS, CODE, MEMORY READS, MEMORY WRITES, STACK */ pan.registers.top = 0; pan.registers.left = dx[1]; pan.registers.bottom = c3y[0]; pan.registers.right = txn; pan.ssehr.top = c3y[0]; pan.ssehr.left = dx[1]; pan.ssehr.bottom = c3y[0] + (ssey ? 1 : 0); pan.ssehr.right = txn; pan.sse.top = c3y[0] + (ssey ? 1 : 0); pan.sse.left = dx[1]; pan.sse.bottom = c3y[1]; pan.sse.right = txn; pan.codehr.top = c3y[1]; pan.codehr.left = dx[1]; pan.codehr.bottom = c3y[1] + 1; pan.codehr.right = txn; pan.code.top = c3y[1] + 1; pan.code.left = dx[1]; pan.code.bottom = c3y[2]; pan.code.right = txn; pan.readhr.top = c3y[2]; pan.readhr.left = dx[1]; pan.readhr.bottom = c3y[2] + 1; pan.readhr.right = txn; pan.readdata.top = c3y[2] + 1; pan.readdata.left = dx[1]; pan.readdata.bottom = c3y[3]; pan.readdata.right = txn; pan.writehr.top = c3y[3]; pan.writehr.left = dx[1]; pan.writehr.bottom = c3y[3] + 1; pan.writehr.right = txn; pan.writedata.top = c3y[3] + 1; pan.writedata.left = dx[1]; pan.writedata.bottom = c3y[4]; pan.writedata.right = txn; pan.stackhr.top = c3y[4]; pan.stackhr.left = dx[1]; pan.stackhr.bottom = c3y[4] + 1; pan.stackhr.right = txn; pan.stack.top = c3y[4] + 1; pan.stack.left = dx[1]; pan.stack.bottom = yn; pan.stack.right = txn; pan.status.top = yn; pan.status.left = 0; pan.status.bottom = yn + 1; pan.status.right = txn; for (i = 0; i < ARRAYLEN(pan.p); ++i) { if (pan.p[i].left > pan.p[i].right) { pan.p[i].left = pan.p[i].right = 0; } if (pan.p[i].top > pan.p[i].bottom) { pan.p[i].top = pan.p[i].bottom = 0; } n = pan.p[i].bottom - pan.p[i].top; if (n == pan.p[i].n) { for (j = 0; j < n; ++j) { pan.p[i].lines[j].i = 0; } } else { for (j = 0; j < pan.p[i].n; ++j) { free(pan.p[i].lines[j].p); } free(pan.p[i].lines); pan.p[i].lines = (struct Buffer *)calloc(n, sizeof(struct Buffer)); pan.p[i].n = n; } } PtyResize(pty, pan.display.bottom - pan.display.top, pan.display.right - pan.display.left); } static i64 Disassemble(void) { i64 lines; lines = pan.disassembly.bottom - pan.disassembly.top * 2; if (Dis(dis, m, GetPc(m), m->ip, lines) != -1) { return DisFind(dis, GetPc(m)); } else { return -1; } } static i64 GetDisIndex(void) { i64 i; if ((i = DisFind(dis, GetPc(m) - m->oplen)) != -1 || (i = Disassemble()) != -1) { while (i + 1 < dis->ops.i) { if (!dis->ops.p[i].size) { ++i; } else { break; } } } return i; } static void DrawDisassembly(struct Panel *p) { i64 i, j; for (i = 0; i < p->bottom - p->top; ++i) { j = opstart + i; if (0 <= j && j < dis->ops.i) { if (j == opline) AppendPanel(p, i, "\033[7m"); AppendPanel(p, i, DisGetLine(dis, m, j)); if (j == opline) AppendPanel(p, i, "\033[27m"); } } } static void DrawHr(struct Panel *p, const char *s) { i64 i, wp, ws, wl, wr; if (p->bottom - p->top < 1) return; wp = p->right - p->left; ws = 8; wl = wp / 4 - ws / 2; wr = wp - (wl + strwidth(s, 0)); for (i = 0; i < wl; ++i) AppendWide(&p->lines[0], HR); AppendStr(&p->lines[0], s); for (i = 0; i < wr; ++i) AppendWide(&p->lines[0], HR); AppendStr(&p->lines[0], "\033[0m"); } static void DrawTerminalHr(struct Panel *p) { i64 i, wp, ws, wl; struct itimerval it; if (p->bottom == p->top) return; if (pty->conf & kPtyBell) { if (!alarmed) { alarmed = true; it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; it.it_value.tv_sec = 0; it.it_value.tv_usec = 800000; setitimer(ITIMER_REAL, &it, 0); } AppendStr(&p->lines[0], "\033[1m"); } wp = p->right - p->left; ws = 8; wl = wp / 4 - ws / 2; for (i = 0; i < wl; ++i) AppendWide(&p->lines[0], HR); AppendFmt(&p->lines[0], "%sTELETYPEWRITER%s──%s──%s──%s──%s", readingteletype ? "\033[1m" : "", readingteletype ? "\033[22m" : "", (pty->conf & kPtyLed1) ? "\033[1;31m" BULB "\033[0m" : "○", (pty->conf & kPtyLed2) ? "\033[1;32m" BULB "\033[0m" : "○", (pty->conf & kPtyLed3) ? "\033[1;33m" BULB "\033[0m" : "○", (pty->conf & kPtyLed4) ? "\033[1;34m" BULB "\033[0m" : "○"); for (i = 26 + wl; i < p->right - p->left; ++i) { AppendWide(&p->lines[0], HR); } } static void DrawTerminal(struct Panel *p) { i64 y, yn; if (p->top == p->bottom) return; for (yn = MIN(pty->yn, p->bottom - p->top), y = 0; y < yn; ++y) { PtyAppendLine(pty, p->lines + y, y); AppendStr(p->lines + y, "\033[0m"); } } static void DrawDisplay(struct Panel *p) { switch (vidya) { case 0: // CGA 40x25 16-gray case 1: // CGA 40x25 16-color case 2: // CGA 80x25 16-gray case 3: // CGA 80x25 16-color DrawHr(&pan.displayhr, "COLOR GRAPHICS ADAPTER"); DrawCga(p, m->system->real + 0xb8000); break; case 7: // MDA 80x25 4-gray DrawHr(&pan.displayhr, "MONOCHROME DISPLAY ADAPTER"); DrawMda(p, (u8(*)[80][2])(m->system->real + 0xb0000), pty->x, pty->y); break; case kModePty: default: DrawTerminalHr(&pan.displayhr); DrawTerminal(p); break; } } static void DrawFlag(struct Panel *p, i64 i, char name, bool value) { char str[3] = " "; if (value) str[1] = name; AppendPanel(p, i, str); } static void DrawRegister(struct Panel *p, i64 i, i64 r, bool first) { char buf[32]; u64 value, previous; value = Read64(m->weg[r]); previous = Read64(laststate.weg[r]); if (value != previous) AppendPanel(p, i, "\033[7m"); snprintf(buf, sizeof(buf), "%-3s", kRegisterNames[m->mode.omode][r]); AppendPanel(p, i, buf); AppendPanel(p, i, " "); snprintf(buf, sizeof(buf), "%0*" PRIx64, GetRegHexWidth(), value); AppendPanel(p, i, buf); if (value != previous) AppendPanel(p, i, "\033[27m"); AppendPanel(p, i, " "); } static void DrawSegment(struct Panel *p, i64 i, struct DescriptorCache value, struct DescriptorCache previous, const char *name, bool fsgs) { bool changed = value.sel != previous.sel || value.base != previous.base; char buf[32]; if (changed) AppendPanel(p, i, "\033[7m"); snprintf(buf, sizeof(buf), "%-3s", name); AppendPanel(p, i, buf); AppendPanel(p, i, " "); if (fsgs) { // only FS & GS can have segment bases beyond the 4 GiB mark snprintf(buf, sizeof(buf), "%04" PRIx16 " @ %016" PRIx64, value.sel, value.base); } else { snprintf(buf, sizeof(buf), "%04" PRIx16 " @ %08" PRIx64, value.sel, value.base); } AppendPanel(p, i, buf); if (changed) AppendPanel(p, i, "\033[27m"); AppendPanel(p, i, " "); } static void DrawSt(struct Panel *p, i64 i, i64 r) { #ifndef DISABLE_X87 char buf[32]; bool isempty, chg; long double value; isempty = FpuGetTag(m, r) == kFpuTagEmpty; if (isempty) AppendPanel(p, i, "\033[38;5;241m"); value = m->fpu.st[(r + ((m->fpu.sw & kFpuSwSp) >> 11)) & 7]; chg = value != laststate.fpu.st[(r + ((m->fpu.sw & kFpuSwSp) >> 11)) & 7]; if (!isempty && chg) AppendPanel(p, i, "\033[7m"); snprintf(buf, sizeof(buf), "ST%" PRId64 " ", r); AppendPanel(p, i, buf); AppendPanel(p, i, FormatLongDouble(buf, value)); if (chg) AppendPanel(p, i, "\033[27m"); AppendPanel(p, i, " "); if (isempty) AppendPanel(p, i, "\033[39m"); #endif } static void DrawCpu(struct Panel *p) { char buf[48]; if (p->top == p->bottom) return; DrawRegister(p, 0, 7, 1), DrawRegister(p, 0, 0, 0), DrawSt(p, 0, 0); DrawRegister(p, 1, 6, 1), DrawRegister(p, 1, 3, 0), DrawSt(p, 1, 1); DrawRegister(p, 2, 2, 1), DrawRegister(p, 2, 5, 0), DrawSt(p, 2, 2); DrawRegister(p, 3, 1, 1), DrawRegister(p, 3, 4, 0), DrawSt(p, 3, 3); DrawRegister(p, 4, 8, 1), DrawRegister(p, 4, 12, 0), DrawSt(p, 4, 4); DrawRegister(p, 5, 9, 1), DrawRegister(p, 5, 13, 0), DrawSt(p, 5, 5); DrawRegister(p, 6, 10, 1), DrawRegister(p, 6, 14, 0), DrawSt(p, 6, 6); DrawRegister(p, 7, 11, 1), DrawRegister(p, 7, 15, 0), DrawSt(p, 7, 7); snprintf(buf, sizeof(buf), "%-3s %0*" PRIx64 " FLG", kRipName[m->mode.omode], GetRegHexWidth(), m->ip); AppendPanel(p, 8, buf); DrawFlag(p, 8, 'C', GetFlag(m->flags, FLAGS_CF)); DrawFlag(p, 8, 'P', GetFlag(m->flags, FLAGS_PF)); DrawFlag(p, 8, 'A', GetFlag(m->flags, FLAGS_AF)); DrawFlag(p, 8, 'Z', GetFlag(m->flags, FLAGS_ZF)); DrawFlag(p, 8, 'S', GetFlag(m->flags, FLAGS_SF)); DrawFlag(p, 8, 'I', GetFlag(m->flags, FLAGS_IF)); DrawFlag(p, 8, 'D', GetFlag(m->flags, FLAGS_DF)); DrawFlag(p, 8, 'O', GetFlag(m->flags, FLAGS_OF)); AppendPanel(p, 8, " "); #ifndef DISABLE_X87 if (m->fpu.sw & kFpuSwIe) AppendPanel(p, 8, " IE"); if (m->fpu.sw & kFpuSwDe) AppendPanel(p, 8, " DE"); if (m->fpu.sw & kFpuSwZe) AppendPanel(p, 8, " ZE"); if (m->fpu.sw & kFpuSwOe) AppendPanel(p, 8, " OE"); if (m->fpu.sw & kFpuSwUe) AppendPanel(p, 8, " UE"); if (m->fpu.sw & kFpuSwPe) AppendPanel(p, 8, " PE"); if (m->fpu.sw & kFpuSwSf) AppendPanel(p, 8, " SF"); if (m->fpu.sw & kFpuSwEs) AppendPanel(p, 8, " ES"); if (m->fpu.sw & kFpuSwC0) AppendPanel(p, 8, " C0"); if (m->fpu.sw & kFpuSwC1) AppendPanel(p, 8, " C1"); if (m->fpu.sw & kFpuSwC2) AppendPanel(p, 8, " C2"); if (m->fpu.sw & kFpuSwBf) AppendPanel(p, 8, " BF"); #endif DrawSegment(p, 9, m->fs, laststate.fs, "FS", true); DrawSegment(p, 9, m->ds, laststate.ds, "DS", false); DrawSegment(p, 9, m->cs, laststate.cs, "CS", false); DrawSegment(p, 10, m->gs, laststate.gs, "GS", true); DrawSegment(p, 10, m->es, laststate.es, "ES", false); DrawSegment(p, 10, m->ss, laststate.ss, "SS", false); } static void DrawXmm(struct Panel *p, i64 i, i64 r) { float f; double d; wchar_t ival; char buf[32]; bool changed; u64 itmp; u8 xmm[16]; i64 j, k, n; int cells, left, cellwidth, panwidth; memcpy(xmm, m->xmm[r], sizeof(xmm)); changed = memcmp(xmm, laststate.xmm[r], sizeof(xmm)) != 0; if (changed) AppendPanel(p, i, "\033[7m"); left = sprintf(buf, "XMM%-2" PRId64 "", r); AppendPanel(p, i, buf); cells = GetXmmTypeCellCount(r); panwidth = p->right - p->left; cellwidth = MIN(MAX(0, (panwidth - left) / cells - 1), (int)sizeof(buf) - 1); for (j = 0; j < cells; ++j) { AppendPanel(p, i, " "); switch (xmmtype.type[r]) { case kXmmFloat: memcpy(&f, xmm + j * sizeof(f), sizeof(f)); FormatDouble(buf, f); break; case kXmmDouble: memcpy(&d, xmm + j * sizeof(d), sizeof(d)); FormatDouble(buf, d); break; case kXmmIntegral: ival = 0; for (k = 0; k < xmmtype.size[r]; ++k) { itmp = xmm[j * xmmtype.size[r] + k] & 0xff; itmp <<= k * 8; ival |= itmp; } if (xmmdisp == kXmmHex || xmmdisp == kXmmChar) { if (xmmdisp == kXmmChar && iswalnum(ival)) { #ifdef __EMSCRIPTEN__ // wat: format specifies type 'wint_t' (aka 'int') but the // argument has type 'wint_t' (aka 'unsigned int') sprintf(buf, "%lc", (int)ival); #else sprintf(buf, "%lc", (wint_t)ival); #endif } else { sprintf(buf, "%.*x", xmmtype.size[r] * 8 / 4, (unsigned)ival); } } else { sprintf(buf, "%" PRId64, SignExtend(ival, xmmtype.size[r] * 8)); } break; default: __builtin_unreachable(); } buf[cellwidth] = '\0'; AppendPanel(p, i, buf); n = cellwidth - strlen(buf); for (k = 0; k < n; ++k) { AppendPanel(p, i, " "); } } if (changed) AppendPanel(p, i, "\033[27m"); } static void DrawSse(struct Panel *p) { i64 i, n; n = p->bottom - p->top; if (n > 0) { for (i = 0; i < MIN(16, n); ++i) { DrawXmm(p, i, i); } } } static void ScrollMemoryView(struct Panel *p, struct MemoryView *v, i64 a) { i64 i, n, w; w = DUMPWIDTH * ((u64)1 << v->zoom); n = p->bottom - p->top; i = a / w; if (!(v->start <= i && i < v->start + n)) { v->start = i - n / 4; } } static void ZoomMemoryView(struct MemoryView *v, i64 y, i64 x, int dy) { i64 a, b, i, s; s = v->start; a = v->zoom; b = MIN(MAXZOOM, MAX(0, a + dy)); i = y * DUMPWIDTH - x; s *= DUMPWIDTH * (1L << a); s += i * (1L << a) - i * (1L << b); s /= DUMPWIDTH * (1L << b); v->zoom = b; v->start = s; } static void ScrollMemoryViews(void) { ScrollMemoryView(&pan.code, &codeview, GetPc(m)); ScrollMemoryView(&pan.readdata, &readview, readaddr); ScrollMemoryView(&pan.writedata, &writeview, writeaddr); ScrollMemoryView(&pan.stack, &stackview, GetSp()); } static void ZoomMemoryViews(struct Panel *p, int y, int x, int dy) { if (p == &pan.code) { ZoomMemoryView(&codeview, y, x, dy); } else if (p == &pan.readdata) { ZoomMemoryView(&readview, y, x, dy); } else if (p == &pan.writedata) { ZoomMemoryView(&writeview, y, x, dy); } else if (p == &pan.stack) { ZoomMemoryView(&stackview, y, x, dy); } } static void DrawMemoryZoomed(struct Panel *p, struct MemoryView *view, long histart, long hiend) { bool high, changed; u8 *canvas, *chunk, *invalid; i64 a, b, c, d, n, i, j, k, size; struct ContiguousMemoryRanges ranges; a = view->start * DUMPWIDTH * ((u64)1 << view->zoom); b = (view->start + (p->bottom - p->top)) * DUMPWIDTH * ((u64)1 << view->zoom); size = (p->bottom - p->top) * DUMPWIDTH; canvas = (u8 *)calloc(1, size); invalid = (u8 *)calloc(1, size); memset(&ranges, 0, sizeof(ranges)); FindContiguousMemoryRanges(m, &ranges); for (k = i = 0; i < ranges.i; ++i) { if ((a >= ranges.p[i].a && a < ranges.p[i].b) || (b >= ranges.p[i].a && b < ranges.p[i].b) || (a < ranges.p[i].a && b >= ranges.p[i].b)) { c = MAX(a, ranges.p[i].a); d = MIN(b, ranges.p[i].b); n = ROUNDUP(d - c, (u64)1 << view->zoom); chunk = (u8 *)malloc(n); CopyFromUser(m, chunk, c, d - c); memset(chunk + (d - c), 0, n - (d - c)); for (j = 0; j < view->zoom; ++j) { Magikarp(chunk, n); n >>= 1; } j = (c - a) / ((u64)1 << view->zoom); memset(invalid + k, -1, j - k); memcpy(canvas + j, chunk, MIN(n, size - j)); k = j + MIN(n, size - j); free(chunk); } } memset(invalid + k, -1, size - k); free(ranges.p); high = false; for (c = i = 0; i < p->bottom - p->top; ++i) { AppendFmt(&p->lines[i], "%0*" PRIx64 " ", GetAddrHexWidth(), ((view->start + i) * DUMPWIDTH * ((u64)1 << view->zoom)) & 0x0000ffffffffffff); for (j = 0; j < DUMPWIDTH; ++j, ++c) { a = ((view->start + i) * DUMPWIDTH + j + 0) * ((u64)1 << view->zoom); b = ((view->start + i) * DUMPWIDTH + j + 1) * ((u64)1 << view->zoom); changed = ((histart >= a && hiend < b) || (histart && hiend && histart >= a && hiend < b)); if (changed && !high) { high = true; AppendStr(&p->lines[i], "\033[7m"); } else if (!changed && high) { AppendStr(&p->lines[i], "\033[27m"); high = false; } if (invalid[c]) { AppendWide(&p->lines[i], L'⋅'); } else { AppendWide(&p->lines[i], kCp437[canvas[c]]); } } if (high) { AppendStr(&p->lines[i], "\033[27m"); high = false; } } free(invalid); free(canvas); } static void DrawMemoryUnzoomed(struct Panel *p, struct MemoryView *view, i64 histart, i64 hiend) { int c, s, x, sc; i64 i, j, k; bool high, changed; high = false; for (i = 0; i < p->bottom - p->top; ++i) { AppendFmt(&p->lines[i], "%0*" PRIx64 " ", GetAddrHexWidth(), ((view->start + i) * DUMPWIDTH) & 0xffffffffffff); for (j = 0; j < DUMPWIDTH; ++j) { k = (view->start + i) * DUMPWIDTH + j; c = VirtualBing(k); s = VirtualShadow(k); if (s != -1) { if (s == -2) { /* grey for shadow memory */ x = 235; } else { sc = (signed char)s; if (sc > 7) { x = 129; /* PURPLE: shadow corruption */ } else if (sc == kAsanHeapFree) { x = 20; /* BLUE: heap freed */ } else if (sc == kAsanRelocated) { x = 16; /* BLACK: heap relocated */ } else if (sc == kAsanHeapUnderrun || sc == kAsanAllocaUnderrun) { x = 53; /* RED+PURPLETINGE: heap underrun */ } else if (sc == kAsanHeapOverrun || sc == kAsanAllocaOverrun) { x = 52; /* RED: heap overrun */ } else if (sc < 0) { x = 52; /* RED: uncategorized invalid */ } else if (sc > 0 && (k & 7) >= sc) { x = 88; /* BRIGHTRED: invalid address (skew) */ } else if (!sc || (sc > 0 && (k & 7) < sc)) { x = 22; /* GREEN: valid address */ } else { Abort(); } } AppendFmt(&p->lines[i], "\033[38;5;253;48;5;%dm", x); } changed = histart <= k && k < hiend; if (changed && !high) { high = true; AppendStr(&p->lines[i], "\033[7m"); } else if (!changed && high) { AppendStr(&p->lines[i], "\033[27m"); high = false; } AppendWide(&p->lines[i], c); if (s != -1) { AppendStr(&p->lines[i], "\033[39;49m"); } } if (high) { AppendStr(&p->lines[i], "\033[27m"); high = false; } } } static void DrawMemory(struct Panel *p, struct MemoryView *view, i64 histart, i64 hiend) { if (p->top == p->bottom) return; if (view->zoom) { DrawMemoryZoomed(p, view, histart, hiend); } else { DrawMemoryUnzoomed(p, view, histart, hiend); } } static void DrawMaps(struct Panel *p) { int i; char *p1, *p2; if (p->top == p->bottom) return; p1 = FormatPml4t(m); for (i = 0; p1; ++i, p1 = p2) { if ((p2 = strchr(p1, '\n'))) *p2++ = '\0'; if (i >= mapsstart) { AppendPanel(p, i - mapsstart, p1); } } } static void DrawBreakpoints(struct Panel *p) { i64 addr; const char *name; char *s, buf[256]; i64 i, sym, line = 0; if (p->top == p->bottom) return; for (i = watchpoints.i; i--;) { if (watchpoints.p[i].disable) continue; if (line >= breakpointsstart) { addr = watchpoints.p[i].addr; sym = DisFindSym(dis, addr); if (!(name = watchpoints.p[i].symbol)) { name = sym != -1 ? dis->syms.p[sym].name : "UNKNOWN"; } snprintf(buf, sizeof(buf), "%0*" PRIx64 " %s", GetAddrHexWidth(), addr, name); AppendPanel(p, line - breakpointsstart, buf); if (sym != -1 && addr != dis->syms.p[sym].addr) { snprintf(buf, sizeof(buf), "+%#" PRIx64, addr - dis->syms.p[sym].addr); AppendPanel(p, line - breakpointsstart, buf); } snprintf(buf, sizeof(buf), " [%#" PRIx64 "]", watchpoints.p[i].oldvalue); AppendPanel(p, line - breakpointsstart, buf); } ++line; } for (i = breakpoints.i; i--;) { if (breakpoints.p[i].disable) continue; if (line >= breakpointsstart) { addr = breakpoints.p[i].addr; sym = DisFindSym(dis, addr); if (!(name = breakpoints.p[i].symbol)) { name = sym != -1 ? dis->syms.p[sym].name : "UNKNOWN"; } if (addr == m->ip) AppendPanel(p, line - breakpointsstart, "\033[7m"); s = buf; s += sprintf(s, "%0*" PRIx64 " ", GetAddrHexWidth(), addr); strcpy(s, name); AppendPanel(p, line - breakpointsstart, buf); if (sym != -1 && addr != dis->syms.p[sym].addr) { snprintf(buf, sizeof(buf), "+%#" PRIx64, addr - dis->syms.p[sym].addr); AppendPanel(p, line - breakpointsstart, buf); } if (addr == m->ip) AppendPanel(p, line - breakpointsstart, "\033[27m"); } ++line; } } static int GetPreferredStackAlignmentMask(void) { switch (m->mode.omode) { case XED_MODE_LONG: return 15; case XED_MODE_LEGACY: return 3; case XED_MODE_REAL: return 3; default: __builtin_unreachable(); } } static void DrawFrames(struct Panel *p) { int i; i64 sym; u8 *r; const char *name; char *s, line[256]; i64 sp, bp, rp; if (p->top == p->bottom) return; rp = m->ip; bp = Read64(m->bp); sp = Read64(m->sp); for (i = 0; i < p->bottom - p->top;) { sym = DisFindSym(dis, rp); name = sym != -1 ? dis->syms.p[sym].name : "UNKNOWN"; s = line; s += sprintf(s, "%0*" PRIx64 " %0*" PRIx64 " ", GetAddrHexWidth(), m->ss.base + bp, GetAddrHexWidth(), rp); s = Demangle(s, name, DIS_MAX_SYMBOL_LENGTH); AppendPanel(p, i - framesstart, line); if (sym != -1 && rp != dis->syms.p[sym].addr) { snprintf(line, sizeof(line), "+%#" PRIx64 "", rp - dis->syms.p[sym].addr); AppendPanel(p, i - framesstart, line); } if (!bp) break; if (bp < sp) { AppendPanel(p, i - framesstart, " [STRAY]"); } else if (bp - sp <= 0x1000) { snprintf(line, sizeof(line), " %" PRId64 " bytes", bp - sp); AppendPanel(p, i - framesstart, line); } if (bp & GetPreferredStackAlignmentMask() && i) { AppendPanel(p, i - framesstart, " [MISALIGN]"); } ++i; if (((m->ss.base + bp) & 0xfff) > 0xff0) break; if (!(r = SpyAddress(m, m->ss.base + bp))) { AppendPanel(p, i - framesstart, "CORRUPT FRAME POINTER"); break; } sp = bp; bp = ReadWordSafely(m->mode.omode, r + 0); rp = ReadWordSafely(m->mode.omode, r + 8); } } static void CheckFramePointerImpl(void) { u8 *r; i64 bp, rp; static i64 lastbp; bp = Read64(m->bp); if (bp && bp == lastbp) return; lastbp = bp; rp = m->ip; while (bp) { if (!(r = SpyAddress(m, m->ss.base + bp))) { LOGF("corrupt frame: %0*" PRIx64 "", GetAddrHexWidth(), bp); ThrowProtectionFault(m); } bp = Read64(r + 0) - 0; rp = Read64(r + 8) - 1; if (!bp && !(m->bofram[0] <= rp && rp <= m->bofram[1])) { LOGF("bad frame !(%0*" PRIx64 " <= %0*" PRIx64 " <= %0*" PRIx64 ")", GetAddrHexWidth(), m->bofram[0], GetAddrHexWidth(), rp, GetAddrHexWidth(), m->bofram[1]); ThrowProtectionFault(m); } } } static void CheckFramePointer(void) { if (m->bofram[0]) { CheckFramePointerImpl(); } } static bool IsExecuting(void) { return (action & (CONTINUE | STEP | NEXT | FINISH)) && !(action & MODAL); } static int AppendStat(struct Buffer *b, int width, const char *name, i64 value, bool changed) { char valbuf[27]; AppendChar(b, ' '); if (changed) AppendStr(b, "\033[31m"); FormatInt64Thousands(valbuf, value); width = AppendFmt(b, "%*s %s", width, valbuf, name); if (changed) AppendStr(b, "\033[39m"); return 1 + width; } static const char *DescribeAction(void) { static char buf[128]; char *p = buf; buf[0] = 0; if (action & RESTART) p = stpcpy(buf, "|RESTART"); if (action & REDRAW) p = stpcpy(p, "|REDRAW"); if (action & CONTINUE) p = stpcpy(p, "|CONTINUE"); if (action & STEP) p = stpcpy(p, "|STEP"); if (action & NEXT) p = stpcpy(p, "|NEXT"); if (action & FINISH) p = stpcpy(p, "|FINISH"); if (action & MODAL) p = stpcpy(p, "|MODAL"); if (action & WINCHED) p = stpcpy(p, "|WINCHED"); if (action & INT) p = stpcpy(p, "|INT"); if (action & QUIT) p = stpcpy(p, "|QUIT"); if (action & EXIT) p = stpcpy(p, "|EXIT"); if (action & ALARM) p = stpcpy(p, "|ALARM"); return buf + !!buf[0]; } static char *GetStatus(int m) { bool once; unsigned i, n; struct timespec now; struct Buffer s = {0}; if (statusmessage && CompareTime(GetTime(), statusexpires)) { AppendStr(&s, statusmessage); } else { AppendStr(&s, "das blinkenlights"); } n = ARRAYLEN(keystrokes.p); for (once = false, now = GetTime(), i = 1; i <= n; --i) { if (!keystrokes.p[(keystrokes.i - i) % n][0] || CompareTime(SubtractTime(now, keystrokes.s[(keystrokes.i - i) % n]), FromSeconds(1)) > 0) { break; } if (!once) { AppendStr(&s, " (keystroke: "); once = true; } else { AppendChar(&s, ' '); } AppendStr(&s, keystrokes.p[(keystrokes.i - i) % n]); } if (once) { AppendChar(&s, ')'); } return s.p; } static void DrawStatus(struct Panel *p) { #define MEMSTAT(f) m->system->memstat.f, m->system->memstat.f != lastmemstat.f char *status; struct Buffer *s; int yn, xn, rw, fds; rw = 0; yn = p->top - p->bottom; xn = p->right - p->left; if (!yn || !xn) return; fds = CountFds(&m->system->fds); s = (struct Buffer *)malloc(sizeof(*s)); memset(s, 0, sizeof(*s)); rw += AppendStr(s, DescribeAction()); rw += AppendStat(s, 12, "ips", ips, false); rw += AppendChar(s, ' '); rw += AppendStat(s, 1, "fds", fds, fds != lastfds); rw += AppendChar(s, ' '); rw += AppendStat(s, 1, "rss", m->system->rss, m->system->rss != lastrss); rw += AppendChar(s, ' '); rw += AppendStat(s, 1, "vss", m->system->vss, m->system->vss != lastvss); rw += AppendChar(s, ' '); if (FLAG_nolinear) { rw += AppendStat(s, 1, "reserve", MEMSTAT(reserved)); rw += AppendChar(s, ' '); rw += AppendStat(s, 1, "commit", MEMSTAT(committed)); rw += AppendChar(s, ' '); } rw += AppendStat(s, 1, "tables", MEMSTAT(tables)); status = GetStatus(xn - rw); AppendFmt(&p->lines[0], "\033[7m%-*s%s\033[0m", xn - rw, status, s->p); free(status); free(s->p); free(s); lastmemstat = m->system->memstat; lastvss = m->system->vss; lastrss = m->system->rss; lastfds = fds; #undef MEMSTAT } bool PreventBufferbloat(void) { bool should_write; struct timespec time, rate; static struct timespec last; time = GetTime(); rate = FromMicroseconds(1. / FPS * 1e6); if (CompareTime(SubtractTime(time, last), rate) >= 0) { should_write = true; last = time; } else if (TURBO) { should_write = false; } else { SleepTime(SubtractTime(rate, SubtractTime(time, last))); should_write = true; last = time; } return should_write; } static void ClearHistory(void) { unsigned i; for (i = 0; i < HISTORY; ++i) { if (g_history.p[i].data) { free(g_history.p[i].data); g_history.p[i].data = 0; } } g_history.viewing = 0; g_history.count = 0; } static void AddHistory(const char *ansi, size_t size) { struct Rendering *r; unassert(g_history.count <= HISTORY); if (g_history.count && g_history.p[(g_history.index - 1) % HISTORY].cycle == cycle) { return; // execution hasn't advanced yet } if (g_history.count < HISTORY) { ++g_history.count; } r = g_history.p + g_history.index % HISTORY; free(r->data); r->cycle = cycle; r->origsize = size; r->data = Deflate(ansi, size, &r->compsize); ++g_history.index; STATISTIC(AVERAGE(redraw_compressed_bytes, r->compsize)); STATISTIC(AVERAGE(redraw_uncompressed_bytes, r->origsize)); } static void RewindHistory(int delta) { int count = g_history.count; int viewing = g_history.viewing; g_history.viewing = MAX(0, MIN(viewing + delta, count)); // skip over the first history entry, since it doesn't feel right to // need to press up arrow twice to see some real history. if (g_history.viewing == 1) { if (delta > 0) { g_history.viewing = 2; } else if (delta < 0) { g_history.viewing = 0; } } g_history.viewing = MIN(g_history.viewing, g_history.count); // clear the crash dialog box if it exists. action &= ~MODAL; } // we need to handle any shutdown via pipeline explicitly // because blink always puts SIGPIPE in the SIG_IGN state static ssize_t HandleEpipe(ssize_t rc) { if (rc == -1 && errno == EPIPE) { LOGF("got EPIPE, shutting down"); exit(EXIT_FAILURE_WITH_SIGNAL(EPIPE)); } return rc; } static void ShowHistory(void) { char *ansi; size_t len, size; char status[1024]; struct Rendering *r; unassert(g_history.viewing > 0); unassert(g_history.viewing <= HISTORY); unassert(g_history.viewing <= g_history.count); r = g_history.p + (g_history.index - g_history.viewing) % HISTORY; unassert(r->data); len = snprintf(status, sizeof(status), "\033[7;35;47m\033[%d;0H" " [ HISTORY %d/%d CYCLE %" PRIu64 " ] " "\033[0m\033[%d;%dH", tyn, g_history.count - (g_history.viewing - 1), g_history.count, r->cycle, tyn, txn); unassert(len < sizeof(status)); size = r->origsize + len; unassert(ansi = (char *)malloc(size)); Inflate(ansi, r->origsize, r->data, r->compsize); memcpy(ansi + r->origsize, status, len); if (PreventBufferbloat()) { HandleEpipe(UninterruptibleWrite(ttyout, ansi, size)); } free(ansi); } void Redraw(bool force) { int i, j; char *ansi; size_t size; double execsecs; struct timespec start_draw, end_draw; if (displayexec) return; if (g_history.viewing) { ShowHistory(); return; } LookupAddress(m, m->ip); // want page fault LookupAddress(m, Get64(m->sp)); // want page fault BEGIN_NO_PAGE_FAULTS; start_draw = GetTime(); execsecs = ToNanoseconds(SubtractTime(start_draw, last_draw)) * 1e-9; ips = last_cycle ? (cycle - last_cycle) / execsecs : 0; SetupDraw(); ScrollOp(&pan.disassembly, GetDisIndex()); for (i = 0; i < ARRAYLEN(pan.p); ++i) { for (j = 0; j < pan.p[i].bottom - pan.p[i].top; ++j) { pan.p[i].lines[j].i = 0; } } DrawDisassembly(&pan.disassembly); DrawDisplay(&pan.display); DrawCpu(&pan.registers); DrawSse(&pan.sse); DrawHr(&pan.breakpointshr, "BREAKPOINTS"); DrawHr(&pan.mapshr, "PML4T"); if (showprofile) { DrawHr(&pan.frameshr, "PROFILE"); } else if (m->bofram[0]) { DrawHr(&pan.frameshr, "PROTECTED FRAMES"); } else { DrawHr(&pan.frameshr, "FRAMES"); } DrawHr(&pan.ssehr, "SSE"); DrawHr(&pan.codehr, "CODE"); DrawHr(&pan.readhr, "READ"); DrawHr(&pan.writehr, "WRITE"); DrawHr(&pan.stackhr, "STACK"); DrawMaps(&pan.maps); if (showprofile) { DrawProfile(&pan.frames); } else { DrawFrames(&pan.frames); } DrawBreakpoints(&pan.breakpoints); DrawMemory(&pan.code, &codeview, GetPc(m), GetPc(m) + m->xedd->length); DrawMemory(&pan.readdata, &readview, readaddr, readaddr + readsize); DrawMemory(&pan.writedata, &writeview, writeaddr, writeaddr + writesize); DrawMemory(&pan.stack, &stackview, GetSp(), GetSp() + GetPointerWidth()); DrawStatus(&pan.status); unassert(ansi = RenderPanels(ARRAYLEN(pan.p), pan.p, tyn, txn, &size)); END_NO_PAGE_FAULTS; end_draw = GetTime(); (void)end_draw; STATISTIC(AVERAGE(redraw_latency_us, ToMicroseconds(SubtractTime(end_draw, start_draw)))); if (force || PreventBufferbloat()) { HandleEpipe(UninterruptibleWrite(ttyout, ansi, size)); } AddHistory(ansi, size); free(ansi); last_cycle = cycle; last_draw = GetTime(); } void ReactiveDraw(void) { if (tuimode) { // LOGF("%" PRIx64 " %s ReactiveDraw", GetPc(m), tuimode ? "TUI" : "EXEC"); Redraw(true); tick = speed; } } static void DescribeKeystroke(char *b, const char *p) { int c; do { c = *p++ & 255; if (c == '\033') { b = stpcpy(b, "ALT-"); c = *p++ & 255; } if (c <= 32) { b = stpcpy(b, "CTRL-"); c = Ctrl(c); } *b++ = c; *b = 0; } while (*p); } static void SetStatusDeadline(void) { struct itimerval it; statusexpires = AddTime(GetTime(), FromSeconds(1)); it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; it.it_value.tv_sec = 1; it.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &it, 0); } static void RecordKeystroke(const char *k) { if (!strchr(k, '[')) { keystrokes.s[keystrokes.i] = GetTime(); DescribeKeystroke(keystrokes.p[keystrokes.i], k); keystrokes.i = (keystrokes.i + 1) % ARRAYLEN(keystrokes.p); ReactiveDraw(); SetStatusDeadline(); } } static void HandleAlarm(void) { alarmed = false; action &= ~ALARM; pty->conf &= ~kPtyBell; free(statusmessage); statusmessage = NULL; } static void HandleTerminalResize(void) { GetTtySize(ttyout); ClearHistory(); dis->ops.i = 0; } void HandleAppReadInterrupt(bool errflag) { LOGF("HandleAppReadInterrupt"); if (errflag) { exitcode = 0; action |= EXIT; } if (action & ALARM) { HandleAlarm(); } if (action & WINCHED) { HandleTerminalResize(); action &= ~WINCHED; } if (action & INT) { action &= ~INT; RecordKeystroke("\3"); ReactiveDraw(); if (action & CONTINUE) { action &= ~CONTINUE; } else { tuimode = true; displayexec = false; } } } static int OnPtyFdClose(int fd) { return VfsClose(fd); } static bool HasPendingInput(int fd) { struct pollfd fds[1]; fds[0].fd = fd; fds[0].events = POLLIN; fds[0].revents = 0; VfsPoll(fds, ARRAYLEN(fds), 0); return fds[0].revents & (POLLIN | POLLERR); } static struct Panel *LocatePanel(int y, int x) { int i; for (i = 0; i < ARRAYLEN(pan.p); ++i) { if ((pan.p[i].left <= x && x < pan.p[i].right) && (pan.p[i].top <= y && y < pan.p[i].bottom)) { return &pan.p[i]; } } return 0; } static struct Mouse ParseMouse(char *p) { int e, x, y; struct Mouse m; e = strtol(p, &p, 10); if (*p == ';') ++p; x = strtol(p, &p, 10); x = MIN(txn, MAX(1, x)) - 1; if (*p == ';') ++p; y = strtol(p, &p, 10); y = MIN(tyn, MAX(1, y)) - 1; e |= (*p == 'm') << 2; m.y = y; m.x = x; m.e = e; return m; } ssize_t ReadAnsi(int fd, char *p, size_t n) { ssize_t rc; struct Mouse mo; for (;;) { LOGF("%" PRIx64 " %s ReadAnsi", GetPc(m), tuimode ? "TUI" : "EXEC"); readingteletype = true; ReactiveDraw(); rc = readansi(fd, p, n); readingteletype = false; if (rc != -1) { if (tuimode && rc > 3 && p[0] == '\033' && p[1] == '[') { if (p[2] == '2' && p[3] == '0' && p[4] == '0' && p[5] == '~') { belay = true; continue; } if (p[2] == '2' && p[3] == '0' && p[4] == '1' && p[5] == '~') { belay = false; continue; } if (p[2] == '<') { mo = ParseMouse(p + 3); if (LocatePanel(mo.y, mo.x) != &pan.display) { HandleKeyboard(p); continue; } } } return rc; } else { unassert(errno == EINTR); HandleAppReadInterrupt(false); return eintr(); } } } static ssize_t ReadPtyFdDirect(int fd) { ssize_t rc; char buf[32]; LOGF("ReadPtyFdDirect"); pty->conf |= kPtyBlinkcursor; do { rc = ReadAnsi(fd, buf, sizeof(buf)); } while (rc == -1 && errno == EINTR); pty->conf &= ~kPtyBlinkcursor; if (rc > 0) { PtyWriteInput(pty, buf, rc); ReactiveDraw(); rc = 0; } return rc; } static ssize_t OnPtyFdReadv(int fd, const struct iovec *iov, int iovlen) { int i; ssize_t rc; void *data; size_t size; ptyisenabled = true; for (size = i = 0; i < iovlen; ++i) { if (iov[i].iov_len) { data = iov[i].iov_base; size = iov[i].iov_len; break; } } if (size) { for (;;) { if ((rc = PtyRead(pty, data, size))) { return rc; } if (ReadPtyFdDirect(fd) == -1) { return -1; } } } else { return 0; } } static int OnPtyFdPoll(struct pollfd *fds, nfds_t nfds, int ms) { nfds_t i; int t, re; bool once; struct pollfd p2; ms &= INT_MAX; ptyisenabled = true; for (once = false, t = i = 0; i < nfds; ++i) { re = 0; if (fds[i].fd >= 0) { if (pty->input.i) { re = POLLIN | POLLOUT; ++t; } else { if (!once) { ReactiveDraw(); once = true; } p2.fd = fds[i].fd; p2.events = fds[i].events; switch (VfsPoll(&p2, 1, ms)) { case -1: re = POLLERR; ++t; break; case 0: break; case 1: re = p2.revents; ++t; break; default: __builtin_unreachable(); } } } fds[i].revents = re; } return t; } void DrawDisplayOnly(void) { struct Panel *p; int i, y, yn, xn, tly, tlx; struct Buffer b; char buf[64]; p = &pan.display; yn = MIN(tyn, p->bottom - p->top); xn = MIN(txn, p->right - p->left); for (i = 0; i < yn; ++i) { p->lines[i].i = 0; } DrawDisplay(p); memset(&b, 0, sizeof(b)); if (displayexec) { tly = tyn / 2 - yn / 2; tlx = txn / 2 - xn / 2; } else { tly = p->top; tlx = p->left; } AppendStr(&b, "\033[0m\033[H"); for (y = 0; y < tyn; ++y) { if (displayexec && y) AppendStr(&b, "\r\n"); if (tly <= y && y < tly + yn) { if (!displayexec) { sprintf(buf, "\033[%d;%dH", y + 1, tlx + 1); AppendStr(&b, buf); } else { for (i = 0; i < tlx; ++i) { AppendChar(&b, ' '); } } // FIXME truncate on right side, should use RenderPanel AppendData(&b, p->lines[y - tly].p, p->lines[y - tly].i); } AppendStr(&b, "\033[0m"); if (displayexec) AppendStr(&b, "\033[K"); } UninterruptibleWrite(ttyout, b.p, b.i); free(b.p); } static ssize_t OnPtyFdWritev(int fd, const struct iovec *iov, int iovlen) { int i; size_t size; if (!ptyisenabled) { ptyisenabled = true; ReactiveDraw(); } for (size = i = 0; i < iovlen; ++i) { PtyWrite(pty, iov[i].iov_base, iov[i].iov_len); size += iov[i].iov_len; } return size; } static int OnPtyFdTiocgwinsz(int fd, struct winsize *ws) { ws->ws_row = pty->yn; ws->ws_col = pty->xn; return 0; } static int OnPtyFdTiocswinsz(int fd, const struct winsize *ws) { return 0; } static int OnPtyFdTcsets(int fd, u64 request, struct termios *c) { return 0; } static int OnPtyTcgetattr(int fd, struct termios *c) { // TODO(jart): We should just use the Linux ABI for these. memset(c, 0, sizeof(*c)); c->c_iflag = ICRNL | IXON #ifdef IUTF8 | IUTF8 #endif ; c->c_oflag = 0 #ifdef ONLCR | ONLCR #endif ; c->c_cflag = CREAD | CS8; c->c_lflag = ISIG | ECHOE | IEXTEN | ECHOK #ifdef ECHOCTL | ECHOCTL #endif #ifdef ECHOKE | ECHOKE #endif ; c->c_cc[VMIN] = 1; c->c_cc[VTIME] = 0; c->c_cc[VINTR] = Ctrl('C'); c->c_cc[VQUIT] = Ctrl('\\'); c->c_cc[VERASE] = Ctrl('?'); c->c_cc[VKILL] = Ctrl('U'); c->c_cc[VEOF] = Ctrl('D'); c->c_cc[VSTART] = Ctrl('Q'); c->c_cc[VSTOP] = Ctrl('S'); c->c_cc[VSUSP] = Ctrl('Z'); c->c_cc[VEOL] = Ctrl('@'); #ifdef VSWTC c->c_cc[VSWTC] = Ctrl('@'); #endif #ifdef VREPRINT c->c_cc[VREPRINT] = Ctrl('R'); #endif #ifdef VDISCARD c->c_cc[VDISCARD] = Ctrl('O'); #endif #ifdef VWERASE c->c_cc[VWERASE] = Ctrl('W'); #endif #ifdef VLNEXT c->c_cc[VLNEXT] = Ctrl('V'); #endif #ifdef VEOL2 c->c_cc[VEOL2] = Ctrl('@'); #endif if (!(pty->conf & kPtyNocanon)) c->c_iflag |= ICANON; if (!(pty->conf & kPtyNoecho)) c->c_iflag |= ECHO; if (!(pty->conf & kPtyNoopost)) c->c_oflag |= OPOST; return 0; } static int OnPtyTcsetattr(int fd, int cmd, const struct termios *c) { if (c->c_iflag & ICANON) { pty->conf &= ~kPtyNocanon; } else { pty->conf |= kPtyNocanon; } if (c->c_iflag & ECHO) { pty->conf &= ~kPtyNoecho; } else { pty->conf |= kPtyNoecho; } if (c->c_oflag & OPOST) { pty->conf &= ~kPtyNoopost; } else { pty->conf |= kPtyNoopost; } return 0; } static const struct FdCb kFdCbPty = { .close = OnPtyFdClose, .readv = OnPtyFdReadv, .writev = OnPtyFdWritev, .poll = OnPtyFdPoll, .tcgetattr = OnPtyTcgetattr, .tcsetattr = OnPtyTcsetattr, .tcgetwinsize = OnPtyFdTiocgwinsz, .tcsetwinsize = OnPtyFdTiocswinsz, }; static void LaunchDebuggerReactively(void) { LOGF("LaunchDebuggerReactively"); LOGF("%s", systemfailure); action &= ~CONTINUE; if (tuimode) { action |= MODAL; } else { if (react) { tuimode = true; action |= MODAL; } else { fprintf(stderr, "ERROR: %s\n", systemfailure); exit(EXIT_FAILURE); } } } static void OnDebug(void) { strcpy(systemfailure, "IT'S A TRAP"); LaunchDebuggerReactively(); } static void OnExitTrap(void) { tuimode = true; action |= MODAL; action &= ~CONTINUE; exitcode = m->system->exitcode; snprintf(systemfailure, sizeof(systemfailure), "guest called exit_group(%d)", exitcode); } static void OnSegmentationFault(void) { snprintf(systemfailure, sizeof(systemfailure), "SEGMENTATION FAULT %0*" PRIx64, GetAddrHexWidth(), m->faultaddr); LaunchDebuggerReactively(); } static void OnProtectionFault(void) { strcpy(systemfailure, "PROTECTION FAULT"); LaunchDebuggerReactively(); } static void OnSimdException(void) { strcpy(systemfailure, "SIMD FAULT"); LaunchDebuggerReactively(); } static void OnUndefinedInstruction(void) { strcpy(systemfailure, "UNDEFINED INSTRUCTION"); LaunchDebuggerReactively(); } static void OnDecodeError(void) { stpcpy(systemfailure, "INSTRUCTION DECODE ERROR"); LaunchDebuggerReactively(); } static void OnDivideError(void) { strcpy(systemfailure, "DIVIDE BY ZERO OR BANE"); LaunchDebuggerReactively(); } static void OnFpuException(void) { strcpy(systemfailure, "FPU EXCEPTION"); LaunchDebuggerReactively(); } static void OnExit(int rc) { if (tuimode) { action |= MODAL; action &= ~CONTINUE; } else { action |= EXIT; } exitcode = rc; if (rc == kMachineHalt) { strcpy(systemfailure, "SYSTEM HALTED"); } else { snprintf(systemfailure, sizeof(systemfailure), "UNHANDLED INTERRUPT %#x", rc); } } bool HasPendingKeyboard(void) { return HasPendingInput(ttyin); } static bool OnHalt(int interrupt) { SYS_LOGF("%" PRIx64 " %s OnHalt(%#x)", GetPc(m), tuimode ? "TUI" : "EXEC", interrupt); if (interrupt >= 0) m->oplen = 0; ReactiveDraw(); if (OnCallBios(interrupt)) { return true; } switch (interrupt) { case 1: case 3: OnDebug(); return false; case kMachineEscape: return true; case kMachineSegmentationFault: OnSegmentationFault(); return true; case kMachineProtectionFault: OnProtectionFault(); return true; case kMachineSimdException: OnSimdException(); return true; case kMachineUndefinedInstruction: OnUndefinedInstruction(); return true; case kMachineDecodeError: OnDecodeError(); return true; case 0: case kMachineDivideError: OnDivideError(); return true; case kMachineFpuException: OnFpuException(); return true; case kMachineExitTrap: OnExitTrap(); return true; case kMachineHalt: default: OnExit(interrupt); return false; } } static void OnBinbase(struct Machine *m) { int i; i64 skew; skew = m->xedd->op.disp * 512; LOGF("skew binbase %" PRId64 " @ %0*" PRIx64 "", skew, GetAddrHexWidth(), GetPc(m)); for (i = 0; i < dis->syms.i; ++i) dis->syms.p[i].addr += skew; for (i = 0; i < dis->loads.i; ++i) dis->loads.p[i].addr += skew; for (i = 0; i < breakpoints.i; ++i) breakpoints.p[i].addr += skew; Disassemble(); } static void OnLongBranch(struct Machine *m) { if (tuimode) { Disassemble(); } } #ifndef DISABLE_ROM static void OnRomWriteAttempt(struct Machine *m, u8 *r) { int w = GetAddrHexWidth(); (void)w; LOGF("attempt to write to rom address %0*tx @ %0*" PRIx64, w, r - m->system->real, w, GetPc(m)); } #endif static void SetStatus(const char *fmt, ...) { char *s; va_list va; va_start(va, fmt); unassert(vasprintf(&s, fmt, va) >= 0); va_end(va); free(statusmessage); statusmessage = s; SetStatusDeadline(); } static int ClampSpeed(int s) { return MAX(-0x1000, MIN(0x40000000, s)); } static void OnTurbo(void) { if (!speed || speed == -1) { speed = 1; } else if (speed > 0) { speed = ClampSpeed(speed << 1); } else { speed = ClampSpeed(speed >> 1); } SetStatus("speed %d", speed); } static void OnSlowmo(void) { if (!speed || speed == 1) { speed = -1; } else if (speed > 0) { speed = ClampSpeed(speed >> 1); } else { speed = ClampSpeed(speed << 1); } SetStatus("speed %d", speed); } static void OnUpArrow(void) { RewindHistory(+1); } static void OnDownArrow(void) { RewindHistory(-1); } static void OnPageUp(void) { RewindHistory(+100); } static void OnPageDown(void) { RewindHistory(-100); } static void OnHome(void) { RewindHistory(+g_history.count); } static void OnEnd(void) { RewindHistory(-g_history.count); } static void OnEnter(void) { dialog = NULL; action &= ~MODAL; m->faultaddr = 0; } static void OnUp(void) { } static void OnDown(void) { } static void OnStep(void) { if (action & MODAL) return; action |= STEP; action &= ~NEXT; action &= ~FINISH; action &= ~CONTINUE; } static void OnNext(void) { if (action & MODAL) return; action ^= NEXT; action &= ~STEP; action &= ~FINISH; action &= ~CONTINUE; } static void OnFinish(void) { if (action & MODAL) return; action ^= FINISH; action &= ~NEXT; action &= ~MODAL; action &= ~CONTINUE; } static void OnContinueTui(void) { action ^= CONTINUE; action &= ~STEP; action &= ~NEXT; action &= ~FINISH; action &= ~MODAL; } static void OnContinueExec(void) { tuimode = false; action |= CONTINUE; action &= ~STEP; action &= ~NEXT; action &= ~FINISH; action &= ~MODAL; } static void OnInt(void) { action |= INT; } static void OnRestart(void) { action |= RESTART; } static void OnXmmType(void) { u8 t; unsigned i; t = CycleXmmType(xmmtype.type[0]); for (i = 0; i < 16; ++i) { xmmtype.type[i] = t; } } static void SetXmmSize(int bytes) { unsigned i; for (i = 0; i < 16; ++i) { xmmtype.size[i] = bytes; } } static void SetXmmDisp(int disp) { xmmdisp = disp; } static void OnXmmSize(void) { SetXmmSize(CycleXmmSize(xmmtype.size[0])); } static void OnXmmDisp(void) { SetXmmDisp(CycleXmmDisp(xmmdisp)); } static void Sleep(int ms) { VfsPoll((struct pollfd[]){{ttyin, POLLIN}}, 1, ms); } static void OnMouseWheelUp(struct Panel *p, int y, int x) { if (p == &pan.disassembly) { RewindHistory(+WHEELDELTA); } else if (p == &pan.code) { codeview.start -= WHEELDELTA; } else if (p == &pan.readdata) { readview.start -= WHEELDELTA; } else if (p == &pan.writedata) { writeview.start -= WHEELDELTA; } else if (p == &pan.stack) { stackview.start -= WHEELDELTA; } else if (p == &pan.maps) { mapsstart = MAX(0, mapsstart - 1); } else if (p == &pan.frames) { framesstart = MAX(0, framesstart - 1); } else if (p == &pan.breakpoints) { breakpointsstart = MAX(0, breakpointsstart - 1); } } static void OnMouseWheelDown(struct Panel *p, int y, int x) { if (p == &pan.disassembly) { RewindHistory(-WHEELDELTA); } else if (p == &pan.code) { codeview.start += WHEELDELTA; } else if (p == &pan.readdata) { readview.start += WHEELDELTA; } else if (p == &pan.writedata) { writeview.start += WHEELDELTA; } else if (p == &pan.stack) { stackview.start += WHEELDELTA; } else if (p == &pan.maps) { mapsstart += 1; } else if (p == &pan.frames) { framesstart += 1; } else if (p == &pan.breakpoints) { breakpointsstart += 1; } } static void OnMouseCtrlWheelUp(struct Panel *p, int y, int x) { ZoomMemoryViews(p, y, x, -1); } static void OnMouseCtrlWheelDown(struct Panel *p, int y, int x) { ZoomMemoryViews(p, y, x, +1); } static void OnMouse(const char *p) { int e, x, y; struct Panel *ep; e = strtol(p, (char **)&p, 10); if (*p == ';') ++p; x = strtol(p, (char **)&p, 10); x = MIN(txn, MAX(1, x)) - 1; if (*p == ';') ++p; y = strtol(p, (char **)&p, 10); y = MIN(tyn, MAX(1, y)) - 1; e |= (*p == 'm') << 2; if ((ep = LocatePanel(y, x))) { y -= ep->top; x -= ep->left; switch (e) { case kMouseWheelUp: if (!natural) { OnMouseWheelUp(ep, y, x); } else { OnMouseWheelDown(ep, y, x); } break; case kMouseWheelDown: if (!natural) { OnMouseWheelDown(ep, y, x); } else { OnMouseWheelUp(ep, y, x); } break; case kMouseCtrlWheelUp: if (!natural) { OnMouseCtrlWheelUp(ep, y, x); } else { OnMouseCtrlWheelDown(ep, y, x); } break; case kMouseCtrlWheelDown: if (!natural) { OnMouseCtrlWheelDown(ep, y, x); } else { OnMouseCtrlWheelUp(ep, y, x); } break; default: break; } } } static void OnHelp(void) { dialog = dialog == kHelp ? NULL : kHelp; } static void HandleKeyboard(const char *k) { const char *p = k; switch (*p++) { CASE('q', OnQ()); CASE('v', OnV()); CASE('?', OnHelp()); CASE('s', OnStep()); CASE('n', OnNext()); CASE('f', OnFinish()); CASE('c', OnContinueTui()); CASE('C', displayexec = false; OnContinueExec()); CASE('D', displayexec = true; OnContinueExec()); CASE('R', OnRestart()); CASE('x', OnXmmDisp()); CASE('t', OnXmmType()); CASE('T', OnXmmSize()); CASE('u', OnUp()); CASE('d', OnDown()); CASE('V', ++verbose); CASE('p', showprofile = !showprofile); CASE('b', BreakAtCurrentInstruction()); CASE('B', PopBreakpoint(&breakpoints)); CASE('M', ToggleMouseTracking()); CASE('\r', OnEnter()); CASE('\n', OnEnter()); CASE('2', showcolumn2 = !showcolumn2); CASE('3', showcolumn3 = !showcolumn3); CASE(Ctrl('C'), OnInt()); CASE(Ctrl('D'), action |= EXIT); CASE(Ctrl('\\'), raise(SIGQUIT)); CASE(Ctrl('Z'), raise(SIGSTOP)); CASE(Ctrl('L'), OnFeed()); CASE(Ctrl('P'), OnUpArrow()); CASE(Ctrl('N'), OnDownArrow()); CASE(Ctrl('V'), OnPageDown()); CASE(Ctrl('T'), OnTurbo()); case 033: switch (*p++) { CASE('v', OnPageUp()); /* alt+v */ CASE('t', OnSlowmo()); /* alt+t */ case 'O': switch (*p++) { CASE('P', OnHelp()); /* \033OP is F1 */ default: break; } break; case '[': switch (*p++) { CASE('<', OnMouse(p)); CASE('A', OnUpArrow()); /* \e[A is up */ CASE('B', OnDownArrow()); /* \e[B is down */ CASE('F', OnEnd()); /* \e[F is end */ CASE('H', OnHome()); /* \e[H is home */ CASE('1', OnHome()); /* \e[1~ is home */ CASE('4', OnEnd()); /* \e[1~ is end */ CASE('5', OnPageUp()); /* \e[1~ is pgup */ CASE('6', OnPageDown()); /* \e[1~ is pgdn */ default: break; } break; default: break; } break; default: break; } RecordKeystroke(k); } static void ReadKeyboard(void) { char buf[64]; memset(buf, 0, sizeof(buf)); if (readansi(ttyin, buf, sizeof(buf)) == -1) { if (errno == EINTR) { LOGF("ReadKeyboard interrupted"); return; } fprintf(stderr, "ReadKeyboard failed: %s\n", DescribeHostErrno(errno)); exit(EXIT_FAILURE); } HandleKeyboard(buf); } static i64 ParseHexValue(const char *s) { char *ep; i64 x; x = strtoll(s, &ep, 16); if (*ep) { fputs("ERROR: bad hexadecimal: ", stderr); fputs(s, stderr); fputc('\n', stderr); exit(EXIT_FAILURE); } return x; } static void HandleBreakpointFlag(const char *s) { struct Breakpoint b; memset(&b, 0, sizeof(b)); if (isdigit(*s)) { b.addr = ParseHexValue(s); } else { b.symbol = optarg_; } PushBreakpoint(&breakpoints, &b); } static void HandleWatchpointFlag(const char *s) { struct Watchpoint b; memset(&b, 0, sizeof(b)); if (isdigit(*s)) { b.addr = ParseHexValue(s); } else { b.symbol = optarg_; } PushWatchpoint(&watchpoints, &b); } _Noreturn static void PrintUsage(int rc, FILE *f) { fprintf(f, "SYNOPSIS\n\n %s%s", "blink", USAGE); exit(rc); } static void LogInstruction(void) { LOGF("EXEC %8" PRIx64 " SP %012" PRIx64 " AX %016" PRIx64 " CX %016" PRIx64 " DX %016" PRIx64 " BX %016" PRIx64 " BP %016" PRIx64 " SI %016" PRIx64 " DI %016" PRIx64 " R8 %016" PRIx64 " R9 %016" PRIx64 " R10 %016" PRIx64 " R11 %016" PRIx64 " R12 %016" PRIx64 " R13 %016" PRIx64 " R14 %016" PRIx64 " R15 %016" PRIx64 " FS %012" PRIx64 " GS %012" PRIx64, m->ip, Get64(m->sp) & 0xffffffffffff, Get64(m->ax), Get64(m->cx), Get64(m->dx), Get64(m->bx), Get64(m->bp), Get64(m->si), Get64(m->di), Get64(m->r8), Get64(m->r9), Get64(m->r10), Get64(m->r11), Get64(m->r12), Get64(m->r13), Get64(m->r14), Get64(m->r15), m->fs.base & 0xffffffffffff, m->gs.base & 0xffffffffffff); } static void EnterWatchpoint(long bp) { LOGF("WATCHPOINT %0*" PRIx64 " %s", GetAddrHexWidth(), watchpoints.p[bp].addr, watchpoints.p[bp].symbol); snprintf(systemfailure, sizeof(systemfailure), "watchpoint %" PRIx64 " triggered%s%s", watchpoints.p[bp].addr, watchpoints.p[bp].symbol ? "\n" : "", watchpoints.p[bp].symbol ? watchpoints.p[bp].symbol : ""); dialog = systemfailure; action &= ~(FINISH | NEXT | CONTINUE); action |= MODAL; tuimode = true; } static void ProfileOp(struct Machine *m, i64 pc) { if (ophits && // pc >= m->system->codestart && // pc < m->system->codestart + m->system->codesize) { ++ophits[pc - m->system->codestart]; } } static void StartOp_Tui(P) { ++cycle; ProfileOp(m, m->ip - m->oplen); } static void Execute(void) { u64 c; if (g_history.viewing) { g_history.viewing = 0; } c = cycle; ExecuteInstruction(m); if (c == cycle) { ++cycle; ProfileOp(m, GetPc(m) - m->oplen); } if (atomic_load_explicit(&m->attention, memory_order_acquire)) { CheckForSignals(m); } } static void Exec(void) { ssize_t bp; int interrupt; LOGF("Exec"); ExecSetup(); m->nofault = false; if (!(interrupt = sigsetjmp(m->onhalt, 1))) { m->canhalt = true; if (!(action & CONTINUE) && (bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) { LOGF("BREAK1 %0*" PRIx64 "", GetAddrHexWidth(), breakpoints.p[bp].addr); ReactToPoint: tuimode = true; LoadInstruction(m, GetPc(m)); if (verbose) LogInstruction(); Execute(); CheckFramePointer(); } else if (!(action & CONTINUE) && (bp = IsAtWatchpoint(&watchpoints, m)) != -1) { LOGF("WATCH1 %0*" PRIx64 " %s", GetAddrHexWidth(), watchpoints.p[bp].addr, watchpoints.p[bp].symbol); goto ReactToPoint; } else { action &= ~CONTINUE; for (;;) { LoadInstruction(m, GetPc(m)); if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) { LOGF("BREAK2 %0*" PRIx64 "", GetAddrHexWidth(), breakpoints.p[bp].addr); action &= ~(FINISH | NEXT | CONTINUE); tuimode = true; break; } if ((bp = IsAtWatchpoint(&watchpoints, m)) != -1) { EnterWatchpoint(bp); break; } if (verbose) LogInstruction(); Execute(); KeepGoing: CheckFramePointer(); if (action & ALARM) { /* TODO(jart): Fix me */ /* DrawDisplayOnly(); */ action &= ~ALARM; } if (action & EXIT) { LOGF("EXEC EXIT"); break; } if (action & INT) { LOGF("EXEC INT"); if (react) { LOGF("REACT"); action &= ~(INT | STEP | FINISH | NEXT); tuimode = true; displayexec = false; break; } else { action &= ~INT; EnqueueSignal(m, SIGINT_LINUX); } } } } } else { if (IsMakingPath(m)) { AbandonPath(m); } // if sigsetjmp fake-returned 1, the actual trap number might have been // either 1 or 0; this should have been stored in m->trapno if (interrupt == 1) interrupt = m->trapno; if (OnHalt(interrupt)) { if (!tuimode) { if (displayexec) { DrawDisplayOnly(); } goto KeepGoing; } } } m->canhalt = false; } static void Tui(void) { int sig; ssize_t bp; int interrupt; bool interactive; LOGF("Tui"); TuiSetup(); SetupDraw(); m->nofault = false; m->system->trapexit = true; ScrollOp(&pan.disassembly, GetDisIndex()); if (!(interrupt = sigsetjmp(m->onhalt, 1))) { m->canhalt = true; do { if (!(action & MODAL)) { LoadInstruction(m, GetPc(m)); if ((action & (FINISH | NEXT | CONTINUE)) && (bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) { action &= ~(FINISH | NEXT | CONTINUE); LOGF("BREAK %0*" PRIx64 "", GetAddrHexWidth(), breakpoints.p[bp].addr); ReactiveDraw(); } else if ((action & (FINISH | NEXT | CONTINUE)) && (bp = IsAtWatchpoint(&watchpoints, m)) != -1) { action &= ~(FINISH | NEXT | CONTINUE); LOGF("WATCH %0*" PRIx64 " AT PC %" PRIx64, GetAddrHexWidth(), watchpoints.p[bp].addr, GetPc(m)); ReactiveDraw(); } } else { m->xedd = (struct XedDecodedInst *)m->opcache->icache[0]; m->xedd->length = 1; m->xedd->bytes[0] = 0xCC; m->xedd->op.rde &= ~00000077760000000000000; m->xedd->op.rde &= (u64)0xCC << 40; // sets mopcode to int3 } if (action & WINCHED) { HandleTerminalResize(); action &= ~WINCHED; } interactive = ++tick >= speed; if (interactive && speed < 0) { Sleep(-speed); } if (action & ALARM) { HandleAlarm(); } if (action & MODAL) { ScrollMemoryViews(); } if (!(action & CONTINUE) || interactive) { tick = 0; Redraw(false); } if (dialog) { PrintMessageBox(ttyout, dialog, tyn, txn); } if (action & MODAL) { PrintMessageBox(ttyout, systemfailure, tyn, txn); ReadKeyboard(); } else if (dialog || !IsExecuting() || (!(action & CONTINUE) && !(action & INT) && HasPendingKeyboard())) { ReadKeyboard(); } if (action & INT) { LOGF("TUI INT"); action &= ~INT; RecordKeystroke("\3"); if (action & (CONTINUE | NEXT | FINISH)) { action &= ~(CONTINUE | NEXT | FINISH | STEP); ReactiveDraw(); } else if ((~m->sigmask & ((u64)1 << (SIGINT_LINUX - 1))) && Read64(m->system->hands[SIGINT_LINUX - 1].handler) != SIG_DFL_LINUX && Read64(m->system->hands[SIGINT_LINUX - 1].handler) != SIG_IGN_LINUX) { EnqueueSignal(m, SIGINT_LINUX); action |= STEP; } else { SetStatus("press q to quit"); } } if (action & EXIT) { LOGF("TUI EXIT"); break; } if (action & RESTART) { LOGF("TUI RESTART"); break; } if (IsExecuting()) { if (!(action & CONTINUE)) { action &= ~STEP; if (action & NEXT) { action &= ~NEXT; if (IsCall()) { BreakAtNextInstruction(); tuimode = false; break; } } if (action & FINISH) { if (IsCall()) { BreakAtNextInstruction(); tuimode = false; break; } else if (IsRet()) { action &= ~FINISH; } } } if (!IsDebugBreak() && IsAtWatchpoint(&watchpoints, m) == -1) { UpdateXmmType(m->xedd->op.rde, &xmmtype); if (verbose) LogInstruction(); CopyMachineState(&laststate); Execute(); ScrollOp(&pan.disassembly, GetDisIndex()); if (!IsShadow(m->readaddr) && !IsShadow(m->readaddr + m->readsize)) { readaddr = m->readaddr; readsize = m->readsize; } if (!IsShadow(m->writeaddr) && !IsShadow(m->writeaddr + m->writesize)) { writeaddr = m->writeaddr; writesize = m->writesize; } ScrollMemoryViews(); if (m->signals & ~m->sigmask) { if ((sig = ConsumeSignal(m, 0, 0))) { exit(EXIT_FAILURE_WITH_SIGNAL(sig)); } } if (!(action & CONTINUE) || interactive) { if (!(action & CONTINUE)) ReactiveDraw(); ScrollMemoryViews(); } } else { m->ip += m->xedd->length; action &= ~NEXT; action &= ~FINISH; action &= ~CONTINUE; } KeepGoing: CheckFramePointer(); if (!(action & CONTINUE)) { ScrollOp(&pan.disassembly, GetDisIndex()); if ((action & FINISH) && IsRet()) action &= ~FINISH; if (((action & NEXT) && IsRet()) || (action & FINISH)) { action &= ~NEXT; } } } } while (tuimode); } else { if (IsMakingPath(m)) { AbandonPath(m); } if (interrupt == 1) interrupt = m->trapno; if (OnHalt(interrupt)) { ReactiveDraw(); ScrollMemoryViews(); goto KeepGoing; } ReactiveDraw(); ScrollOp(&pan.disassembly, GetDisIndex()); } if ((action & EXIT)) { m->canhalt = false; TuiCleanup(); } } _Noreturn static void PrintVersion(void) { fputs(VERSION, stdout); exit(EXIT_SUCCESS); } static void GetOpts(int argc, char *argv[]) { int opt; bool wantunsafe = false; FLAG_nologstderr = true; #ifndef DISABLE_OVERLAYS FLAG_overlays = getenv("BLINK_OVERLAYS"); if (!FLAG_overlays) FLAG_overlays = DEFAULT_OVERLAYS; #endif #ifndef DISABLE_VFS FLAG_prefix = getenv("BLINK_PREFIX"); #endif while ((opt = GetOpt(argc, argv, "0hjmvVtrzRNsZb:Hw:L:C:B:")) != -1) { switch (opt) { case '0': FLAG_zero = true; break; case 'j': FLAG_wantjit = true; break; case 't': tuimode = false; break; case 's': ++FLAG_strace; break; case 'm': wantunsafe = true; if (!CanHaveLinearMemory()) { fprintf(stderr, "linearization not possible on this system" " (word size is %d bits and page size is %ld)\n", bsr(UINTPTR_MAX) + 1, sysconf(_SC_PAGESIZE)); exit(EXIT_FAILURE); } break; case 'R': react = false; break; case 'N': natural = true; break; case 'r': wantmetal = true; break; case 'Z': FLAG_statistics = true; break; case 'b': HandleBreakpointFlag(optarg_); break; case 'w': HandleWatchpointFlag(optarg_); break; case 'H': memset(&g_high, 0, sizeof(g_high)); break; case 'v': PrintVersion(); break; case 'V': ++verbose; break; case 'L': FLAG_logpath = optarg_; break; case 'C': #if !defined(DISABLE_OVERLAYS) FLAG_overlays = optarg_; #elif !defined(DISABLE_VFS) FLAG_prefix = optarg_; #else WriteErrorString("error: overlays support was disabled\n"); #endif break; case 'B': FLAG_bios = optarg_; break; case 'z': ++codeview.zoom; ++readview.zoom; ++writeview.zoom; ++stackview.zoom; break; case 'h': PrintUsage(0, stdout); default: PrintUsage(48, stderr); } } LogInit(FLAG_logpath); if (wantmetal) wantunsafe = false; FLAG_nolinear = !wantunsafe; } static void AddPath_StartOp_Tui(P) { Jitter(m, rde, 0, 0, "qc", StartOp_Tui); } static bool FileExists(const char *path) { return !VfsAccess(AT_FDCWD, path, F_OK, 0); } int VirtualMachine(int argc, char *argv[]) { struct Dll *e; if (FileExists(argv[optind_])) { codepath = argv[optind_]; } else if (Commandv(argv[optind_], pathbuf, sizeof(pathbuf))) { codepath = pathbuf; } else { fprintf(stderr, "%s: command not found: %s\n", argv[0], argv[optind_]); exit(EXIT_FAILURE_EXEC_FAILED); } optind_++; do { action = 0; ptyisenabled = false; vidya = m->metal ? 3 : kModePty; if (vidya != kModePty) { VidyaServiceSetMode(vidya); } LoadProgram(m, codepath, codepath, argv + optind_ - 1 + FLAG_zero, environ, FLAG_bios); if (m->system->codesize) { ophits = (unsigned long *)AllocateBig( m->system->codesize * sizeof(unsigned long), PROT_READ | PROT_WRITE, MAP_ANONYMOUS_ | MAP_PRIVATE, -1, 0); } ScrollMemoryViews(); AddStdFd(&m->system->fds, 0); AddStdFd(&m->system->fds, 1); AddStdFd(&m->system->fds, 2); if (tuimode) { int tty; if (isatty(0)) { tty = 0; } else if (isatty(1)) { tty = 1; } else { tty = VfsOpen(AT_FDCWD, "/dev/tty", O_RDWR | O_NOCTTY, 0); } if (tty != -1) { tty = VfsFcntl(tty, F_DUPFD_CLOEXEC, kMinBlinkFd); } if (tty == -1) { WriteErrorString("failed to open /dev/tty\n"); exit(EXIT_FAILURE); } ttyin = tty; ttyout = tty; } else { ttyin = -1; ttyout = -1; } if (ttyout != -1) { tyn = 24; txn = 80; GetTtySize(ttyout); for (e = dll_first(m->system->fds.list); e; e = dll_next(m->system->fds.list, e)) { if (isatty(FD_CONTAINER(e)->fildes)) { FD_CONTAINER(e)->cb = &kFdCbPty; } } } do { if (!tuimode) { Exec(); } else { Tui(); } } while (!(action & (RESTART | EXIT))); } while (action & RESTART); DisFree(dis); return exitcode; } void FreePanels(void) { int i, j; for (i = 0; i < ARRAYLEN(pan.p); ++i) { for (j = 0; j < pan.p[i].n; ++j) { free(pan.p[i].lines[j].p); } free(pan.p[i].lines); } } void TerminateSignal(struct Machine *m, int sig, int code) { if (!react) { LOGF("terminating due to signal %s code=%d", DescribeSignal(sig), code); WriteErrorString("\r\033[K\033[J" "terminating due to signal; see log\n"); exit(EXIT_FAILURE_WITH_SIGNAL(sig)); } } static void OnSigSegv(int sig, siginfo_t *si, void *uc) { struct Machine *m = g_machine; #ifdef __APPLE__ sig = FixXnuSignal(m, sig, si); #endif #ifndef DISABLE_JIT if (IsSelfModifyingCodeSegfault(m, si)) return; #endif LOGF("OnSigSegv(%p)", si->si_addr); RestoreIp(m); // TODO(jart): Fix address translation in non-linear mode. m->faultaddr = ConvertHostToGuestAddress(m->system, si->si_addr, 0); ERRF("SIGSEGV AT ADDRESS %#" PRIx64 " (OR %p) at RIP=%#" PRIx64, m->faultaddr, si->si_addr, m->ip); ERRF("BACKTRACE\n\t%s", GetBacktrace(m)); if (!react) { sig = UnXlatSignal(si->si_signo); DeliverSignalToUser(m, sig, UnXlatSiCode(sig, si->si_code)); } siglongjmp(m->onhalt, kMachineSegmentationFault); } int main(int argc, char *argv[]) { int rc; struct System *s; static struct sigaction sa; setlocale(LC_ALL, ""); SetupWeb(); GetStartDir(); AtAbort(PrintStats); #ifndef NDEBUG AtAbort(PrintStats); #endif // Ensure utf-8 is printed correctly on windows, this method // has issues(http://stackoverflow.com/a/10884364/4279) but // should work for at least windows 7 and newer. #if defined(_WIN32) && !defined(__CYGWIN__) SetConsoleOutputCP(CP_UTF8); #endif g_blink_path = argc > 0 ? argv[0] : 0; react = true; tuimode = true; WriteErrorInit(); InitMap(); GetOpts(argc, argv); InitBus(); #ifndef DISABLE_OVERLAYS if (SetOverlays(FLAG_overlays, true)) { WriteErrorString("bad blink overlays spec; see log for details\n"); exit(EXIT_FAILURE); } #endif #ifndef DISABLE_VFS if (VfsInit(FLAG_prefix)) { WriteErrorString("error: vfs initialization failed\n"); exit(EXIT_FAILURE); } #endif #ifdef HAVE_JIT AddPath_StartOp_Hook = AddPath_StartOp_Tui; #endif unassert((pty = NewPty())); unassert((s = NewSystem(wantmetal ? XED_MACHINE_MODE_REAL : XED_MACHINE_MODE_LONG))); unassert((m = g_machine = NewMachine(s, 0))); #ifdef HAVE_JIT if (!FLAG_wantjit || wantmetal) { DisableJit(&m->system->jit); } #endif if (wantmetal) { m->metal = true; } m->system->redraw = Redraw; m->system->onbinbase = OnBinbase; m->system->onlongbranch = OnLongBranch; #ifndef DISABLE_ROM m->system->onromwriteattempt = OnRomWriteAttempt; #endif speed = 1; SetXmmSize(2); SetXmmDisp(kXmmHex); signal(SIGPIPE, SIG_IGN); sigfillset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = OnSigSys; unassert(!sigaction(SIGSYS, &sa, 0)); sa.sa_handler = OnSigInt; unassert(!sigaction(SIGINT, &sa, 0)); sa.sa_handler = OnSigWinch; unassert(!sigaction(SIGWINCH, &sa, 0)); sa.sa_handler = OnSigAlrm; unassert(!sigaction(SIGALRM, &sa, 0)); #if !defined(__SANITIZE_THREAD__) && !defined(__FILC__) sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = OnSigSegv; unassert(!sigaction(SIGBUS, &sa, 0)); unassert(!sigaction(SIGSEGV, &sa, 0)); #endif m->system->blinksigs |= (u64)1 << (SIGINT_LINUX - 1) | // (u64)1 << (SIGALRM_LINUX - 1) | // (u64)1 << (SIGWINCH_LINUX - 1); // if (optind_ == argc) PrintUsage(48, stderr); rc = VirtualMachine(argc, argv); FreeBig(ophits, m->system->codesize * sizeof(unsigned long)); FreeMachine(m); ClearHistory(); FreePanels(); free(profsyms.p); if (FLAG_statistics) { PrintStats(); } return rc; } ================================================ FILE: blink/blinkenlights.h ================================================ #ifndef BLINK_BLINKENLIGHTS_H_ #define BLINK_BLINKENLIGHTS_H_ /* Shared variables and functions with bios.c */ #include #include #include #include #include "blink/likely.h" #include "blink/util.h" #define kModePty 255 /* blinkenlights.c */ extern int ttyin; extern int vidya; extern bool tuimode; extern struct Pty *pty; extern struct Machine *m; extern bool ptyisenabled; void SetCarry(bool cf); void ReactiveDraw(void); void Redraw(bool force); void DrawDisplayOnly(void); bool HasPendingKeyboard(void); void HandleAppReadInterrupt(bool errflag); ssize_t ReadAnsi(int fd, char *p, size_t n); /* bios.c */ void VidyaServiceSetMode(int); bool OnCallBios(int interrupt); static inline wint_t GetVidyaByte(unsigned char b) { if (LIKELY(0x20 <= b && b <= 0x7E)) return b; /* * In the emulated screen, show 0xff as a "shouldered open box" * instead of lambda. The Unicode 4.0 charts tell us that this * glyph is an ISO 9995-7 "keyboard symbol for No Break Space". */ if (UNLIKELY(b == 0xFF)) return 0x237D; return kCp437[b]; } #endif /* BLINK_BLINKENLIGHTS_H_ */ ================================================ FILE: blink/bmi2.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/rde.h" #ifndef DISABLE_BMI2 // BMI2 // BZHI clearing starting at bit // MULX flagless unsigned multiply // PDEP parallel bits deposit // PEXT parallel bits extract // RORX flagless rotate right logical // SARX flagless shift arithmetic right // SHRX flagless shift logical right // SHLX flagless shift logical left static u64 Pdep(u64 x, u64 mask) { u64 r, b; for (r = 0, b = 1; mask; mask >>= 1, b <<= 1) { if (mask & 1) { if (x & 1) r |= b; x >>= 1; } } return r; } static u64 Pext(u64 x, u64 mask) { u64 r, b; for (r = 0, b = 1; mask; mask >>= 1, x >>= 1) { if (mask & 1) { if (x & 1) r |= b; b <<= 1; } } return r; } static void OpPbit(P, u64 op(u64, u64)) { if (Rexw(rde)) { Put64(RegRexrReg(m, rde), op(Get64(RegVreg(m, rde)), Load64(GetModrmRegisterWordPointerRead8(A)))); } else { Put64(RegRexrReg(m, rde), (u32)op(Get32(RegVreg(m, rde)), Load32(GetModrmRegisterWordPointerRead4(A)))); } } static void OpBzhi(P) { int i; u64 x; bool sf; bool cf = 0; i = Get8(RegVreg(m, rde)); if (Rexw(rde)) { x = Load64(GetModrmRegisterWordPointerRead8(A)); if (i < 64) { x &= ((u64)1 << i) - 1; } else { cf = 1; } sf = (i64)x < 0; } else { x = Load32(GetModrmRegisterWordPointerRead4(A)); if (i < 32) { x &= (1u << i) - 1; } else { cf = 1; } sf = (i32)x < 0; } Put64(RegRexrReg(m, rde), x); m->flags = SetFlag(m->flags, FLAGS_ZF, !x); m->flags = SetFlag(m->flags, FLAGS_CF, cf); m->flags = SetFlag(m->flags, FLAGS_SF, sf); m->flags = SetFlag(m->flags, FLAGS_OF, false); } void Op2f5(P) { if (Rep(rde) == 2) { OpPbit(A, Pdep); } else if (Rep(rde) == 3) { OpPbit(A, Pext); } else if (!Osz(rde)) { OpBzhi(A); #ifndef TINY } else { OpUdImpl(m); #endif } } void OpRorx(P) { int i; u64 z; #ifndef TINY if (Ymm(rde)) OpUdImpl(m); #endif if (Rexw(rde)) { u64 x = Load64(GetModrmRegisterWordPointerRead8(A)); if ((i = uimm0 & 63)) { x = x >> i | x << (64 - i); } z = x; } else { u32 x = Load32(GetModrmRegisterWordPointerRead4(A)); if ((i = uimm0 & 31)) { x = x >> i | x << (32 - i); } z = x; } Put64(RegRexrReg(m, rde), z); } static void OpShlx(P) { int i; u64 z; i = Get8(RegVreg(m, rde)); if (Rexw(rde)) { u64 x = Load64(GetModrmRegisterWordPointerRead8(A)); i &= 63; if (i) x <<= i; z = x; } else { u32 x = Load32(GetModrmRegisterWordPointerRead4(A)); i &= 31; if (i) x <<= i; z = x; } Put64(RegRexrReg(m, rde), z); } static void OpShrx(P) { int i; u64 z; i = Get8(RegVreg(m, rde)); if (Rexw(rde)) { u64 x = Load64(GetModrmRegisterWordPointerRead8(A)); i &= 63; if (i) x >>= i; z = x; } else { u32 x = Load32(GetModrmRegisterWordPointerRead4(A)); i &= 31; if (i) x >>= i; z = x; } Put64(RegRexrReg(m, rde), z); } static void OpSarx(P) { int i; u64 z; i = Get8(RegVreg(m, rde)); if (Rexw(rde)) { i64 x = Load64(GetModrmRegisterWordPointerRead8(A)); i &= 63; if (i) x >>= i; z = x; } else { i32 x = Load32(GetModrmRegisterWordPointerRead4(A)); i &= 31; if (i) x >>= i; z = (u32)x; } Put64(RegRexrReg(m, rde), z); } void OpShx(P) { #ifndef TINY if (Ymm(rde)) OpUdImpl(m); #endif if (Osz(rde)) { OpShlx(A); } else if (Rep(rde) == 2) { OpShrx(A); } else if (Rep(rde) == 3) { OpSarx(A); #ifndef TINY } else { OpUdImpl(m); #endif } } #endif /* DISABLE_BMI2 */ ================================================ FILE: blink/breakpoint.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/breakpoint.h" #include #include #include "blink/builtin.h" void PopBreakpoint(struct Breakpoints *bps) { if (bps->i) { --bps->i; } } ssize_t PushBreakpoint(struct Breakpoints *bps, struct Breakpoint *b) { int i; for (i = 0; i < bps->i; ++i) { if (bps->p[i].disable) { memcpy(&bps->p[i], b, sizeof(*b)); return i; } } if (bps->i++ == bps->n) { bps->n = bps->i + (bps->i >> 1); bps->p = (struct Breakpoint *)realloc(bps->p, bps->n * sizeof(*bps->p)); } bps->p[bps->i - 1] = *b; return bps->i - 1; } ssize_t IsAtBreakpoint(struct Breakpoints *bps, i64 addr) { int i; for (i = bps->i; i--;) { if (bps->p[i].disable) continue; if (bps->p[i].addr == addr) { if (bps->p[i].oneshot) { bps->p[i].disable = true; if (i == bps->i - 1) { --bps->i; } } return i; } } return -1; } ================================================ FILE: blink/breakpoint.h ================================================ #ifndef BLINK_BREAKPOINT_H_ #define BLINK_BREAKPOINT_H_ #include #include #include #include "blink/types.h" struct Breakpoint { i64 addr; const char *symbol; bool disable; bool oneshot; }; struct Breakpoints { int i, n; struct Breakpoint *p; }; ssize_t IsAtBreakpoint(struct Breakpoints *, i64); ssize_t PushBreakpoint(struct Breakpoints *, struct Breakpoint *); void PopBreakpoint(struct Breakpoints *); #endif /* BLINK_BREAKPOINT_H_ */ ================================================ FILE: blink/breg.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/modrm.h" #include "blink/types.h" // Byte register offsets. // // for (i = 0; i < 2; ++i) { // rex // for (j = 0; j < 2; ++j) { // rexb, or rexr // for (k = 0; k < 8; ++k) { // reg, rm, or srm // kByteReg[i << 4 | j << 3 | k] = // i ? (j << 3 | k) * 8 : (k & 3) * 8 + ((k & 4) >> 2); // } // } // } const u8 kByteReg[32] = {0000, 0010, 0020, 0030, 0001, 0011, 0021, 0031, 0000, 0010, 0020, 0030, 0001, 0011, 0021, 0031, 0000, 0010, 0020, 0030, 0040, 0050, 0060, 0070, 0100, 0110, 0120, 0130, 0140, 0150, 0160, 0170}; ================================================ FILE: blink/buffer.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/buffer.h" #include #include #include #include #include #include #include #include "blink/macros.h" #include "blink/memcpy.h" #include "blink/stats.h" #include "blink/util.h" #include "blink/vfs.h" static bool GrowBuffer(struct Buffer *b, int need) { char *p; unsigned n; n = MAX(b->i + need, MAX(16, b->n + (b->n >> 1))); if (!(p = (char *)realloc(b->p, n))) return false; b->p = p; b->n = n; return true; } void AppendData(struct Buffer *b, const char *data, int len) { if (b->i + len + 1 > b->n && !GrowBuffer(b, len + 1)) return; memcpy(b->p + b->i, data, len); b->p[b->i += len] = 0; } int AppendChar(struct Buffer *b, char c) { if (b->i + 2 > b->n && !GrowBuffer(b, 2)) return 0; b->p[b->i++] = c; b->p[b->i] = 0; return 1; } int AppendStr(struct Buffer *b, const char *s) { int n = strlen(s); AppendData(b, s, n); return n; } int AppendWide(struct Buffer *b, wint_t wc) { u64 wb; if (0 <= wc && wc <= 0x7f) { AppendChar(b, wc); } else { if (b->i + 8 > b->n && !GrowBuffer(b, 8)) return 0; wb = tpenc(wc); do { b->p[b->i++] = wb & 0xFF; } while ((wb >>= 8)); b->p[b->i] = 0; } return 1; } int AppendFmt(struct Buffer *b, const char *fmt, ...) { int n; va_list va, vb; va_start(va, fmt); va_copy(vb, va); n = vsnprintf(b->p + b->i, b->n - b->i, fmt, va); if (b->i + n + 1 > b->n) { do { if (b->n) { b->n += b->n >> 1; } else { b->n = 16; } } while (b->i + n + 1 > b->n); b->p = (char *)realloc(b->p, b->n); vsnprintf(b->p + b->i, b->n - b->i, fmt, vb); } va_end(vb); va_end(va); b->i += n; return n; } ssize_t UninterruptibleWrite(int fd, const void *p, size_t n) { size_t i; ssize_t rc; for (i = 0; i < n; i += rc) { TryAgain: rc = VfsWrite(fd, (const char *)p + i, n - i); if (rc == -1 && errno == EINTR) goto TryAgain; if (rc == -1) return -1; } return n; } ================================================ FILE: blink/buffer.h ================================================ #ifndef BLINK_BUFFER_H_ #define BLINK_BUFFER_H_ #include #include #include "blink/builtin.h" struct Buffer { int i, n; char *p; }; int AppendChar(struct Buffer *, char); void AppendData(struct Buffer *, const char *, int); int AppendStr(struct Buffer *, const char *); int AppendWide(struct Buffer *, wint_t); int AppendFmt(struct Buffer *, const char *, ...) printf_attr(2); #endif /* BLINK_BUFFER_H_ */ ================================================ FILE: blink/builtin.h ================================================ #ifndef BLINK_BUILTIN_H_ #define BLINK_BUILTIN_H_ #include #include "config.h" #if __GNUC__ + 0 < 2 #undef __GNUC__ #elif defined(__GNUC__) && defined(SWIG) /* lool */ #undef __GNUC__ #elif defined(__GNUC__) && defined(__NVCC__) /* lool */ #undef __GNUC__ #elif !defined(__GNUC__) && defined(__APPLE__) /* modesty */ #define __GNUC__ 4 #define __GNUC_MINOR__ 2 #define __GNUC_PATCHLEVEL__ 1 #elif !defined(__GNUC__) && defined(__TINYC__) #define __GNUC__ 2 #define __GNUC_MINOR__ 0 #define __GNUC_PATCHLEVEL__ 0 #endif #ifdef __STRICT_ANSI__ #define asm __asm__ #endif #if __GNUC__ + 0 < 2 #define __attribute__(x) #endif #ifndef __has_builtin #define __has_builtin(x) 0 #endif #ifndef __has_attribute #define __has_attribute(x) 0 #endif #ifndef __has_feature #define __has_feature(x) 0 #endif #if !defined(__SANITIZE_THREAD__) && __has_feature(thread_sanitizer) #define __SANITIZE_THREAD__ #endif #if !defined(__SANITIZE_ADDRESS__) && __has_feature(address_sanitizer) #define __SANITIZE_ADDRESS__ #endif #ifndef __BIGGEST_ALIGNMENT__ #define __BIGGEST_ALIGNMENT__ 16 #endif #ifdef _MSC_VER #define __builtin_unreachable() __assume(0) #elif !((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405 || \ defined(__clang__) || defined(__INTEL_COMPILER)) #define __builtin_unreachable() \ for (;;) { \ } #endif #if !(defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)) #define __builtin_expect(x, y) (x) #endif #if !__has_builtin(__builtin___clear_cache) && \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) < 403 #define __builtin___clear_cache(x, y) (void)0 #endif #ifndef thatispacked #define thatispacked __attribute__((__packed__)) #endif #ifndef pureconst #define pureconst __attribute__((__const__)) #endif #ifndef dontinline #ifdef _MSC_VER #define dontinline __declspec(noinline) #elif __has_attribute(__noinline__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301 #define dontinline __attribute__((__noinline__)) #else #define dontinline #endif #endif #ifndef nosideeffect #if __has_attribute(__pure__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 296 #define nosideeffect __attribute__((__pure__)) #else #define nosideeffect #endif #endif #ifndef forceinline #ifdef __cplusplus #define forceinline inline #else #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 302 #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 || \ !defined(__cplusplus) || \ (defined(__clang__) && \ (defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__))) #if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus) #define forceinline \ static __inline __attribute__((__always_inline__, __gnu_inline__, \ __no_instrument_function__, __unused__)) #else #define forceinline \ static __inline __attribute__((__always_inline__, \ __no_instrument_function__, __unused__)) #endif /* __GNUC_STDC_INLINE__ */ #endif /* GCC >= 4.3 */ #elif defined(_MSC_VER) #define forceinline __forceinline #else #define forceinline static inline #endif /* !ANSI && GCC >= 3.2 */ #endif /* __cplusplus */ #endif #ifndef flattencalls #define flattencalls __attribute__((__flatten__)) #endif #ifndef relegated #if __has_attribute(__cold__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 #define relegated __attribute__((__cold__)) #else #define relegated #endif #endif #ifndef returnsaligned #if __has_attribute(__assume_aligned__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409 #define returnsaligned(x) __attribute__((__assume_aligned__ x)) #else #define returnsaligned(x) #endif #endif #ifndef optimizesize #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ __has_attribute(__optimize__) #define optimizesize __attribute__((__optimize__("s"))) #else #define optimizesize #endif #endif #ifndef dontclone #if __has_attribute(__noclone__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405 #define dontclone __attribute__((__noclone__)) #else #define dontclone #endif #endif #ifndef noinstrument #if __has_attribute(__no_instrument_function__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 204 #define noinstrument __attribute__((__no_instrument_function__)) #else #define noinstrument #endif #endif #ifndef noasan #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ __has_attribute(__no_sanitize_address__) #define noasan __attribute__((__no_sanitize_address__)) #else #define noasan #endif #endif #ifndef notsan #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ __has_attribute(__no_sanitize_thread__) #define notsan __attribute__((__no_sanitize_thread__)) #else #define notsan #endif #endif #ifndef noubsan #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ __has_attribute(__no_sanitize_undefined__) #define noubsan __attribute__((__no_sanitize_undefined__)) #else #define noubsan #endif #endif #ifndef nomsan #if __has_feature(memory_sanitizer) #define __SANITIZE_MEMORY__ #define nomsan __attribute__((__no_sanitize__("memory"))) #else #define nomsan #endif #endif #ifndef dontdiscard #if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \ __has_attribute(__warn_unused_result__)) #define dontdiscard __attribute__((__warn_unused_result__)) #else #define dontdiscard #endif #endif #ifndef nostackprotector #if __has_attribute(__no_stack_protector__) #define nostackprotector __attribute__((__no_stack_protector__)) #elif (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ __has_attribute(__optimize__) #define nostackprotector __attribute__((__optimize__("-fno-stack-protector"))) #else #define nostackprotector #endif #endif #ifdef __GNUC__ #define printf_attr(n) __attribute__((__format__(__printf__, n, n + 1))) #else #define printf_attr(n) #endif #ifdef __x86_64__ #define CAN_64BIT 1 #elif LONG_BIT >= 64 #define CAN_64BIT 1 #else #define CAN_64BIT 0 #endif #if CAN_64BIT && !defined(__STRICT_ANSI__) && \ ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406 || defined(__llvm__)) #define HAVE_INT128 #endif #if !defined(__SANITIZE_THREAD__) && defined(TSAN) #define __SANITIZE_THREAD__ #endif #if !defined(__SANITIZE_UNDEFINED__) && defined(UBSAN) #define __SANITIZE_UNDEFINED__ #endif #if !defined(DISABLE_JIT) && (defined(__x86_64__) || defined(__aarch64__)) && \ !defined(__SANITIZE_MEMORY__) && !defined(__SANITIZE_THREAD__) && \ !defined(__NetBSD__) && !defined(NOJIT) && !defined(__FILC__) #define HAVE_JIT #endif #if defined(HAVE_JIT) && defined(__GNUC__) && !defined(__SANITIZE_ADDRESS__) #ifndef __OPTIMIZE__ #define TRIVIALLY_RELOCATABLE \ noinstrument dontclone noubsan nostackprotector optimizesize #else #define TRIVIALLY_RELOCATABLE noinstrument dontclone noubsan nostackprotector #endif #define MICRO_OP_SAFE TRIVIALLY_RELOCATABLE forceinline #define MICRO_OP TRIVIALLY_RELOCATABLE #else #define MICRO_OP_SAFE static inline #define MICRO_OP #endif #if defined(__GNUC__) || defined(__llvm__) #pragma GCC diagnostic ignored "-Wtype-limits" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic error "-Wpointer-arith" #pragma GCC diagnostic error "-Wnonnull" #pragma GCC diagnostic error "-Wunused-result" #ifndef __cplusplus #pragma GCC diagnostic error "-Wimplicit-function-declaration" #if __GNUC__ >= 6 #pragma GCC diagnostic error "-Wincompatible-pointer-types" #if __GNUC__ >= 8 #pragma GCC diagnostic error "-Wmultistatement-macros" #pragma GCC diagnostic error "-Wpacked-not-aligned" #pragma GCC diagnostic error "-Wcast-align=strict" #pragma GCC diagnostic error "-Wif-not-aligned" #endif /* GCC 8+ */ #endif /* GCC 6+ */ #endif /* __cplusplus */ #endif /* GCC || LLVM */ #if defined(__GNUC__) && !defined(__llvm__) #pragma GCC diagnostic error "-Wwrite-strings" #pragma GCC diagnostic error "-Wtrampolines" #if __GNUC__ >= 6 #pragma GCC diagnostic error "-Wnonnull-compare" #pragma GCC diagnostic error "-Wframe-larger-than=16384" #if __GNUC__ >= 9 #pragma GCC diagnostic error "-Walloca-larger-than=1024" #pragma GCC diagnostic error "-Wvla-larger-than=1024" #endif /* GCC 9+ */ #elif __GNUC__ >= 9 #pragma GCC diagnostic error /* e.g. fabs not abs */ "-Wabsolute-value" #endif /* GCC 6+ */ #endif /* GCC && !LLVM */ #ifdef __llvm__ #pragma clang diagnostic error "-Wassume" #endif /* !GCC && LLVM */ #endif /* BLINK_BUILTIN_H_ */ ================================================ FILE: blink/bus.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bus.h" #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/dll.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/rde.h" #include "blink/swap.h" #include "blink/thread.h" #include "blink/tsan.h" #ifdef HAVE_PTHREAD_PROCESS_SHARED #define BUS_MEMORY MAP_SHARED #else #define BUS_MEMORY MAP_PRIVATE #endif struct Bus *g_bus; void InitBus(void) { unsigned i; pthread_condattr_t_ cattr; pthread_mutexattr_t_ mattr; #ifndef HAVE_PTHREAD_PROCESS_SHARED if (g_bus) FreeBig(g_bus, sizeof(*g_bus)); #endif unassert(g_bus = (struct Bus *)AllocateBig(sizeof(*g_bus), PROT_READ | PROT_WRITE, BUS_MEMORY | MAP_ANONYMOUS_, -1, 0)); unassert(!pthread_condattr_init(&cattr)); unassert(!pthread_mutexattr_init(&mattr)); #ifdef HAVE_PTHREAD_PROCESS_SHARED unassert(!pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED)); unassert(!pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)); #endif #ifdef HAVE_THREADS for (i = 0; i < kBusCount; ++i) unassert(!pthread_mutex_init(&g_bus->lock[i], 0)); #endif unassert(!pthread_mutex_init(&g_bus->futexes.lock, &mattr)); for (i = 0; i < kFutexMax; ++i) { unassert(!pthread_cond_init(&g_bus->futexes.mem[i].cond, &cattr)); unassert(!pthread_mutex_init(&g_bus->futexes.mem[i].lock, &mattr)); dll_init(&g_bus->futexes.mem[i].elem); dll_make_last(&g_bus->futexes.free, &g_bus->futexes.mem[i].elem); } unassert(!pthread_mutexattr_destroy(&mattr)); unassert(!pthread_condattr_destroy(&cattr)); } void LockBus(const u8 *locality) { #ifdef HAVE_THREADS /* A locked instruction is guaranteed to lock only the area of memory defined by the destination operand, but may be interpreted by the system as a lock for a larger memory area. ──Intel V.3 §8.1.2.2 */ _Static_assert(IS2POW(kBusCount), "virtual bus count must be two-power"); _Static_assert(IS2POW(kBusRegion), "virtual bus region must be two-power"); _Static_assert(kBusRegion >= 16, "virtual bus region must be at least 16"); LOCK(&g_bus->lock[(uintptr_t)locality / kBusRegion % kBusCount]); #endif } void UnlockBus(const u8 *locality) { #ifdef HAVE_THREADS UNLOCK(&g_bus->lock[(uintptr_t)locality / kBusRegion % kBusCount]); #endif } i64 Load8(const u8 p[1]) { return atomic_load_explicit((_Atomic(u8) *)p, memory_order_acquire); } i64 Load16(const u8 p[2]) { i64 z; #if (defined(__x86_64__) || defined(__i386__)) && \ !defined(__SANITIZE_UNDEFINED__) && !defined(__FILC__) z = atomic_load_explicit((_Atomic(u16) *)p, memory_order_relaxed); #else if (!((uintptr_t)p & 1)) { z = Little16(atomic_load_explicit((_Atomic(u16) *)p, memory_order_acquire)); } else { z = Read16(p); } #endif return z; } i64 Load32(const u8 p[4]) { i64 z; #if (defined(__x86_64__) || defined(__i386__)) && \ !defined(__SANITIZE_UNDEFINED__) && !defined(__FILC__) z = atomic_load_explicit((_Atomic(u32) *)p, memory_order_relaxed); #else if (!((uintptr_t)p & 3)) { z = Little32(atomic_load_explicit((_Atomic(u32) *)p, memory_order_acquire)); } else { z = Read32(p); } #endif return z; } i64 Load64(const u8 p[8]) { i64 z; #if CAN_64BIT #if defined(__x86_64__) && !defined(__SANITIZE_UNDEFINED__) && \ !defined(__FILC__) z = atomic_load_explicit((_Atomic(u64) *)p, memory_order_relaxed); #else if (!((uintptr_t)p & 7)) { z = Little64(atomic_load_explicit((_Atomic(u64) *)p, memory_order_acquire)); } else { z = Read64(p); } #endif #else LockBus(p); z = Read64(p); UnlockBus(p); #endif return z; } i64 Load64Unlocked(const u8 p[8]) { i64 z; #if CAN_64BIT z = Load64(p); #else z = Read64(p); #endif return z; } void Store8(u8 p[1], u64 x) { atomic_store_explicit((_Atomic(u8) *)p, x, memory_order_release); } void Store16(u8 p[2], u64 x) { #if (defined(__x86_64__) || defined(__i386__)) && \ !defined(__SANITIZE_UNDEFINED__) && !defined(__FILC__) atomic_store_explicit((_Atomic(u16) *)p, x, memory_order_relaxed); #else if (!((uintptr_t)p & 1)) { atomic_store_explicit((_Atomic(u16) *)p, Little16(x), memory_order_release); } else { Write16(p, x); } #endif } void Store32(u8 p[4], u64 x) { #if (defined(__x86_64__) || defined(__i386__)) && \ !defined(__SANITIZE_UNDEFINED__) && !defined(__FILC__) atomic_store_explicit((_Atomic(u32) *)p, x, memory_order_relaxed); #else if (!((uintptr_t)p & 3)) { atomic_store_explicit((_Atomic(u32) *)p, Little32(x), memory_order_release); } else { Write32(p, x); } #endif } void Store64(u8 p[8], u64 x) { #if CAN_64BIT #if defined(__x86_64__) && !defined(__SANITIZE_UNDEFINED__) && \ !defined(__FILC__) atomic_store_explicit((_Atomic(u64) *)p, x, memory_order_relaxed); #else if (!((uintptr_t)p & 7)) { atomic_store_explicit((_Atomic(u64) *)p, Little64(x), memory_order_release); } else { Write64(p, x); } #endif #else LockBus(p); Write64(p, x); UnlockBus(p); #endif } void Store64Unlocked(u8 p[8], u64 x) { #if CAN_64BIT Store64(p, x); #else Write64(p, x); #endif } u64 ReadRegister(u64 rde, u8 p[8]) { if (Rexw(rde)) { return Get64(p); } else if (!Osz(rde)) { return Get32(p); } else { return Get16(p); } } i64 ReadRegisterSigned(u64 rde, u8 p[8]) { if (Rexw(rde)) { return (i64)Get64(p); } else if (!Osz(rde)) { return (i32)Get32(p); } else { return (i16)Get16(p); } } void WriteRegister(u64 rde, u8 p[8], u64 x) { if (Rexw(rde)) { Put64(p, x); } else if (!Osz(rde)) { Put64(p, x & 0xffffffff); } else { Put16(p, x); } } u64 ReadMemory(u64 rde, u8 p[8]) { if (Rexw(rde)) { return Load64(p); } else if (!Osz(rde)) { return Load32(p); } else { return Load16(p); } } u64 ReadMemoryUnlocked(u64 rde, u8 p[8]) { if (Rexw(rde)) { return Load64Unlocked(p); } else if (!Osz(rde)) { return Load32(p); } else { return Load16(p); } } u64 ReadMemorySigned(u64 rde, u8 p[8]) { if (Rexw(rde)) { return (i64)Load64(p); } else if (!Osz(rde)) { return (i32)Load32(p); } else { return (i16)Load16(p); } } void WriteMemory(u64 rde, u8 p[8], u64 x) { if (Rexw(rde)) { Store64(p, x); } else if (!Osz(rde)) { Store32(p, x); } else { Store16(p, x); } } void WriteRegisterOrMemory(u64 rde, u8 p[8], u64 x) { if (IsModrmRegister(rde)) { WriteRegister(rde, p, x); } else { WriteMemory(rde, p, x); } } void WriteRegisterBW(u64 rde, u8 p[8], u64 x) { switch (RegLog2(rde)) { case 3: Put64(p, x); break; case 2: Put64(p, x & 0xffffffff); break; case 0: Put8(p, x); break; case 1: Put16(p, x); break; default: __builtin_unreachable(); } } i64 ReadRegisterBW(u64 rde, u8 p[8]) { switch (RegLog2(rde)) { case 3: return Get64(p); case 2: return Get32(p); case 0: return Get8(p); case 1: return Get16(p); default: __builtin_unreachable(); } } i64 ReadMemoryBW(u64 rde, u8 p[8]) { switch (RegLog2(rde)) { case 3: return Load64(p); case 2: return Load32(p); case 0: return Load8(p); case 1: return Load16(p); default: __builtin_unreachable(); } } void WriteMemoryBW(u64 rde, u8 p[8], u64 x) { switch (RegLog2(rde)) { case 3: Store64(p, x); break; case 2: Store32(p, x); break; case 0: Store8(p, x); break; case 1: Store16(p, x); break; default: __builtin_unreachable(); } } void WriteRegisterOrMemoryBW(u64 rde, u8 p[8], u64 x) { if (IsModrmRegister(rde)) { WriteRegisterBW(rde, p, x); } else { WriteMemoryBW(rde, p, x); } } i64 ReadRegisterOrMemoryBW(u64 rde, u8 p[8]) { if (IsModrmRegister(rde)) { return ReadRegisterBW(rde, p); } else { return ReadMemoryBW(rde, p); } } ================================================ FILE: blink/bus.h ================================================ #ifndef BLINK_MOP_H_ #define BLINK_MOP_H_ #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/dll.h" #include "blink/endian.h" #include "blink/thread.h" #include "blink/tsan.h" #include "blink/tunables.h" #include "blink/types.h" #define FUTEX_CONTAINER(e) DLL_CONTAINER(struct Futex, elem, e) struct Futex { i64 addr; int waiters; struct Dll elem; pthread_cond_t_ cond; pthread_mutex_t_ lock; }; struct Futexes { struct Dll *active; struct Dll *free; pthread_mutex_t_ lock; struct Futex mem[kFutexMax]; }; struct Bus { pthread_mutex_t_ lock[kBusCount]; struct Futexes futexes; }; extern struct Bus *g_bus; void InitBus(void); void LockBus(const u8 *); void UnlockBus(const u8 *); i64 Load8(const u8[1]) nosideeffect; i64 Load16(const u8[2]) nosideeffect; i64 Load32(const u8[4]) nosideeffect; i64 Load64(const u8[8]) nosideeffect; i64 Load64Unlocked(const u8[8]) nosideeffect; void Store8(u8[1], u64); void Store16(u8[2], u64); void Store32(u8[4], u64); void Store64(u8[8], u64); void Store64Unlocked(u8[8], u64); i64 ReadRegisterSigned(u64, u8[8]); u64 ReadMemory(u64, u8[8]); u64 ReadMemorySigned(u64, u8[8]); u64 ReadMemoryUnlocked(u64, u8[8]); u64 ReadRegister(u64, u8[8]); void WriteMemory(u64, u8[8], u64); void WriteRegister(u64, u8[8], u64); void WriteRegisterOrMemory(u64, u8[8], u64); i64 ReadMemoryBW(u64, u8[8]); i64 ReadRegisterBW(u64, u8[8]); void WriteMemoryBW(u64, u8[8], u64); void WriteRegisterBW(u64, u8[8], u64); i64 ReadRegisterOrMemoryBW(u64, u8[8]); void WriteRegisterOrMemoryBW(u64, u8[8], u64); u64 LoadPte32_(const u8 *) nosideeffect; bool CasPte32_(u8 *, u64, u64); void StorePte32_(u8 *, u64); nosideeffect static inline u64 LoadPte(const u8 *pte) { #if CAN_64BIT return Little64( atomic_load_explicit((_Atomic(u64) *)pte, memory_order_acquire)); #else return LoadPte32_(pte); #endif } static inline void StorePte(u8 *pte, u64 val) { #if CAN_64BIT atomic_store_explicit((_Atomic(u64) *)pte, Little64(val), memory_order_release); #else StorePte32_(pte, val); #endif } static inline bool CasPte(u8 *pte, u64 oldval, u64 newval) { #if CAN_64BIT oldval = Little64(oldval); return atomic_compare_exchange_strong_explicit( (_Atomic(u64) *)pte, &oldval, Little64(newval), // memory_order_release, memory_order_relaxed); #else return CasPte32_(pte, oldval, newval); #endif } #endif /* BLINK_MOP_H_ */ ================================================ FILE: blink/case.h ================================================ #ifndef BLINK_CASE_H_ #define BLINK_CASE_H_ #define CASE(OP, CODE) \ case OP: \ CODE; \ break #define CASR(OP, CODE) \ case OP: \ CODE; \ return #define XLAT(x, y) \ case x: \ return y #endif /* BLINK_CASE_H_ */ ================================================ FILE: blink/cga.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/cga.h" #include "blink/bda.h" #include #include #include "blink/blinkenlights.h" #include "blink/buffer.h" #include "blink/macros.h" #include "blink/util.h" /* blk blu grn cyn red mag yel wht */ static const u8 kCgaToAnsi[16] = {30, 34, 32, 36, 31, 35, 33, 37, 90, 94, 92, 96, 91, 95, 93, 97}; size_t FormatCga(u8 bgfg, char buf[11]) { return sprintf(buf, "\033[%d;%dm", kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10, kCgaToAnsi[bgfg & 0x0F]); } #ifdef IUTF8 #define CURSOR L'▂' #else #define CURSOR '_' #endif void DrawCga(struct Panel *p, u8 *vram) { unsigned y, x, ny, nx, a, ch, attr, curx, cury; u8 *v; wint_t wch; char buf[11]; ny = MIN(BdaLines, p->bottom - p->top); nx = BdaCols; curx = BdaCurx; cury = BdaCury; for (y = 0; y < ny; ++y) { a = -1; v = vram + y * nx * 2; for (x = 0; x < nx; ++x) { ch = *v++; attr = *v++; if (!BdaCurhidden && x == curx && y == cury) { if (ch == ' ' || ch == '\0') { wch = CURSOR; } else { wch = GetVidyaByte(ch); attr = (attr & 0xF0) >> 4 | (attr & 0x0F) << 4; } a = -1; } else { wch = GetVidyaByte(ch); } if (attr != a) { AppendData(&p->lines[y], buf, FormatCga((a = attr), buf)); } AppendWide(&p->lines[y], wch); } AppendStr(&p->lines[y], "\033[0m"); } } ================================================ FILE: blink/cga.h ================================================ #ifndef BLINK_CGA_H_ #define BLINK_CGA_H_ #include "blink/panel.h" #include "blink/types.h" void DrawCga(struct Panel *, u8 *); size_t FormatCga(u8, char[11]); #endif /* BLINK_CGA_H_ */ ================================================ FILE: blink/checked.h ================================================ #ifndef EASYCKDINT_H_ #define EASYCKDINT_H_ #ifdef __has_include #if __has_include() #include #ifndef ckd_add #error " lacks ckd_add() macro?" #endif /* !ckd_add */ #endif /* */ #endif /* __has_include */ #ifndef ckd_add #define __STDC_VERSION_STDCKDINT_H__ 202311L #if defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC) #define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res)) #define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res)) #define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res)) #endif /* __GNUC__ >= 5 && !__ICC */ #if !defined(ckd_add) && defined(__has_builtin) #if __has_builtin(__builtin_add_overflow) && \ __has_builtin(__builtin_sub_overflow) && \ __has_builtin(__builtin_mul_overflow) #define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res)) #define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res)) #define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res)) #endif /* __builtin_..._overflow */ #endif /* !ckd_add && __has_builtin */ #ifndef ckd_add /* FIXME */ #define ckd_add(res, x, y) (*(res) = (x) + (y), 0) #define ckd_sub(res, x, y) (*(res) = (x) - (y), 0) #define ckd_mul(res, x, y) (*(res) = (x) * (y), 0) #endif /* !ckd_add */ #endif /* !ckd_add */ #endif /* EASYCKDINT_H_ */ ================================================ FILE: blink/clmul.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bitscan.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/rde.h" struct clmul { u64 x, y; }; static struct clmul clmul(u64 a, u64 b) { u64 t, x = 0, y = 0; if (a && b) { if (bsr(a) < bsr(b)) t = a, a = b, b = t; for (t = 0; b; a <<= 1, b >>= 1) { if (b & 1) x ^= a, y ^= t; t = t << 1 | a >> 63; } } return (struct clmul){x, y}; } void OpSsePclmulqdq(P) { struct clmul res; if (Osz(rde)) { res = clmul( Get64(XmmRexrReg(m, rde) + ((uimm0 & 0x01) << 3)), Read64(GetModrmRegisterXmmPointerRead16(A) + ((uimm0 & 0x10) >> 1))); Put64(XmmRexrReg(m, rde) + 0, res.x); Put64(XmmRexrReg(m, rde) + 8, res.y); } else { OpUdImpl(m); } } ================================================ FILE: blink/close.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/debug.h" #include "blink/dll.h" #include "blink/errno.h" #include "blink/fds.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/vfs.h" static int CloseFd(struct Fd *fd) { int rc; unassert(fd->cb); if (fd->dirstream) { rc = VfsClosedir(fd->dirstream); } else { rc = fd->cb->close(fd->fildes); } FreeFd(fd); return rc; } static int CloseFds(struct Dll *fds) { int rc = 0; struct Dll *e, *e2; for (e = dll_first(fds); e; e = e2) { e2 = dll_next(fds, e); dll_remove(&fds, e); rc |= CloseFd(FD_CONTAINER(e)); } return rc; } static int FinishClose(struct Machine *m, int rc) { if (rc == -1 && errno == EINTR && !CheckInterrupt(m, true)) rc = 0; return rc; } int SysClose(struct Machine *m, i32 fildes) { struct Fd *fd; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { dll_remove(&m->system->fds.list, &fd->elem); } UNLOCK(&m->system->fds.lock); if (!fd) return -1; return FinishClose(m, CloseFd(fd)); } void SysCloseExec(struct System *s) { struct Fd *fd; struct Dll *e, *e2, *fds; LOCK(&s->fds.lock); for (fds = 0, e = dll_first(s->fds.list); e; e = e2) { fd = FD_CONTAINER(e); e2 = dll_next(s->fds.list, e); if (fd->oflags & O_CLOEXEC) { dll_remove(&s->fds.list, e); dll_make_last(&fds, e); } } UNLOCK(&s->fds.lock); CloseFds(fds); } #ifndef DISABLE_NONPOSIX static int SysCloseRangeCloexec(struct Machine *m, u32 first, u32 last) { struct Fd *fd; struct Dll *e; LOCK(&m->system->fds.lock); for (e = dll_first(m->system->fds.list); e; e = dll_next(m->system->fds.list, e)) { fd = FD_CONTAINER(e); if (first <= (u32)fd->fildes && (u32)fd->fildes <= last) { if (~fd->oflags & O_CLOEXEC) { fd->oflags |= O_CLOEXEC; VfsFcntl(fd->fildes, F_SETFD, FD_CLOEXEC); } } } UNLOCK(&m->system->fds.lock); return 0; } int SysCloseRange(struct Machine *m, u32 first, u32 last, u32 flags) { int rc; struct Fd *fd; sigset_t block, oldmask; struct Dll *e, *e2, *fds; if ((flags & ~CLOSE_RANGE_CLOEXEC_LINUX) || first > last) { return einval(); } if (flags & CLOSE_RANGE_CLOEXEC_LINUX) { return SysCloseRangeCloexec(m, first, last); } LOCK(&m->system->fds.lock); for (fds = 0, e = dll_first(m->system->fds.list); e; e = e2) { fd = FD_CONTAINER(e); e2 = dll_next(m->system->fds.list, e); if (first <= (u32)fd->fildes && (u32)fd->fildes <= last) { dll_remove(&m->system->fds.list, e); dll_make_last(&fds, e); } } UNLOCK(&m->system->fds.lock); unassert(!sigfillset(&block)); unassert(!pthread_sigmask(SIG_BLOCK, &block, &oldmask)); rc = CloseFds(fds); unassert(!pthread_sigmask(SIG_SETMASK, &oldmask, 0)); unassert(!(rc == -1 && errno == EINTR)); return rc; } #endif /* DISABLE_NONPOSIX */ ================================================ FILE: blink/cmpxchg.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/alu.h" #include "blink/assert.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/thread.h" void OpCmpxchgEbAlGb(P) { u8 *p = GetModrmRegisterBytePointerWrite1(A); u8 *q = ByteRexrReg(m, rde); u8 ax = atomic_load_explicit((_Atomic(u8) *)m->ax, memory_order_relaxed); atomic_compare_exchange_strong_explicit( (_Atomic(u8) *)p, &ax, atomic_load_explicit((_Atomic(u8) *)q, memory_order_relaxed), memory_order_acq_rel, memory_order_acquire); Sub8(m, Get8(m->ax), Little8(ax)); atomic_store_explicit((_Atomic(u8) *)m->ax, ax, memory_order_relaxed); } static void LockCmpxchgMem32(struct Machine *m, u64 rde, u8 *p) { u8 *q; int c; u32 x, z; bool didit; q = RegRexrReg(m, rde); if (!((uintptr_t)p & 3)) { x = atomic_load_explicit((_Atomic(u32) *)m->ax, memory_order_relaxed); didit = atomic_compare_exchange_strong_explicit( (_Atomic(u32) *)p, &x, atomic_load_explicit((_Atomic(u32) *)q, memory_order_relaxed), memory_order_acq_rel, memory_order_acquire); z = Get32(m->ax) - Little32(x); c = Get32(m->ax) < z; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; if (!didit) Put64(m->ax, Little32(x)); } else { LockBus(p); x = Load32(p); Sub32(m, Get32(m->ax), x); if ((didit = x == Get32(m->ax))) { Store32(p, Get32(q)); } else { Put64(m->ax, x); } UnlockBus(p); } } static void Cmpxchg(struct Machine *m, u64 rde, u8 *p) { u8 *q; bool didit; q = RegRexrReg(m, rde); if (Rexw(rde)) { u64 x; #if CAN_64BIT if (Lock(rde) && !((uintptr_t)p & 7)) { x = atomic_load_explicit((_Atomic(u64) *)m->ax, memory_order_relaxed); atomic_compare_exchange_strong_explicit( (_Atomic(u64) *)p, &x, atomic_load_explicit((_Atomic(u64) *)q, memory_order_relaxed), memory_order_acq_rel, memory_order_acquire); Sub64(m, Get64(m->ax), Little64(x)); atomic_store_explicit((_Atomic(u64) *)m->ax, x, memory_order_relaxed); return; } #endif if (Lock(rde)) { LockBus(p); x = Load64Unlocked(p); Sub64(m, Get64(m->ax), x); if ((didit = x == Get64(m->ax))) { Store64Unlocked(p, Get64(q)); } else { Put64(m->ax, x); } UnlockBus(p); } else { x = Load64(p); Sub64(m, Get64(m->ax), x); if ((didit = x == Get64(m->ax))) { Store64(p, Get64(q)); } else { Put64(m->ax, x); } } } else if (!Osz(rde)) { if (Lock(rde) && !((uintptr_t)p & 3)) { u32 ax = atomic_load_explicit((_Atomic(u32) *)m->ax, memory_order_relaxed); didit = atomic_compare_exchange_strong_explicit( (_Atomic(u32) *)p, &ax, atomic_load_explicit((_Atomic(u32) *)q, memory_order_relaxed), memory_order_acq_rel, memory_order_acquire); Sub32(m, Get32(m->ax), Little32(ax)); if (!didit) Put64(m->ax, Little32(ax)); } else { if (Lock(rde)) LockBus(p); u32 x = Load32(p); Sub32(m, Get32(m->ax), x); if ((didit = x == Get32(m->ax))) { Store32(p, Get32(q)); } else { Put64(m->ax, x); } if (Lock(rde)) UnlockBus(p); } if (IsModrmRegister(rde)) { Put32(p + 4, 0); } } else { if (Lock(rde) && !((uintptr_t)p & 1)) { u16 ax = atomic_load_explicit((_Atomic(u16) *)m->ax, memory_order_relaxed); atomic_compare_exchange_strong_explicit( (_Atomic(u16) *)p, &ax, atomic_load_explicit((_Atomic(u16) *)q, memory_order_relaxed), memory_order_acq_rel, memory_order_acquire); Sub16(m, Get16(m->ax), Little16(ax)); atomic_store_explicit((_Atomic(u16) *)m->ax, ax, memory_order_relaxed); } else { if (Lock(rde)) LockBus(p); u16 x = Load16(p); Sub16(m, Get16(m->ax), x); if ((didit = x == Get16(m->ax))) { Store16(p, Get16(q)); } else { Put16(m->ax, x); } if (Lock(rde)) UnlockBus(p); } } } void OpCmpxchgEvqpRaxGvqp(P) { Cmpxchg(m, rde, GetModrmRegisterWordPointerWriteOszRexw(A)); if (IsMakingPath(m)) { Jitter(A, "P" // res0 = GetRegOrMemPointer(RexbRm) "r0a2=" // arg2 = res0 "a1i" // arg1 = rde "q" // arg0 = m "c", // call function rde, (Lock(rde) && !IsModrmRegister(rde) && !Rexw(rde) && !Osz(rde) && !(GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF) & (SF | OF | AF | PF))) ? LockCmpxchgMem32 : Cmpxchg); } } ================================================ FILE: blink/commandv.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include #include "blink/builtin.h" #include "blink/overlays.h" #include "blink/util.h" #include "blink/vfs.h" struct PathSearcher { char *path; size_t pathlen; size_t namelen; const char *name; const char *syspath; }; static char EndsWithIgnoreCase(const char *p, unsigned long n, const char *s) { unsigned long i, m; if (n >= (m = strlen(s))) { for (i = n - m; i < n; ++i) { if (tolower(p[i]) != *s++) { return 0; } } return 1; } else { return 0; } } static char IsComPath(struct PathSearcher *ps) { return EndsWithIgnoreCase(ps->name, ps->namelen, ".com") || EndsWithIgnoreCase(ps->name, ps->namelen, ".exe") || EndsWithIgnoreCase(ps->name, ps->namelen, ".com.dbg"); } static char AccessCommand(struct PathSearcher *ps, const char *suffix, unsigned long pathlen) { unsigned long suffixlen; suffixlen = strlen(suffix); if (pathlen + 1 + ps->namelen + suffixlen + 1 > ps->pathlen) return 0; if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; memcpy(ps->path + pathlen, ps->name, ps->namelen); memcpy(ps->path + pathlen + ps->namelen, suffix, suffixlen + 1); return !VfsAccess(AT_FDCWD, ps->path, X_OK, 0); } static char SearchPath(struct PathSearcher *ps, const char *suffix) { const char *p; unsigned long i; for (p = ps->syspath;;) { for (i = 0; p[i] && p[i] != ':'; ++i) { if (i < ps->pathlen) { ps->path[i] = p[i]; } } if (AccessCommand(ps, suffix, i)) { return 1; } else if (p[i] == ':') { p += i + 1; } else { return 0; } } } static char FindCommand(struct PathSearcher *ps, const char *suffix) { if (memchr(ps->name, '/', ps->namelen) || memchr(ps->name, '\\', ps->namelen)) { ps->path[0] = 0; return AccessCommand(ps, suffix, 0); } else { if (AccessCommand(ps, suffix, 0)) return 1; } return SearchPath(ps, suffix); } /** * Searches for command `name` on system `$PATH`. */ char *Commandv(const char *name, char *buf, size_t size) { struct PathSearcher ps; ps.path = buf; ps.pathlen = size; ps.syspath = getenv("PATH"); if (!ps.syspath) ps.syspath = "/usr/local/bin:/bin:/usr/bin"; if (!(ps.namelen = strlen((ps.name = name)))) return 0; if (ps.namelen + 1 > ps.pathlen) return 0; if (FindCommand(&ps, "") || (!IsComPath(&ps) && FindCommand(&ps, ".com"))) { return ps.path; } else { return 0; } } ================================================ FILE: blink/compress.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/assert.h" #include "blink/util.h" void *Deflate(const void *data, unsigned size, unsigned *out_size) { void *res; uLong bound; z_stream zs = {0}; bound = compressBound(size); unassert(res = malloc(bound)); unassert(deflateInit2(&zs, 4, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) == Z_OK); zs.next_in = (z_const Bytef *)data; zs.avail_in = size; zs.avail_out = bound; zs.next_out = (Bytef *)res; unassert(deflate(&zs, Z_FINISH) == Z_STREAM_END); unassert(deflateEnd(&zs) == Z_OK); unassert(res = realloc(res, zs.total_out)); *out_size = zs.total_out; return res; } void Inflate(void *out, unsigned outsize, const void *in, unsigned insize) { z_stream zs; zs.next_in = (z_const Bytef *)in; zs.avail_in = insize; zs.total_in = insize; zs.next_out = (Bytef *)out; zs.avail_out = outsize; zs.total_out = outsize; zs.zalloc = Z_NULL; zs.zfree = Z_NULL; unassert(inflateInit2(&zs, -MAX_WBITS) == Z_OK); unassert(inflate(&zs, Z_FINISH) == Z_STREAM_END); unassert(inflateEnd(&zs) == Z_OK); } ================================================ FILE: blink/cp437.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/util.h" /* * The original hardware displayed 0x00, 0x20, and 0xff as space. It * made sense for viewing sparse binary data that 0x00 be blank. But * it doesn't make sense for dense data too, and we don't need three * space characters. So we diverge in our implementation and display * 0xff as lambda. */ const short kCp437[256] = /* clang-format off */ { 0x00a0,0x263a,0x263b,0x2665,0x2666,0x2663,0x2660,0x2022, /*00: ☺☻♥♦♣♠•*/ 0x25d8,0x25cb,0x25d9,0x2642,0x2640,0x266a,0x266b,0x263c, /*08:◘○◙♂♀♪♫☼*/ 0x25ba,0x25c4,0x2195,0x203c,0x00b6,0x00a7,0x25ac,0x21a8, /*10:►◄↕‼¶§▬↨*/ 0x2191,0x2193,0x2192,0x2190,0x221f,0x2194,0x25b2,0x25bc, /*18:↑↓→←∟↔▲▼*/ 0x0020,0x0021,0x201c,0x0023,0x0024,0x0025,0x0026,0x2018, /*20: !“#$%&‘*/ 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, /*28:()*+,-./*/ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, /*30:01234567*/ 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x2047, /*38:89:;<=>⁇*/ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, /*40:@ABCDEFG*/ 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, /*48:HIJKLMNO*/ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, /*50:PQRSTUVW*/ 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, /*58:XYZ[\]^_*/ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, /*60:`abcdefg*/ 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, /*68:hijklmno*/ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, /*70:pqrstuvw*/ 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302, /*78:xyz{|}~⌂*/ 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, /*80:Çüéâäàåç*/ 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, /*88:êëèïîìÄÅ*/ 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, /*90:ÉæÆôöòûù*/ 0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20ac,0x0192, /*98:ÿÖÜ¢£¥€ƒ*/ 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, /*a0:áíóúñѪº*/ 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, /*a8:¿⌐¬½¼¡«»*/ 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, /*b0:░▒▓│┤╡╢╖*/ 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, /*b8:╕╣║╗╝╜╛┐*/ 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, /*c0:└┴┬├─┼╞╟*/ 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, /*c8:╚╔╩╦╠═╬╧*/ 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, /*d0:╨╤╥╙╘╒╓╫*/ 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, /*d8:╪┘┌█▄▌▐▀*/ 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x03bc,0x03c4, /*e0:αßΓπΣσμτ*/ 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, /*e8:ΦΘΩδ∞φε∩*/ 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, /*f0:≡±≥≤⌠⌡÷≈*/ 0x00b0,0x2219,0x00d7,0x221a,0x207f,0x00b2,0x25a0,0x03bb, /*f8:°∙×√ⁿ²■λ*/ } /* clang-format on */; ================================================ FILE: blink/cpucount.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/macros.h" #include "blink/util.h" #ifdef HAVE_SCHED_H #include #endif #ifdef HAVE_SYSCTL #include #endif static _Atomic(int) g_cpucount; static int GetCpuCountImpl(void) { #ifdef HAVE_SCHED_GETAFFINITY cpu_set_t s; if (sched_getaffinity(0, sizeof(s), &s) == -1) return -1; return CPU_COUNT(&s); #elif defined(HAVE_SYSCTL) int x; size_t n = sizeof(x); int mib[] = {CTL_HW, HW_NCPU}; if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return -1; return x; #elif defined(_SC_NPROCESSORS_ONLN) return sysconf(_SC_NPROCESSORS_ONLN); #else return 1; #endif /* HAVE_SYSCTL */ } int GetCpuCount(void) { int rc; if (!(rc = g_cpucount)) { if ((rc = GetCpuCountImpl()) < 1) rc = 1; g_cpucount = rc; } return rc; } ================================================ FILE: blink/cpuid.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/assert.h" #include "blink/endian.h" #include "blink/machine.h" #define INTEL "GenuineIntel" #define BLINK "GenuineBlink" #define LINUX_ "Linux\0\0\0\0\0\0\0" #define FREEBSD_ "FreeBSD\0\0\0\0\0\0" #define NETBSD_ "NetBSD\0\0\0\0\0\0" #define OPENBSD_ "OpenBSD\0\0\0\0\0" #define XNU_ "XNU\0\0\0\0\0\0\0\0\0" #define WINDOWS_ "Windows\0\0\0\0\0" #define CYGWIN_ "Cygwin\0\0\0\0\0\0" #define HAIKU_ "Haiku\0\0\0\0\0\0\0" #define UNKNOWN_ "Unknown\0\0\0\0\0\0" #ifdef __COSMOPOLITAN__ #define OS \ (IsLinux() ? LINUX_ \ : IsFreebsd() ? FREEBSD_ \ : IsNetbsd() ? NETBSD_ \ : IsOpenbsd() ? OPENBSD_ \ : IsXnu() ? XNU_ \ : IsWindows() ? WINDOWS_ \ : UNKNOWN_) #elif defined(__linux) #define OS LINUX_ #elif defined(__FreeBSD__) #define OS FREEBSD_ #elif defined(__NetBSD__) #define OS NETBSD_ #elif defined(__OpenBSD__) #define OS OPENBSD_ #elif defined(__APPLE__) #define OS XNU_ #elif defined(__CYGWIN__) #define OS CYGWIN_ #elif defined(__HAIKU__) #define OS HAIKU_ #else #define OS UNKNOWN_ #endif #define X86_64_ "x86_64\0\0\0\0\0\0" #define I386_ "i386\0\0\0\0\0\0\0\0" #define AARCH64_ "aarch64\0\0\0\0\0" #define ARM_ "arm\0\0\0\0\0\0\0\0\0" #define PPC64_ "ppc64\0\0\0\0\0\0\0" #define PPC64LE_ "ppc64le\0\0\0\0\0" #define PPC_ "ppc\0\0\0\0\0\0\0\0\0" #define S390X_ "s390x\0\0\0\0\0\0\0" #define RISCV64_ "riscv64\0\0\0\0\0" #define RISCV32_ "riscv32\0\0\0\0\0" #if defined(__x86_64__) #define ARCH_NAME X86_64_ #elif defined(__i386__) #define ARCH_NAME I386_ #elif defined(__aarch64__) #define ARCH_NAME AARCH64_ #elif defined(__ARMEL__) #define ARCH_NAME ARM_ #elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) #define ARCH_NAME PPC64LE_ #elif defined(__powerpc64__) #define ARCH_NAME PPC64_ #elif defined(__powerpc__) #define ARCH_NAME PPC_ #elif defined(__s390x__) #define ARCH_NAME S390X_ #elif defined(__riscv) && __riscv_xlen == 64 #define ARCH_NAME RISCV64_ #elif defined(__riscv) && __riscv_xlen == 32 #define ARCH_NAME RISCV32_ #else #define ARCH_NAME UNKNOWN_ #endif void OpCpuid(P) { u32 ax, bx, cx, dx, jit; if (m->trapcpuid) { ThrowSegmentationFault(m, 0); } ax = bx = cx = dx = 0; switch (Get32(m->ax)) { case 0: ax = 7; goto vendor; case 0x80000000: ax = 0x80000001; vendor: // glibc binaries won't run unless we report blink as a // modern linux kernel on top of genuine intel hardware bx = Read32((const u8 *)INTEL + 0); dx = Read32((const u8 *)INTEL + 4); cx = Read32((const u8 *)INTEL + 8); break; case 0x40000000: bx = Read32((const u8 *)BLINK + 0); cx = Read32((const u8 *)BLINK + 4); dx = Read32((const u8 *)BLINK + 8); break; case 0x40031337: bx = Read32((const u8 *)OS + 0); cx = Read32((const u8 *)OS + 4); dx = Read32((const u8 *)OS + 8); break; case 0x40031338: bx = Read32((const u8 *)ARCH_NAME + 0); cx = Read32((const u8 *)ARCH_NAME + 4); dx = Read32((const u8 *)ARCH_NAME + 8); break; case 1: cx |= 1 << 0; // sse3 cx |= 1 << 1; // pclmulqdq cx |= 1 << 9; // ssse3 cx |= 1 << 23; // popcnt cx |= 1 << 30; // rdrnd cx |= 0 << 25; // aes cx |= 1 << 13; // cmpxchg16b cx |= 1u << 31; // hypervisor dx |= 1 << 4; // tsc dx |= 1 << 6; // pae dx |= 1 << 8; // cmpxchg8b dx |= 1 << 15; // cmov dx |= 1 << 19; // clflush dx |= 1 << 23; // mmx dx |= 1 << 24; // fxsave dx |= 1 << 25; // sse dx |= 1 << 26; // sse2 cx |= 0 << 19; // sse4.1 cx |= 0 << 20; // sse4.2 #ifndef DISABLE_X87 dx |= 1 << 0; // fpu #endif break; case 2: // Cache and TLB information ax = 0x76035a01; bx = 0x00f0b0ff; cx = 0x00000000; dx = 0x00ca0000; break; case 7: switch (Get32(m->cx)) { case 0: bx |= 1 << 0; // fsgsbase bx |= 1 << 9; // erms bx |= 1 << 18; // rdseed cx |= 1 << 22; // rdpid #ifndef DISABLE_BMI2 bx |= 1 << 8; // bmi2 bx |= 1 << 19; // adx #endif break; default: break; } break; case 0x80000001: jit = !IsJitDisabled(&m->system->jit); cx |= 1 << 0; // lahf cx |= jit << 31; // jit dx |= 1 << 0; // fpu dx |= 1 << 8; // cmpxchg8b dx |= 1 << 11; // syscall dx |= 1 << 15; // cmov dx |= 1 << 20; // nx dx |= 1 << 23; // mmx dx |= 1 << 24; // fxsave dx |= 1 << 27; // rdtscp dx |= 1 << 29; // long break; case 0x80000007: dx |= 1 << 8; // invtsc break; case 4: // cpu cache information // - Level 1 data 8-way 32,768 byte cache w/ 64 sets of 64 byte // lines shared across 2 threads // - Level 1 code 8-way 32,768 byte cache w/ 64 sets of 64 byte // lines shared across 2 threads // - Level 2 8-way 262,144 byte cache w/ 512 sets of 64 byte lines // shared across 2 threads // - Level 3 complexly-indexed 16-way 8,388,608 byte cache w/ 8,192 // sets of 64 byte lines shared across 16 threads switch (Get32(m->cx)) { case 0: ax = 0x1c004121; bx = 0x01c0003f; cx = 0x0000003f; dx = 0x00000000; break; case 1: ax = 0x1c004122; bx = 0x01c0003f; cx = 0x0000003f; dx = 0x00000000; break; case 2: ax = 0x1c004143; bx = 0x01c0003f; cx = 0x000001ff; dx = 0x00000000; break; case 3: ax = 0x1c03c163; bx = 0x03c0003f; cx = 0x00001fff; dx = 0x00000006; break; default: break; } break; case 6: // thermal and power management leaf ax = 0x00000077; bx = 0x00000002; cx = 0x0000000b; dx = 0x00000000; break; default: break; } Put64(m->ax, ax); Put64(m->bx, bx); Put64(m->cx, cx); Put64(m->dx, dx); } ================================================ FILE: blink/crc32.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bus.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/swap.h" #include "blink/types.h" static u32 kCastagnoli[256]; static void InitializeCrc32(u32 table[256], u32 polynomial) { u32 d, i, r; for (d = 0; d < 256; ++d) { r = d; for (i = 0; i < 8; ++i) { r = r >> 1 ^ (r & 1 ? polynomial : 0); } table[d] = r; } } static u32 ReverseBits32(u32 x) { x = SWAP32(x); x = (x & 0xaaaaaaaa) >> 1 | (x & 0x55555555) << 1; x = (x & 0xcccccccc) >> 2 | (x & 0x33333333) << 2; x = (x & 0xf0f0f0f0) >> 4 | (x & 0x0f0f0f0f) << 4; return x; } static u32 Castagnoli(u32 h, u64 w, long n) { long i; static int once; if (!once) { InitializeCrc32(kCastagnoli, ReverseBits32(0x1edc6f41)); once = 1; } for (i = 0; i < n; ++i) { h = h >> 8 ^ kCastagnoli[(h & 255) ^ (w & 255)]; w >>= 8; } return h; } static void OpCrc32(P) { Put64(RegRexrReg(m, rde), Castagnoli(Get32(RegRexrReg(m, rde)), ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A)), 1 << RegLog2(rde))); } void Op2f01(P) { if (!Rep(rde) && !Osz(rde)) { OpUdImpl(m); // TODO: movbe } else if (Rep(rde) == 2 && !Osz(rde)) { OpCrc32(A); } else { OpUdImpl(m); } } ================================================ FILE: blink/cvt.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/fpu.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/pun.h" #include "blink/stats.h" #define kOpCvt0f2a 0 #define kOpCvtt0f2c 4 #define kOpCvt0f2d 8 #define kOpCvt0f5a 12 #define kOpCvt0f5b 16 #define kOpCvt0fE6 20 static double SseRoundDouble(struct Machine *m, double x) { switch ((m->mxcsr & kMxcsrRc) >> 13) { case 0: return rint(x); case 1: return floor(x); case 2: return ceil(x); case 3: return trunc(x); default: __builtin_unreachable(); } } static void OpGdqpWssCvttss2si(P) { i64 n; union FloatPun f; f.i = Read32(GetModrmRegisterXmmPointerRead4(A)); n = f.f; if (!Rexw(rde)) n &= 0xffffffff; Put64(RegRexrReg(m, rde), n); } static void OpGdqpWsdCvttsd2si(P) { i64 n; union DoublePun d; d.i = Read64(GetModrmRegisterXmmPointerRead8(A)); n = d.f; if (!Rexw(rde)) n &= 0xffffffff; Put64(RegRexrReg(m, rde), n); } static void OpGdqpWssCvtss2si(P) { i64 n; union FloatPun f; f.i = Read32(GetModrmRegisterXmmPointerRead4(A)); n = rintf(f.f); if (!Rexw(rde)) n &= 0xffffffff; Put64(RegRexrReg(m, rde), n); } static void OpGdqpWsdCvtsd2si(P) { i64 n; union DoublePun d; d.i = Read64(GetModrmRegisterXmmPointerRead8(A)); n = SseRoundDouble(m, d.f); if (!Rexw(rde)) n &= 0xffffffff; Put64(RegRexrReg(m, rde), n); } static void OpVssEdqpCvtsi2ss(P) { union FloatPun f; if (Rexw(rde)) { i64 n = Read64(GetModrmRegisterWordPointerRead8(A)); f.f = n; Put32(XmmRexrReg(m, rde), f.i); if (IsMakingPath(m)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "a2i" // arg2 = RexrReg(rde) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call function (d1) RexrReg(rde), Int64ToFloat); } } else { i32 n = Read32(GetModrmRegisterWordPointerRead4(A)); f.f = n; Put32(XmmRexrReg(m, rde), f.i); if (IsMakingPath(m)) { Jitter(A, "z2B" // res0 = GetRegOrMem[force32bit](RexbRm) "a2i" // arg2 = RexrReg(rde) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call function (d1) RexrReg(rde), Int32ToFloat); } } } static void OpVsdEdqpCvtsi2sd(P) { union DoublePun d; if (Rexw(rde)) { d.f = (i64)Read64(GetModrmRegisterWordPointerRead8(A)); Put64(XmmRexrReg(m, rde), d.i); if (IsMakingPath(m)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "a2i" // arg2 = RexrReg(rde) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call function (d1) RexrReg(rde), Int64ToDouble); } } else { d.f = (i32)Read32(GetModrmRegisterWordPointerRead4(A)); Put64(XmmRexrReg(m, rde), d.i); if (IsMakingPath(m)) { Jitter(A, "z2B" // res0 = GetRegOrMem[force32bit](RexbRm) "a2i" // arg2 = RexrReg(rde) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call function (d1) RexrReg(rde), Int32ToDouble); } } } static void OpVpsQpiCvtpi2ps(P) { u8 *p; i32 i[2]; union FloatPun f[2]; p = GetModrmRegisterMmPointerRead8(A); i[0] = Read32(p + 0); i[1] = Read32(p + 4); f[0].f = i[0]; f[1].f = i[1]; Put32(XmmRexrReg(m, rde) + 0, f[0].i); Put32(XmmRexrReg(m, rde) + 4, f[1].i); } static void OpVpdQpiCvtpi2pd(P) { u8 *p; i32 n[2]; union DoublePun f[2]; p = GetModrmRegisterMmPointerRead8(A); n[0] = Read32(p + 0); n[1] = Read32(p + 4); f[0].f = n[0]; f[1].f = n[1]; Put64(XmmRexrReg(m, rde) + 0, f[0].i); Put64(XmmRexrReg(m, rde) + 8, f[1].i); } static void OpPpiWpsqCvtps2pi(P) { u8 *p; unsigned i; i32 n[2]; union FloatPun f[2]; p = GetModrmRegisterXmmPointerRead8(A); f[0].i = Read32(p + 0 * 4); f[1].i = Read32(p + 1 * 4); switch ((m->mxcsr & kMxcsrRc) >> 13) { case 0: for (i = 0; i < 2; ++i) n[i] = rintf(f[i].f); break; case 1: for (i = 0; i < 2; ++i) n[i] = floorf(f[i].f); break; case 2: for (i = 0; i < 2; ++i) n[i] = ceilf(f[i].f); break; case 3: for (i = 0; i < 2; ++i) n[i] = truncf(f[i].f); break; default: __builtin_unreachable(); } Put32(MmReg(m, rde) + 0, n[0]); Put32(MmReg(m, rde) + 4, n[1]); } static void OpPpiWpsqCvttps2pi(P) { u8 *p; i32 n[2]; union FloatPun f[2]; p = GetModrmRegisterXmmPointerRead8(A); f[0].i = Read32(p + 0); f[1].i = Read32(p + 4); n[0] = f[0].f; n[1] = f[1].f; Put32(MmReg(m, rde) + 0, n[0]); Put32(MmReg(m, rde) + 4, n[1]); } static void OpPpiWpdCvtpd2pi(P) { u8 *p; unsigned i; i32 n[2]; union DoublePun d[2]; p = GetModrmRegisterXmmPointerRead16(A); d[0].i = Read64(p + 0); d[1].i = Read64(p + 8); for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i].f); Put32(MmReg(m, rde) + 0, n[0]); Put32(MmReg(m, rde) + 4, n[1]); } static void OpPpiWpdCvttpd2pi(P) { u8 *p; i32 n[2]; union DoublePun d[2]; p = GetModrmRegisterXmmPointerRead16(A); d[0].i = Read64(p + 0); d[1].i = Read64(p + 8); n[0] = d[0].f; n[1] = d[1].f; Put32(MmReg(m, rde) + 0, n[0]); Put32(MmReg(m, rde) + 4, n[1]); } static void OpVpdWpsCvtps2pd(P) { u8 *p; union FloatPun f[2]; union DoublePun d[2]; p = GetModrmRegisterXmmPointerRead8(A); f[0].i = Read32(p + 0); f[1].i = Read32(p + 4); d[0].f = f[0].f; d[1].f = f[1].f; Put64(XmmRexrReg(m, rde) + 0, d[0].i); Put64(XmmRexrReg(m, rde) + 8, d[1].i); } static void OpVpsWpdCvtpd2ps(P) { u8 *p; union FloatPun f[2]; union DoublePun d[2]; p = GetModrmRegisterXmmPointerRead16(A); d[0].i = Read64(p + 0); d[1].i = Read64(p + 8); f[0].f = d[0].f; f[1].f = d[1].f; Put32(XmmRexrReg(m, rde) + 0, f[0].i); Put32(XmmRexrReg(m, rde) + 4, f[1].i); } static void OpVssWsdCvtsd2ss(P) { union FloatPun f; union DoublePun d; d.i = Read64(GetModrmRegisterXmmPointerRead8(A)); f.f = d.f; Put32(XmmRexrReg(m, rde), f.i); } static void OpVsdWssCvtss2sd(P) { union FloatPun f; union DoublePun d; f.i = Read32(GetModrmRegisterXmmPointerRead4(A)); d.f = f.f; Put64(XmmRexrReg(m, rde), d.i); } static void OpVpsWdqCvtdq2ps(P) { u8 *p; i32 n[4]; union FloatPun f[4]; p = GetModrmRegisterXmmPointerRead16(A); n[0] = Read32(p + 0 * 4); n[1] = Read32(p + 1 * 4); n[2] = Read32(p + 2 * 4); n[3] = Read32(p + 3 * 4); f[0].f = n[0]; f[1].f = n[1]; f[2].f = n[2]; f[3].f = n[3]; Put32(XmmRexrReg(m, rde) + 0 * 4, f[0].i); Put32(XmmRexrReg(m, rde) + 1 * 4, f[1].i); Put32(XmmRexrReg(m, rde) + 2 * 4, f[2].i); Put32(XmmRexrReg(m, rde) + 3 * 4, f[3].i); } static void OpVpdWdqCvtdq2pd(P) { u8 *p; i32 n[2]; union DoublePun d[2]; p = GetModrmRegisterXmmPointerRead8(A); n[0] = Read32(p + 0 * 4); n[1] = Read32(p + 1 * 4); d[0].f = n[0]; d[1].f = n[1]; Put64(XmmRexrReg(m, rde) + 0, d[0].i); Put64(XmmRexrReg(m, rde) + 8, d[1].i); } static void OpVdqWpsCvttps2dq(P) { u8 *p; i32 n[4]; union FloatPun f[4]; p = GetModrmRegisterXmmPointerRead16(A); f[0].i = Read32(p + 0 * 4); f[1].i = Read32(p + 1 * 4); f[2].i = Read32(p + 2 * 4); f[3].i = Read32(p + 3 * 4); n[0] = f[0].f; n[1] = f[1].f; n[2] = f[2].f; n[3] = f[3].f; Put32(XmmRexrReg(m, rde) + 0 * 4, n[0]); Put32(XmmRexrReg(m, rde) + 1 * 4, n[1]); Put32(XmmRexrReg(m, rde) + 2 * 4, n[2]); Put32(XmmRexrReg(m, rde) + 3 * 4, n[3]); } static void OpVdqWpsCvtps2dq(P) { u8 *p; unsigned i; i32 n[4]; union FloatPun f[4]; p = GetModrmRegisterXmmPointerRead16(A); f[0].i = Read32(p + 0 * 4); f[1].i = Read32(p + 1 * 4); f[2].i = Read32(p + 2 * 4); f[3].i = Read32(p + 3 * 4); switch ((m->mxcsr & kMxcsrRc) >> 13) { case 0: for (i = 0; i < 4; ++i) n[i] = rintf(f[i].f); break; case 1: for (i = 0; i < 4; ++i) n[i] = floorf(f[i].f); break; case 2: for (i = 0; i < 4; ++i) n[i] = ceilf(f[i].f); break; case 3: for (i = 0; i < 4; ++i) n[i] = truncf(f[i].f); break; default: __builtin_unreachable(); } Put32(XmmRexrReg(m, rde) + 0 * 4, n[0]); Put32(XmmRexrReg(m, rde) + 1 * 4, n[1]); Put32(XmmRexrReg(m, rde) + 2 * 4, n[2]); Put32(XmmRexrReg(m, rde) + 3 * 4, n[3]); } static void OpVdqWpdCvttpd2dq(P) { u8 *p; i32 n[2]; union DoublePun d[2]; p = GetModrmRegisterXmmPointerRead16(A); d[0].i = Read64(p + 0); d[1].i = Read64(p + 8); n[0] = d[0].f; n[1] = d[1].f; Put32(XmmRexrReg(m, rde) + 0, n[0]); Put32(XmmRexrReg(m, rde) + 4, n[1]); } static void OpVdqWpdCvtpd2dq(P) { u8 *p; i32 n[2]; unsigned i; union DoublePun d[2]; p = GetModrmRegisterXmmPointerRead16(A); d[0].i = Read64(p + 0); d[1].i = Read64(p + 8); for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i].f); Put32(XmmRexrReg(m, rde) + 0, n[0]); Put32(XmmRexrReg(m, rde) + 4, n[1]); } static void OpCvt(P, unsigned long op) { IGNORE_RACES_START(); switch (op | Rep(rde) | Osz(rde)) { case kOpCvt0f2a + 0: OpVpsQpiCvtpi2ps(A); break; case kOpCvt0f2a + 1: OpVpdQpiCvtpi2pd(A); break; case kOpCvt0f2a + 2: OpVsdEdqpCvtsi2sd(A); // #1 hot (6796033) break; case kOpCvt0f2a + 3: OpVssEdqpCvtsi2ss(A); break; case kOpCvtt0f2c + 0: OpPpiWpsqCvttps2pi(A); break; case kOpCvtt0f2c + 1: OpPpiWpdCvttpd2pi(A); break; case kOpCvtt0f2c + 2: // #2 hot (111540) OpGdqpWsdCvttsd2si(A); break; case kOpCvtt0f2c + 3: OpGdqpWssCvttss2si(A); break; case kOpCvt0f2d + 0: OpPpiWpsqCvtps2pi(A); break; case kOpCvt0f2d + 1: OpPpiWpdCvtpd2pi(A); break; case kOpCvt0f2d + 2: OpGdqpWsdCvtsd2si(A); break; case kOpCvt0f2d + 3: OpGdqpWssCvtss2si(A); break; case kOpCvt0f5a + 0: OpVpdWpsCvtps2pd(A); break; case kOpCvt0f5a + 1: OpVpsWpdCvtpd2ps(A); break; case kOpCvt0f5a + 2: OpVssWsdCvtsd2ss(A); break; case kOpCvt0f5a + 3: OpVsdWssCvtss2sd(A); break; case kOpCvt0f5b + 0: OpVpsWdqCvtdq2ps(A); break; case kOpCvt0f5b + 1: OpVdqWpsCvtps2dq(A); break; case kOpCvt0f5b + 3: OpVdqWpsCvttps2dq(A); break; case kOpCvt0fE6 + 1: OpVdqWpdCvtpd2dq(A); break; case kOpCvt0fE6 + 2: OpVdqWpdCvttpd2dq(A); break; case kOpCvt0fE6 + 3: OpVpdWdqCvtdq2pd(A); break; default: OpUdImpl(m); } IGNORE_RACES_END(); } void OpCvt0f2a(P) { OpCvt(A, kOpCvt0f2a); } void OpCvtt0f2c(P) { OpCvt(A, kOpCvtt0f2c); } void OpCvt0f2d(P) { OpCvt(A, kOpCvt0f2d); } void OpCvt0f5a(P) { OpCvt(A, kOpCvt0f5a); } void OpCvt0f5b(P) { OpCvt(A, kOpCvt0f5b); } void OpCvt0fE6(P) { OpCvt(A, kOpCvt0fE6); } ================================================ FILE: blink/debug.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/debug.h" #include #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/dis.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/loader.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/overlays.h" #include "blink/stats.h" #include "blink/thread.h" #include "blink/tsan.h" #include "blink/util.h" #include "blink/x86.h" #ifdef HAVE_SCHED_H #include #endif #if defined(HAVE_LIBUNWIND) && !defined(MUSL_CROSS_MAKE) #define UNW_LOCAL_ONLY #ifdef __x86_64__ #include #else #include #endif #endif #define FAKE_WORD 0x6660666066660666 #define MAX_BACKTRACE_LINES 64 #define APPEND(...) o += snprintf(b + o, o > n ? 0 : n - o, __VA_ARGS__) _Thread_local static jmp_buf g_busted; const char *GetBlinkBacktrace(void) { #if defined(HAVE_LIBUNWIND) && !defined(MUSL_CROSS_MAKE) _Thread_local static char b[2048]; int o = 0; char sym[256]; int n = sizeof(b); unw_cursor_t cursor; unw_context_t context; unw_word_t offset, pc; unw_getcontext(&context); unw_init_local(&cursor, &context); APPEND("blink backtrace"); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &pc); if (!pc) break; APPEND("\n\t%lx ", pc); if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { APPEND("%s+%ld", sym, offset); } else { APPEND(""); } } return b; #else return ""; #endif } static void OnBusted(int sig) { longjmp(g_busted, sig); } static i64 ReadWord(int mode, u8 *p) { switch (mode) { default: case XED_MODE_LONG: return Load64Unlocked(p); case XED_MODE_LEGACY: return Load32(p); case XED_MODE_REAL: return Load16(p); } } i64 ReadWordSafely(int mode, u8 *p) { i64 res; sigset_t oldss, newss; struct sigaction newsa, oldsa[2]; newsa.sa_flags = 0; newsa.sa_handler = OnBusted; sigemptyset(&newsa.sa_mask); sigemptyset(&newss); sigaddset(&newss, SIGBUS); sigaddset(&newss, SIGSEGV); sigaction(SIGBUS, &newsa, oldsa + 0); sigaction(SIGSEGV, &newsa, oldsa + 1); pthread_sigmask(SIG_UNBLOCK, &newss, &oldss); if (!setjmp(g_busted)) { res = ReadWord(mode, p); } else { res = FAKE_WORD >> ((8 - (2 << mode)) * 8); } pthread_sigmask(SIG_SETMASK, &oldss, 0); sigaction(SIGSEGV, oldsa + 1, 0); sigaction(SIGBUS, oldsa + 0, 0); return res; } // TODO(jart): This function should be immune to SIGSEGV and SIGBUS. int GetInstruction(struct Machine *m, i64 pc, struct XedDecodedInst *x) { int i, rc, err; u8 copy[15], *toil, *addr; BEGIN_NO_PAGE_FAULTS; if ((addr = SpyAddress(m, pc))) { if ((i = 4096 - (pc & 4095)) >= 15) { if (!DecodeInstruction(x, addr, 15, m->mode.omode)) { rc = 0; } else { rc = kMachineDecodeError; } } else if ((toil = SpyAddress(m, pc + i))) { memcpy(copy, addr, i); memcpy(copy + i, toil, 15 - i); if (!DecodeInstruction(x, copy, 15, m->mode.omode)) { rc = 0; } else { rc = kMachineDecodeError; } } else if (!(err = DecodeInstruction(x, addr, i, m->mode.omode))) { rc = 0; } else if (err == XED_ERROR_BUFFER_TOO_SHORT) { rc = kMachineSegmentationFault; } else { rc = kMachineDecodeError; } } else { memset(x, 0, sizeof(*x)); rc = kMachineSegmentationFault; } END_NO_PAGE_FAULTS; return rc; } const char *DescribeCpuFlags(int flags) { _Thread_local static char b[7]; b[0] = (flags & OF) ? 'O' : '.'; b[1] = (flags & SF) ? 'S' : '.'; b[2] = (flags & ZF) ? 'Z' : '.'; b[3] = (flags & AF) ? 'A' : '.'; b[4] = (flags & PF) ? 'P' : '.'; b[5] = (flags & CF) ? 'C' : '.'; return b; } const char *DescribeOp(struct Machine *m, i64 pc) { _Thread_local static char b[256]; int e, i, k, o = 0, n = sizeof(b); struct Dis d = {true}; if (!(e = GetInstruction(m, pc, d.xedd))) { #ifndef DISABLE_DISASSEMBLER char spec[64]; o = DisInst(&d, b, DisSpec(d.xedd, spec)) - b; #else APPEND(".byte"); #endif } if (e != kMachineSegmentationFault) { k = MAX(8, d.xedd->length); for (i = 0; i < k; ++i) { APPEND(" %02x", d.xedd->bytes[i]); } } else { APPEND("segfault"); } #ifndef DISABLE_DISASSEMBLER DisFree(&d); #endif return b; } void PrintFds(struct Fds *fds) { struct Dll *e; LOGF("%-8s %-8s", "fildes", "oflags"); for (e = dll_first(fds->list); e; e = dll_next(fds->list, e)) { LOGF("%-8d %-8x", FD_CONTAINER(e)->fildes, FD_CONTAINER(e)->oflags); } } const char *GetBacktrace(struct Machine *m) { _Thread_local static char b[16384]; int o = 0; int n = sizeof(b); #ifndef DISABLE_BACKTRACE struct Dis dis = {true}; u8 *r; int i; i64 sym, sp, bp, rp; char kAlignmentMask[] = {3, 3, 15}; #endif if (!m) return ""; BEGIN_NO_PAGE_FAULTS; #ifndef DISABLE_BACKTRACE if (!m->system->dis) { m->system->dis = &dis; LoadDebugSymbols(m->system); } #endif APPEND(" PC %" PRIx64 " %s\n\t" " AX %016" PRIx64 " " " CX %016" PRIx64 " " " DX %016" PRIx64 " " " BX %016" PRIx64 "\n\t" " SP %016" PRIx64 " " " BP %016" PRIx64 " " " SI %016" PRIx64 " " " DI %016" PRIx64 "\n\t" " R8 %016" PRIx64 " " " R9 %016" PRIx64 " " "R10 %016" PRIx64 " " "R11 %016" PRIx64 "\n\t" "R12 %016" PRIx64 " " "R13 %016" PRIx64 " " "R14 %016" PRIx64 " " "R15 %016" PRIx64 "\n\t" " FS %016" PRIx64 " " " GS %016" PRIx64 " " "OPS %-16ld " "FLG %s\n\t" "%s\n\t", m->cs.base + MaskAddress(m->mode.omode, m->ip), DescribeOp(m, GetPc(m)), Get64(m->ax), Get64(m->cx), Get64(m->dx), Get64(m->bx), Get64(m->sp), Get64(m->bp), Get64(m->si), Get64(m->di), Get64(m->r8), Get64(m->r9), Get64(m->r10), Get64(m->r11), Get64(m->r12), Get64(m->r13), Get64(m->r14), Get64(m->r15), m->fs.base, m->gs.base, GET_COUNTER(instructions_decoded), DescribeCpuFlags(m->flags), g_progname); #ifndef DISABLE_BACKTRACE rp = m->ip; bp = Get64(m->bp); sp = Get64(m->sp); for (i = 0; i < MAX_BACKTRACE_LINES;) { if (i) APPEND("\n\t"); sym = DisFindSym(m->system->dis, rp); APPEND("%012" PRIx64 " %012" PRIx64 " %s", m->ss.base + bp, rp, sym != -1 ? m->system->dis->syms.p[sym].name : "UNKNOWN"); if (sym != -1 && rp != m->system->dis->syms.p[sym].addr) { APPEND("+%#" PRIx64 "", rp - m->system->dis->syms.p[sym].addr); } if (!bp) break; if (bp < sp) { APPEND(" [STRAY]"); } else if (bp - sp <= 0x1000) { APPEND(" %" PRId64 " bytes", bp - sp); } if (bp & kAlignmentMask[m->mode.omode] && i) { APPEND(" [MISALIGN]"); } ++i; if (((m->ss.base + bp) & 0xfff) > 0xff0) break; if (!(r = SpyAddress(m, m->ss.base + bp))) { APPEND(" [CORRUPT FRAME POINTER]"); break; } sp = bp; bp = ReadWordSafely(m->mode.omode, r + 0); rp = ReadWordSafely(m->mode.omode, r + 8); } if (m->system->dis == &dis) { DisFree(&dis); m->system->dis = 0; } #endif END_NO_PAGE_FAULTS; return b; } bool CheckMemoryInvariants(struct System *s) { // TODO(jart): rewrite our memory accounting code return true; } ================================================ FILE: blink/debug.h ================================================ #ifndef BLINK_DEBUG_H_ #define BLINK_DEBUG_H_ #include #include "blink/fds.h" #include "blink/types.h" void DumpHex(u8 *, size_t); void PrintFds(struct Fds *); i64 ReadWordSafely(int, u8 *); const char *DescribeProt(int); const char *DescribeMopcode(int); const char *DescribeCpuFlags(int); const char *GetBlinkBacktrace(void); #endif /* BLINK_DEBUG_H_ */ ================================================ FILE: blink/debug2.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/dis.h" #include "blink/dll.h" #include "blink/elf.h" #include "blink/endian.h" #include "blink/fspath.h" #include "blink/loader.h" #include "blink/machine.h" #include "blink/map.h" #include "blink/overlays.h" #include "blink/util.h" #include "blink/vfs.h" #define READ32(p) Read32((const u8 *)(p)) static void LoadFileMapSymbols(struct System *s, struct FileMap *fm) { int fd; i64 base; void *map; char *path; int oflags; struct stat st; char pathdbg[PATH_MAX]; if (fm->offset) return; oflags = O_RDONLY | O_CLOEXEC | O_NOCTTY; snprintf(pathdbg, sizeof(pathdbg), "%s.dbg", fm->path); if ((fd = VfsOpen(AT_FDCWD, (path = pathdbg), oflags, 0)) != -1 || (fd = VfsOpen(AT_FDCWD, (path = fm->path), oflags, 0)) != -1) { if (VfsFstat(fd, &st) != -1 && (map = Mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0, "debug")) != MAP_FAILED) { if (st.st_size >= sizeof(Elf64_Ehdr_) && READ32(map) == READ32("\177ELF") && GetElfMemorySize((Elf64_Ehdr_ *)map, st.st_size, &base) != -1) { DisLoadElf(s->dis, (Elf64_Ehdr_ *)map, st.st_size, fm->virt - base); if (s->onsymbols) { s->onsymbols(s); } } else { ELF_LOGF("%s: not a valid elf image", path); } unassert(!Munmap(map, st.st_size)); } else { ELF_LOGF("%s: mmap failed: %s", path, DescribeHostErrno(errno)); } unassert(!VfsClose(fd)); } else { ELF_LOGF("%s: open failed: %s", path, DescribeHostErrno(errno)); } } void LoadDebugSymbols(struct System *s) { struct Dll *e; unassert(s->dis); s->onfilemap = LoadFileMapSymbols; for (e = dll_first(s->filemaps); e; e = dll_next(s->filemaps, e)) { LoadFileMapSymbols(s, FILEMAP_CONTAINER(e)); } } ================================================ FILE: blink/demangle.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/debug.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/sigwinch.h" #include "blink/thread.h" #include "blink/util.h" struct CxxFilt { pthread_once_t_ once; pthread_mutex_t_ lock; int reader; int writer; int pid; } g_cxxfilt = { PTHREAD_ONCE_INIT_, }; static void InitCxxFilt(void) { pthread_mutexattr_t attr; unassert(!pthread_mutexattr_init(&attr)); unassert(!pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)); unassert(!pthread_mutex_init(&g_cxxfilt.lock, &attr)); unassert(!pthread_mutexattr_destroy(&attr)); } static void CloseCxxFiltUnlocked(void) { sigset_t ss, oldss; if (g_cxxfilt.pid > 0) { LOGF("closing pipe to c++filt"); unassert(!sigemptyset(&ss)); unassert(!sigaddset(&ss, SIGCHLD)); unassert(!pthread_sigmask(SIG_BLOCK, &ss, &oldss)); unassert(!close(g_cxxfilt.writer)); unassert(waitpid(g_cxxfilt.pid, 0, 0) == g_cxxfilt.pid); unassert(!close(g_cxxfilt.reader)); unassert(!pthread_sigmask(SIG_SETMASK, &oldss, 0)); g_cxxfilt.pid = -1; } } static void CloseCxxFilt(void) { LOCK(&g_cxxfilt.lock); CloseCxxFiltUnlocked(); UNLOCK(&g_cxxfilt.lock); } static void CxxFiltBeforeFork(void) { LOGF("CxxFiltBeforeFork"); LOCK(&g_cxxfilt.lock); } static void CxxFiltAfterForkChild(void) { LOGF("CxxFiltAfterForkChild"); if (g_cxxfilt.pid > 0) { unassert(!close(g_cxxfilt.writer)); unassert(!close(g_cxxfilt.reader)); g_cxxfilt.pid = 0; } UNLOCK(&g_cxxfilt.lock); } static void CxxFiltAfterForkParent(void) { LOGF("CxxFiltAfterForkParent"); UNLOCK(&g_cxxfilt.lock); } static void SpawnCxxFilt(void) { sigset_t ss; const char *cxxfilt; char executable[PATH_MAX]; int pipefds[2][2] = {{-1, -1}, {-1, -1}}; cxxfilt = getenv("CXXFILT"); if (cxxfilt && !*cxxfilt) { LOGF("$CXXFILT was empty string, disabling c++ demangling"); g_cxxfilt.pid = -1; return; } if (!cxxfilt) cxxfilt = "c++filt"; if (!Commandv(cxxfilt, executable, sizeof(executable))) { LOGF("path lookup of $CXXFILT (%s) failed!", cxxfilt); g_cxxfilt.pid = -1; return; } LOGF("spawning c++ symbol demangler %s", executable); if (pipe(pipefds[1]) == -1 || // pipe(pipefds[0]) == -1 || // (g_cxxfilt.pid = fork()) == -1) { LOGF("can't launch c++ demangler: %s", DescribeHostErrno(errno)); close(pipefds[0][0]); close(pipefds[0][1]); close(pipefds[1][0]); close(pipefds[1][1]); g_cxxfilt.pid = -1; return; } if (!g_cxxfilt.pid) { unassert(!sigemptyset(&ss)); unassert(!sigaddset(&ss, SIGINT)); unassert(!sigaddset(&ss, SIGQUIT)); unassert(!sigaddset(&ss, SIGWINCH)); unassert(!pthread_sigmask(SIG_BLOCK, &ss, 0)); unassert(dup2(pipefds[1][0], 0) == 0); unassert(dup2(pipefds[0][1], 1) == 1); if (pipefds[0][0] > 1) unassert(!close(pipefds[0][0])); if (pipefds[0][1] > 1) unassert(!close(pipefds[0][1])); if (pipefds[1][0] > 1) unassert(!close(pipefds[1][0])); if (pipefds[1][1] > 1) unassert(!close(pipefds[1][1])); execv(executable, (char *const[]){(char *)cxxfilt, 0}); _exit(EXIT_FAILURE_EXEC_FAILED); } unassert(!close(pipefds[0][1])); unassert(!close(pipefds[1][0])); g_cxxfilt.reader = fcntl(pipefds[0][0], F_DUPFD_CLOEXEC, kMinBlinkFd); unassert(g_cxxfilt.reader != -1); unassert(!close(pipefds[0][0])); g_cxxfilt.writer = fcntl(pipefds[1][1], F_DUPFD_CLOEXEC, kMinBlinkFd); unassert(g_cxxfilt.writer != -1); unassert(!close(pipefds[1][1])); unassert(!atexit(CloseCxxFilt)); unassert(!pthread_atfork(CxxFiltBeforeFork, // CxxFiltAfterForkParent, // CxxFiltAfterForkChild)); } static char *CopySymbol(char *p, size_t pn, const char *s, size_t sn) { size_t extra; bool showdots, iscomplicated; unassert(pn >= 1 + 3 + 1 + 1); iscomplicated = memchr(s, ' ', sn) || memchr(s, '(', sn); extra = 1; if (iscomplicated) extra += 2; if (sn + extra > pn) { sn = pn - extra - 3; showdots = true; } else { showdots = false; } if (iscomplicated) *p++ = '"'; if (sn) { memcpy(p, s, sn); p = p + sn; } if (showdots) p = stpcpy(p, "..."); if (iscomplicated) *p++ = '"'; *p = '\0'; return p; } static char *DemangleCxxFilt(char *p, size_t pn, const char *s, size_t sn) { char *res; ssize_t rc; size_t got; struct iovec iov[2]; static char buf[1024]; buf[0] = '\n'; iov[0].iov_base = (void *)s; iov[0].iov_len = sn; iov[1].iov_base = buf; iov[1].iov_len = 1; if (writev(g_cxxfilt.writer, iov, ARRAYLEN(iov)) != -1) { if ((rc = read(g_cxxfilt.reader, buf, sizeof(buf))) != -1) { got = rc; if (got >= 2 && buf[got - 1] == '\n') { if (buf[got - 2] == '\r') --got; --got; res = CopySymbol(p, pn, buf, got); } else { LOGF("c++filt read didn't end with a newline!"); res = 0; } } else { LOGF("failed to read from c++filt pipe: %s", DescribeHostErrno(errno)); res = 0; } } else { LOGF("failed to write to c++filt pipe: %s", DescribeHostErrno(errno)); res = 0; } return res; } /** * Decrypts C++ symbol. * * This function turns C++ symbols from their linkable name (e.g. * `_ZN15set_early_dwarfD1Ev`) into a readable name (e.g. * `set_early_dwarf::~set_early_dwarf()`). If the symbol in question * isn't from a C++ program, then the symbol is simply copied to the * output. The same applies if the translation fails, which means this * function always succeeds. * * Filtering is performed by piping symbols to the `c++filt` command. If * this program isn't on the `$PATH` or has a different name, then that * name or path may be set using the `$CXXFILT` environment variable. If * this environment variable is present and contains an empty string, * then C++ symbol translation will be disabled. * * @param p is output buffer * @param symbol is nul-terminated link-time symbol to translate * @param n is the number of bytes available in `p` * @return pointer to NUL byte, cf. stcpy() */ char *Demangle(char *p, const char *symbol, size_t n) { int cs; char *r; size_t sn; sigset_t ss, oldss; sn = strlen(symbol); if (StartsWith(symbol, "_Z")) { #ifdef HAVE_PTHREAD_SETCANCELSTATE unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs)); #endif unassert(!pthread_once_(&g_cxxfilt.once, InitCxxFilt)); LOCK(&g_cxxfilt.lock); if (g_cxxfilt.pid != -1) { unassert(!sigemptyset(&ss)); unassert(!sigaddset(&ss, SIGINT)); unassert(!sigaddset(&ss, SIGALRM)); unassert(!sigaddset(&ss, SIGWINCH)); unassert(!pthread_sigmask(SIG_BLOCK, &ss, &oldss)); if (!g_cxxfilt.pid) { SpawnCxxFilt(); } if (g_cxxfilt.pid != -1) { r = DemangleCxxFilt(p, n, symbol, sn); if (!r) { CloseCxxFiltUnlocked(); } } else { r = 0; } unassert(!pthread_sigmask(SIG_SETMASK, &oldss, 0)); } else { r = 0; } UNLOCK(&g_cxxfilt.lock); #ifdef HAVE_PTHREAD_SETCANCELSTATE unassert(!pthread_setcancelstate(cs, 0)); #endif } else { r = 0; } if (!r) { r = CopySymbol(p, n, symbol, sn); } return r; } ================================================ FILE: blink/deps.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/flags.h" #include "blink/rde.h" #include "blink/x86.h" static bool IsJump(u64 rde) { int op = Mopcode(rde); return op == 0x0E9 || // jmp Jvds op == 0x0EB || // jmp Jbs op == 0x0E8; // call Jvds } static bool IsConditionalJump(u64 rde) { int op = Mopcode(rde); return (0x070 <= op && op <= 0x07F) || // Jcc Jbs (0x180 <= op && op <= 0x18F); // Jcc Jvds } static int CrawlFlags(struct Machine *m, // i64 pc, // int myflags, // int look, // int depth) { u64 place; int need, deps; for (need = 0;;) { place = pc; SPX_LOGF("%" PRIx64 " %*s%s", pc, depth * 2, "", DescribeOp(m, pc)); if (LoadInstruction2(m, place)) { WriteCod("/\tfailed to speculate instruction at %" PRIx64 "\n", place); return -1; } pc += Oplength(m->xedd->op.rde); deps = GetFlagDeps(m->xedd->op.rde); if (deps) { WriteCod("/\top at %" PRIx64 " needs %s\n", place, DescribeCpuFlags(deps)); } need |= deps & myflags; if (!(myflags &= ~GetFlagClobbers(m->xedd->op.rde))) { return need; } else if (!--look) { WriteCod("/\tgiving up on speculation\n"); return -1; } else if (IsJump(m->xedd->op.rde)) { pc += m->xedd->op.disp; } else if (IsConditionalJump(m->xedd->op.rde)) { need |= CrawlFlags(m, pc + m->xedd->op.disp, myflags, look, depth + 1); if (need == -1) return -1; } else if (ClassifyOp(m->xedd->op.rde) != kOpNormal) { WriteCod("/\tspeculated abnormal op at %" PRIx64 "\n", place); return -1; } } } // returns bitset of flags read by code at pc, or -1 if unknown int GetNeededFlags(struct Machine *m, i64 pc, int myflags) { int rc = CrawlFlags(m, pc, myflags, 32, 0); WriteCod("/\t%" PRIx64 " needs flags %s\n", pc, DescribeCpuFlags(rc)); return rc; } // returns bitset of flags set or undefined by operation int GetFlagClobbers(u64 rde) { switch (Mopcode(rde)) { default: return 0; case 0xE8: // call case 0xC3: // ret if (Rep(rde)) { return 0; } else { return -1; } case 0x105: // syscall return -1; case 0x000: // add byte case 0x001: // add word case 0x002: // add byte flip case 0x003: // add word flip case 0x004: // add %al $ib case 0x005: // add %rax $ivds case 0x008: // or byte case 0x009: // or word case 0x00A: // or byte flip case 0x00B: // or word flip case 0x00C: // or %al $ib case 0x00D: // or %rax $ivds case 0x010: // adc byte case 0x011: // adc word case 0x012: // adc byte flip case 0x013: // adc word flip case 0x014: // adc %al $ib case 0x015: // adc %rax $ivds case 0x018: // sbb byte case 0x019: // sbb word case 0x01A: // sbb byte flip case 0x01B: // sbb word flip case 0x01C: // sbb %al $ib case 0x01D: // sbb %rax $ivds case 0x020: // and byte case 0x021: // and word case 0x022: // and byte flip case 0x023: // and word flip case 0x024: // and %al $ib case 0x025: // and %rax $ivds case 0x028: // sub byte case 0x029: // sub word case 0x02A: // sub byte flip case 0x02B: // sub word flip case 0x02C: // sub %al $ib case 0x02D: // sub %rax $ivds case 0x030: // xor byte case 0x031: // xor word case 0x032: // xor byte flip case 0x033: // xor word flip case 0x034: // xor %al $ib case 0x035: // xor %rax $ivds case 0x038: // cmp byte case 0x039: // cmp word case 0x03A: // cmp byte flip case 0x03B: // cmp word flip case 0x03C: // cmp %al $ib case 0x03D: // cmp %rax $ivds case 0x080: // alubireg case 0x081: // aluwireg case 0x082: // alubireg case 0x083: // aluwireg case 0x084: // alubtest case 0x085: // aluwtest case 0x0A6: // cmps case 0x0A7: // cmps case 0x0A8: // test %al $ib case 0x0A9: // test %rax $ivds case 0x0AE: // scas case 0x0AF: // scas case 0x069: // imul case 0x06B: // Imul case 0x1AF: // imul case 0x12E: // comisd case 0x12F: // comisd case 0x1A4: // shld $ib case 0x1A5: // shld %cl case 0x1AC: // shrd $ib case 0x1AD: // shrd %cl case 0x1B0: // cmpxchg byte case 0x1B1: // cmpxchg word case 0x1BC: // bsf case 0x1BD: // bsr case 0x1C0: // xadd byte case 0x1C1: // xadd word case 0x02F: // das case 0x037: // aaa case 0x03F: // aas case 0x0D5: // aad return CF | ZF | SF | OF | AF | PF; case 0x0C0: // bsu $ib byte case 0x0C1: // bsu $ib word case 0x0D0: // bsu $1 byte case 0x0D1: // bsu $1 word case 0x0D2: // bsu %cl byte case 0x0D3: // bsu %cl word switch (ModrmReg(rde)) { case 0: // rol case 1: // ror case 2: // rcl case 3: // rcr return OF | CF; case 4: // shl case 5: // shr case 6: // sal case 7: // sar return CF | ZF | SF | OF | AF | PF; default: __builtin_unreachable(); } case 0x0DB: // fpu case 0x0DF: // fpu if (IsModrmRegister(rde) && (ModrmReg(rde) == 5 || ModrmReg(rde) == 6)) { return OF | SF | AF; // fucomip, fcomip } else { return 0; } case 0x0F5: // cmc case 0x0F8: // clc case 0x0F9: // stc return CF; case 0x0F6: // 0f6 case 0x0F7: // 0f7 switch (ModrmReg(rde)) { case 2: // not return 0; case 0: // test case 1: // test case 3: // neg case 4: // mul case 5: // imul case 6: // div case 7: // idiv return CF | ZF | SF | OF | AF | PF; default: __builtin_unreachable(); } case 0x0FE: case 0x0FF: switch (ModrmReg(rde)) { case 0: // inc case 1: // dec return ZF | SF | OF | AF | PF; case 2: // call *Ev case 3: // callf *Ev return -1; default: // call, jmp, jmpf, push return 0; } case 0x1A3: // bit bt case 0x1AB: // bit bts case 0x1B3: // bit btr case 0x1BA: // bit case 0x1BB: // bit return CF | SF | OF | AF | PF; case 0x09E: // sahf return CF | ZF | SF | AF | PF; case 0x09D: // popf return 0x00ffffff; case 0x1b8: if (Rep(rde) == 3) { return CF | ZF | SF | OF | PF; // popcnt } else { return 0; } case 0x2f5: if (Rep(rde)) { return 0; // pdep, pext } else if (!Osz(rde)) { return CF | ZF | SF | OF | AF | PF; // bzhi } else { return 0; } case 0x2f6: if (Osz(rde)) { return CF; // adcx } else if (Rep(rde) == 3) { return OF; // adox } else { return 0; } } } // returns bitset of flags read by operation int GetFlagDeps(u64 rde) { switch (Mopcode(rde)) { default: return 0; case 0x010: // adc byte case 0x011: // adc word case 0x012: // adc byte flip case 0x013: // adc word flip case 0x014: // adc %al $ib case 0x015: // adc %rax $ivds case 0x018: // sbb byte case 0x019: // sbb word case 0x01A: // sbb byte flip case 0x01B: // sbb word flip case 0x01C: // sbb %al $ib case 0x01D: // sbb %rax $ivds case 0x072: // jb case 0x073: // jae case 0x142: // cmovb case 0x143: // cmovnb case 0x182: // jb case 0x183: // jae case 0x192: // setb case 0x193: // setae case 0x0D6: // salc case 0x0F5: // cmc return CF; case 0x070: // jo case 0x071: // jno case 0x140: // cmovo case 0x141: // cmovno case 0x180: // jo case 0x181: // jno case 0x190: // seto case 0x191: // setno case 0x0CE: // into return OF; case 0x074: // je case 0x075: // jne case 0x144: // cmove case 0x145: // cmovne case 0x184: // je case 0x185: // jne case 0x194: // sete case 0x195: // setne case 0x0E0: // loopne case 0x0E1: // loope return ZF; case 0x076: // jbe case 0x077: // ja case 0x146: // cmovbe case 0x147: // cmova case 0x186: // jbe case 0x187: // ja case 0x196: // setbe case 0x197: // seta return CF | ZF; case 0x078: // js case 0x079: // jns case 0x148: // cmovs case 0x149: // cmovns case 0x188: // js case 0x189: // jns case 0x198: // sets case 0x199: // setns return SF; case 0x07A: // jp case 0x07B: // jnp case 0x14A: // cmovp case 0x14B: // cmovnp case 0x18A: // jp case 0x18B: // jnp case 0x19A: // setp case 0x19B: // setnp return PF; case 0x07C: // jl case 0x07D: // jge case 0x14C: // cmovl case 0x14D: // cmovge case 0x18C: // jl case 0x18D: // jge case 0x19C: // setl case 0x19D: // setge return OF | SF; case 0x07E: // jle case 0x07F: // jg case 0x14E: // cmovle case 0x14F: // cmovg case 0x18E: // jle case 0x18F: // jg case 0x19E: // setle case 0x19F: // setg return OF | SF | ZF; case 0x080: // alu byte $ib case 0x081: // alu word $iw case 0x082: // alu byte $ib case 0x083: // alu word $ibs case 0x0C0: // bsu byte $ib case 0x0C1: // bsu word $ib case 0x0D0: // bsu byte $1 case 0x0D1: // bsu word $1 case 0x0D2: // bsu byte %cl case 0x0D3: // bsu word %cl switch (ModrmReg(rde)) { case 2: // adc, rcl case 3: // sbb, rcr return CF; default: return 0; } case 0x0DA: // fpu case 0x0DB: // fpu switch (ModrmReg(rde)) { case 0: // fcmovb return CF; case 1: // fcmove case 2: // fcmovbe return ZF; case 3: // fcmovu return PF; default: return 0; } case 0x09F: // lahf return CF | ZF | SF | AF | PF; case 0x02F: // das case 0x037: // aaa return CF | AF; case 0x09C: // pushf return 0x00ffffff; case 0x2f6: if (Osz(rde)) { return CF; // adcx } else if (Rep(rde) == 3) { return OF; // adox } else { return 0; } } } int ClassifyOp(u64 rde) { switch (Mopcode(rde)) { default: return kOpNormal; case 0x070: // OpJo case 0x071: // OpJno case 0x072: // OpJb case 0x073: // OpJae case 0x074: // OpJe case 0x075: // OpJne case 0x076: // OpJbe case 0x077: // OpJa case 0x078: // OpJs case 0x079: // OpJns case 0x07A: // OpJp case 0x07B: // OpJnp case 0x07C: // OpJl case 0x07D: // OpJge case 0x07E: // OpJle case 0x07F: // OpJg case 0x09A: // OpCallf case 0x0C2: // OpRetIw case 0x0C3: // OpRet case 0x0CA: // OpRetf case 0x0CB: // OpRetf case 0x0E0: // OpLoopne case 0x0E1: // OpLoope case 0x0E2: // OpLoop1 case 0x0E3: // OpJcxz case 0x0E8: // OpCallJvds case 0x0E9: // OpJmp case 0x0EA: // OpJmpf case 0x0EB: // OpJmp case 0x0CF: // OpIret case 0x180: // OpJo case 0x181: // OpJno case 0x182: // OpJb case 0x183: // OpJae case 0x184: // OpJe case 0x185: // OpJne case 0x186: // OpJbe case 0x187: // OpJa case 0x188: // OpJs case 0x189: // OpJns case 0x18A: // OpJp case 0x18B: // OpJnp case 0x18C: // OpJl case 0x18D: // OpJge case 0x18E: // OpJle case 0x18F: // OpJg return kOpBranching; case 0x0FF: // Op0ff switch (ModrmReg(rde)) { case 2: // call *Ev case 3: // lcall *Ev case 4: // jmp *Ev case 5: // ljmp *Ev return kOpBranching; default: return kOpNormal; } case 0x0F1: // OpInterrupt1 case 0x0CC: // OpInterrupt3 case 0x0CD: // OpInterruptImm case 0x105: // OpSyscall // precious ops are excluded from jit pathmaking entirely. not // doing this would be inviting disaster, since system calls and // longjmp could do anything. for example, we don't want clone() // to fork a jit path under construction. return kOpPrecious; case 0x130: // OpWrmsr case 0x1A2: // OpCpuid return kOpSerializing; case 0x1AE: switch (ModrmReg(rde)) { case 5: // lfence case 6: // mfence return kOpSerializing; default: return kOpNormal; } } } ================================================ FILE: blink/describeflags.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/describeflags.h" #include const char *DescribeFlagz(char *p, size_t n, const struct DescribeFlagz *d, size_t m, const char *prefix, unsigned x) { bool t; char b[21]; size_t i, j, k; for (t = false, i = j = 0; j < m; ++j) { if (d[j].flag && d[j].flag != -1u && (x & d[j].flag) == d[j].flag) { x &= ~d[j].flag; if (t) { if (i + 1 < n) p[i++] = '|'; } else { t = true; } for (k = 0; prefix && prefix[k]; ++k) { if (i + 1 < n) p[i++] = prefix[k]; } for (k = 0; d[j].name[k]; ++k) { if (i + 1 < n) p[i++] = d[j].name[k]; } } } if (x || !t) { if (t && i + 1 < n) p[i++] = '|'; if (i + 1 < n) p[i++] = '0'; if (x) { if (i + 1 < n) p[i++] = 'x'; k = 0; do { if (i + 1 < n) b[k++] = "0123456789abcdef"[x % 16]; } while ((x /= 16)); while (k--) { if (i + 1 < n) p[i++] = b[k]; } } } if (i < n) p[i] = 0; return p; } ================================================ FILE: blink/describeflags.h ================================================ #ifndef BLINK_DESCRIBEFLAGS_H_ #define BLINK_DESCRIBEFLAGS_H_ #include #include "blink/builtin.h" struct DescribeFlagz { unsigned flag; const char *name; }; const char *DescribeFlagz(char *, size_t, const struct DescribeFlagz *, size_t, const char *, unsigned); #endif /* BLINK_DESCRIBEFLAGS_H_ */ ================================================ FILE: blink/describehosterrno.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/thread.h" #include "blink/util.h" const char *DescribeHostErrno(int x) { _Thread_local static char buf[21]; if (x == EPERM) return "EPERM"; if (x == ENOENT) return "ENOENT"; if (x == ESRCH) return "ESRCH"; if (x == EINTR) return "EINTR"; if (x == EIO) return "EIO"; if (x == ENXIO) return "ENXIO"; if (x == E2BIG) return "E2BIG"; if (x == ENOEXEC) return "ENOEXEC"; if (x == EBADF) return "EBADF"; if (x == ECHILD) return "ECHILD"; if (x == EAGAIN) return "EAGAIN"; #if EWOULDBLOCK != EAGAIN if (x == EWOULDBLOCK) return "EWOULDBLOCK"; #endif if (x == ENOMEM) return "ENOMEM"; if (x == EACCES) return "EACCES"; if (x == EFAULT) return "EFAULT"; #ifdef ENOTBLK if (x == ENOTBLK) return "ENOTBLK"; #endif if (x == EBUSY) return "EBUSY"; if (x == EEXIST) return "EEXIST"; if (x == EXDEV) return "EXDEV"; if (x == ENODEV) return "ENODEV"; if (x == ENOTDIR) return "ENOTDIR"; if (x == EISDIR) return "EISDIR"; if (x == EINVAL) return "EINVAL"; if (x == ENFILE) return "ENFILE"; if (x == EMFILE) return "EMFILE"; if (x == ENOTTY) return "ENOTTY"; if (x == ETXTBSY) return "ETXTBSY"; if (x == EFBIG) return "EFBIG"; if (x == ENOSPC) return "ENOSPC"; if (x == ESPIPE) return "ESPIPE"; if (x == EROFS) return "EROFS"; if (x == EMLINK) return "EMLINK"; if (x == EPIPE) return "EPIPE"; if (x == EDOM) return "EDOM"; if (x == ERANGE) return "ERANGE"; if (x == EDEADLK) return "EDEADLK"; if (x == ENAMETOOLONG) return "ENAMETOOLONG"; if (x == ENOLCK) return "ENOLCK"; if (x == ENOSYS) return "ENOSYS"; if (x == ENOTEMPTY) return "ENOTEMPTY"; if (x == ELOOP) return "ELOOP"; if (x == ENOMSG) return "ENOMSG"; if (x == EIDRM) return "EIDRM"; #ifdef EREMOTE if (x == EREMOTE) return "EREMOTE"; #endif if (x == EPROTO) return "EPROTO"; if (x == EBADMSG) return "EBADMSG"; if (x == EOVERFLOW) return "EOVERFLOW"; if (x == EILSEQ) return "EILSEQ"; #ifdef EUSERS if (x == EUSERS) return "EUSERS"; #endif if (x == ENOTSOCK) return "ENOTSOCK"; if (x == EDESTADDRREQ) return "EDESTADDRREQ"; if (x == EMSGSIZE) return "EMSGSIZE"; if (x == EPROTOTYPE) return "EPROTOTYPE"; if (x == ENOPROTOOPT) return "ENOPROTOOPT"; if (x == EPROTONOSUPPORT) return "EPROTONOSUPPORT"; #ifdef ESOCKTNOSUPPORT if (x == ESOCKTNOSUPPORT) return "ESOCKTNOSUPPORT"; #endif if (x == ENOTSUP) return "ENOTSUP"; #if EOPNOTSUPP != ENOTSUP if (x == EOPNOTSUPP) return "EOPNOTSUPP"; #endif #ifdef EPFNOSUPPORT if (x == EPFNOSUPPORT) return "EPFNOSUPPORT"; #endif if (x == EAFNOSUPPORT) return "EAFNOSUPPORT"; if (x == EADDRINUSE) return "EADDRINUSE"; if (x == EADDRNOTAVAIL) return "EADDRNOTAVAIL"; if (x == ENETDOWN) return "ENETDOWN"; if (x == ENETUNREACH) return "ENETUNREACH"; if (x == ENETRESET) return "ENETRESET"; if (x == ECONNABORTED) return "ECONNABORTED"; if (x == ECONNRESET) return "ECONNRESET"; if (x == ENOBUFS) return "ENOBUFS"; if (x == EISCONN) return "EISCONN"; if (x == ENOTCONN) return "ENOTCONN"; #ifdef ESHUTDOWN if (x == ESHUTDOWN) return "ESHUTDOWN"; #endif #ifdef ETOOMANYREFS if (x == ETOOMANYREFS) return "ETOOMANYREFS"; #endif if (x == ETIMEDOUT) return "ETIMEDOUT"; if (x == ECONNREFUSED) return "ECONNREFUSED"; #ifdef EHOSTDOWN if (x == EHOSTDOWN) return "EHOSTDOWN"; #endif if (x == EHOSTUNREACH) return "EHOSTUNREACH"; if (x == EALREADY) return "EALREADY"; if (x == EINPROGRESS) return "EINPROGRESS"; if (x == ESTALE) return "ESTALE"; if (x == EDQUOT) return "EDQUOT"; if (x == ECANCELED) return "ECANCELED"; #ifdef EOWNERDEAD if (x == EOWNERDEAD) return "EOWNERDEAD"; #endif #ifdef ENOTRECOVERABLE if (x == ENOTRECOVERABLE) return "ENOTRECOVERABLE"; #endif #ifdef ETIME if (x == ETIME) return "ETIME"; #endif #ifdef ENONET if (x == ENONET) return "ENONET"; #endif #ifdef ERESTART if (x == ERESTART) return "ERESTART"; #endif #ifdef ENOSR if (x == ENOSR) return "ENOSR"; #endif #ifdef ENOSTR if (x == ENOSTR) return "ENOSTR"; #endif #ifdef ENODATA if (x == ENODATA) return "ENODATA"; #endif #ifdef EMULTIHOP if (x == EMULTIHOP) return "EMULTIHOP"; #endif #ifdef ENOLINK if (x == ENOLINK) return "ENOLINK"; #endif #ifdef ENOMEDIUM if (x == ENOMEDIUM) return "ENOMEDIUM"; #endif #ifdef EMEDIUMTYPE if (x == EMEDIUMTYPE) return "EMEDIUMTYPE"; #endif FormatInt64(buf, x); return buf; } ================================================ FILE: blink/describeprot.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/debug.h" #include "blink/thread.h" #include "blink/util.h" const char *DescribeProt(int prot) { char *p; bool gotsome; _Thread_local static char buf[64]; if (!prot) return "PROT_NONE"; p = buf; gotsome = false; if (prot & PROT_READ) { if (gotsome) *p++ = '|'; p = stpcpy(p, "PROT_READ"); prot &= ~PROT_READ; gotsome = true; } if (prot & PROT_WRITE) { if (gotsome) *p++ = '|'; p = stpcpy(p, "PROT_WRITE"); prot &= ~PROT_WRITE; gotsome = true; } if (prot & PROT_EXEC) { if (gotsome) *p++ = '|'; p = stpcpy(p, "PROT_EXEC"); prot &= ~PROT_EXEC; gotsome = true; } if (prot) { if (gotsome) *p++ = '|'; p = FormatInt64(p, prot); } return buf; } ================================================ FILE: blink/describesignal.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/linux.h" #include "blink/thread.h" #include "blink/util.h" // @asyncsignalsafe const char *DescribeSignal(int sig) { char *p; _Thread_local static char buf[30]; switch (sig) { case SIGHUP_LINUX: return "SIGHUP"; case SIGINT_LINUX: return "SIGINT"; case SIGQUIT_LINUX: return "SIGQUIT"; case SIGILL_LINUX: return "SIGILL"; case SIGTRAP_LINUX: return "SIGTRAP"; case SIGABRT_LINUX: return "SIGABRT"; case SIGBUS_LINUX: return "SIGBUS"; case SIGFPE_LINUX: return "SIGFPE"; case SIGKILL_LINUX: return "SIGKILL"; case SIGUSR1_LINUX: return "SIGUSR1"; case SIGSEGV_LINUX: return "SIGSEGV"; case SIGUSR2_LINUX: return "SIGUSR2"; case SIGPIPE_LINUX: return "SIGPIPE"; case SIGALRM_LINUX: return "SIGALRM"; case SIGTERM_LINUX: return "SIGTERM"; case SIGSTKFLT_LINUX: return "SIGSTKFLT"; case SIGCHLD_LINUX: return "SIGCHLD"; case SIGCONT_LINUX: return "SIGCONT"; case SIGSTOP_LINUX: return "SIGSTOP"; case SIGTSTP_LINUX: return "SIGTSTP"; case SIGTTIN_LINUX: return "SIGTTIN"; case SIGTTOU_LINUX: return "SIGTTOU"; case SIGURG_LINUX: return "SIGURG"; case SIGXCPU_LINUX: return "SIGXCPU"; case SIGXFSZ_LINUX: return "SIGXFSZ"; case SIGVTALRM_LINUX: return "SIGVTALRM"; case SIGPROF_LINUX: return "SIGPROF"; case SIGWINCH_LINUX: return "SIGWINCH"; case SIGIO_LINUX: return "SIGIO"; case SIGSYS_LINUX: return "SIGSYS"; case SIGINFO_LINUX: return "SIGINFO"; case SIGPWR_LINUX: return "SIGPWR"; default: break; } p = buf; if (SIGRTMIN_LINUX <= sig && sig <= SIGRTMAX_LINUX) { p = stpcpy(p, "SIGRTMIN+"); p = FormatInt64(p, sig - SIGRTMIN_LINUX); } else { p = FormatInt64(p, sig); } return buf; } ================================================ FILE: blink/devfs.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Trung Nguyen │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/devfs.h" #include #include #include "blink/errno.h" #include "blink/hostfs.h" #include "blink/log.h" #ifndef DISABLE_VFS static int DevfsInit(const char *source, u64 flags, const void *data, struct VfsDevice **device, struct VfsMount **mount) { int ret; if (source == NULL) { return efault(); } if (*source == '\0') { source = "/dev"; } VFS_LOGF("real devfs not implemented, delegating to hostfs"); if ((ret = HostfsInit(source, flags, data, device, mount)) != -1) { (*device)->ops = &g_devfs.ops; } return ret; } static int DevfsReadmountentry(struct VfsDevice *device, char **spec, char **type, char **mntops) { *spec = strdup("none"); if (*spec == NULL) { return enomem(); } *type = strdup("devtmpfs"); if (type == NULL) { free(*spec); return enomem(); } *mntops = NULL; return 0; } struct VfsSystem g_devfs = {.name = "devfs", .nodev = true, .ops = { .Init = DevfsInit, .Freeinfo = HostfsFreeInfo, .Freedevice = HostfsFreeDevice, .Finddir = HostfsFinddir, .Readmountentry = DevfsReadmountentry, .Readlink = HostfsReadlink, .Mkdir = HostfsMkdir, .Mkfifo = HostfsMkfifo, .Open = HostfsOpen, .Access = HostfsAccess, .Stat = HostfsStat, .Fstat = HostfsFstat, .Chmod = HostfsChmod, .Fchmod = HostfsFchmod, .Chown = HostfsChown, .Fchown = HostfsFchown, .Ftruncate = HostfsFtruncate, .Link = HostfsLink, .Unlink = HostfsUnlink, .Read = HostfsRead, .Write = HostfsWrite, .Pread = HostfsPread, .Pwrite = HostfsPwrite, .Readv = HostfsReadv, .Writev = HostfsWritev, .Preadv = HostfsPreadv, .Pwritev = HostfsPwritev, .Seek = HostfsSeek, .Fsync = HostfsFsync, .Fdatasync = HostfsFdatasync, .Flock = HostfsFlock, .Fcntl = HostfsFcntl, .Ioctl = HostfsIoctl, .Dup = HostfsDup, #ifdef HAVE_DUP3 .Dup3 = HostfsDup3, #endif .Poll = HostfsPoll, .Opendir = HostfsOpendir, #ifdef HAVE_SEEKDIR .Seekdir = HostfsSeekdir, .Telldir = HostfsTelldir, #endif .Readdir = HostfsReaddir, .Rewinddir = HostfsRewinddir, .Closedir = HostfsClosedir, .Bind = HostfsBind, .Connect = HostfsConnect, .Connectunix = HostfsConnectUnix, .Accept = HostfsAccept, .Listen = HostfsListen, .Shutdown = HostfsShutdown, .Recvmsg = HostfsRecvmsg, .Sendmsg = HostfsSendmsg, .Recvmsgunix = HostfsRecvmsgUnix, .Sendmsgunix = HostfsSendmsgUnix, .Getsockopt = HostfsGetsockopt, .Setsockopt = HostfsSetsockopt, .Getsockname = HostfsGetsockname, .Getpeername = HostfsGetpeername, .Rename = HostfsRename, .Utime = HostfsUtime, .Futime = HostfsFutime, .Symlink = HostfsSymlink, .Mmap = HostfsMmap, .Munmap = HostfsMunmap, .Mprotect = HostfsMprotect, .Msync = HostfsMsync, .Pipe = NULL, #ifdef HAVE_PIPE2 .Pipe2 = NULL, #endif .Socket = NULL, .Socketpair = NULL, .Tcgetattr = NULL, .Tcsetattr = NULL, .Tcflush = NULL, .Tcdrain = NULL, .Tcsendbreak = NULL, .Tcflow = NULL, .Tcgetsid = NULL, .Tcgetpgrp = NULL, .Tcsetpgrp = NULL, #ifdef HAVE_SOCKATMARK .Sockatmark = NULL, #endif .Fexecve = NULL, }}; #endif /* DISABLE_VFS */ ================================================ FILE: blink/devfs.h ================================================ #ifndef BLINK_DEVFS_H_ #define BLINK_DEVFS_H_ #include "blink/vfs.h" extern struct VfsSystem g_devfs; #endif // BLINK_DEVFS_H_ ================================================ FILE: blink/dis.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/dis.h" #include #include #include #include "blink/assert.h" #include "blink/debug.h" #include "blink/endian.h" #include "blink/high.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/types.h" #include "blink/util.h" #define ADDRLEN 8 #define BYTELEN 11 #define PFIXLEN 4 #define NAMELEN 8 #define CODELEN 40 #define CODELIM 15 #define DATALIM 8 #define PIVOTOP pos_opcode char *DisColumn(char *p2, char *p1, long need) { char *p; long have; unassert(p2 >= p1); have = p2 - p1; p = p2; do { *p++ = ' '; } while (++have < need); *p = '\0'; return p; } static char *DisOctets(char *p, const u8 *d, size_t n) { size_t i; for (i = 0; i < n; ++i) { if (i) *p++ = ','; *p++ = '0'; *p++ = 'x'; *p++ = "0123456789abcdef"[(d[i] & 0xf0) >> 4]; *p++ = "0123456789abcdef"[(d[i] & 0x0f) >> 0]; } *p = '\0'; return p; } static char *DisByte(char *p, const u8 *d, size_t n) { p = HighStart(p, g_high.keyword); p = DisColumn(stpcpy(p, ".byte"), p, NAMELEN); p = HighEnd(p); p = DisOctets(p, d, n); return p; } static char *DisError(struct Dis *d, char *p, int err) { p = DisColumn(DisByte(p, d->xedd->bytes, MIN(15, d->xedd->length)), p, CODELEN); p = HighStart(p, g_high.comment); *p++ = '#'; *p++ = ' '; p = stpcpy(p, "error"); p = HighEnd(p); *p = '\0'; return p; } static size_t uint64toarray_fixed16(u64 x, char b[17], u8 k) { char *p; unassert(k <= 64 && !(k & 3)); for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15]; *p = '\0'; return p - b; } static char *DisAddr(struct Dis *d, char *p) { i64 x = d->addr; if (0 <= x && x < 0x10fff0) { return p + uint64toarray_fixed16(x, p, 24); } else if (INT_MIN <= x && x <= INT_MAX) { return p + uint64toarray_fixed16(x, p, 32); } else { return p + uint64toarray_fixed16(x, p, 48); } } static char *DisRaw(struct Dis *d, char *p) { long i; int plen; if (0 <= d->addr && d->addr < 0x10fff0) { plen = 2; } else { plen = PFIXLEN; } for (i = 0; i < plen - MIN(plen, d->xedd->op.PIVOTOP); ++i) { *p++ = ' '; *p++ = ' '; } for (i = 0; i < MIN(15, d->xedd->length); ++i) { if (i == d->xedd->op.PIVOTOP) *p++ = ' '; *p++ = "0123456789abcdef"[(d->xedd->bytes[i] & 0xf0) >> 4]; *p++ = "0123456789abcdef"[(d->xedd->bytes[i] & 0x0f) >> 0]; } *p = '\0'; return p; } static char *DisCode(struct Dis *d, char *p, int err) { char optspecbuf[128]; if (!err) { return DisInst(d, p, DisSpec(d->xedd, optspecbuf)); } else { return DisError(d, p, err); } } static char *DisLineCode(struct Dis *d, char *p, int err) { int blen, plen; if (0 <= d->addr && d->addr < 0x10fff0) { plen = 2; blen = 6; } else { blen = BYTELEN; plen = PFIXLEN; } p = DisColumn(DisAddr(d, p), p, ADDRLEN); #ifdef HAVE_JIT if (d->m && !IsJitDisabled(&d->m->system->jit)) { uintptr_t hook; if ((hook = GetJitHook(&d->m->system->jit, d->addr))) { if (hook == (uintptr_t)JitlessDispatch) { *p++ = 'S'; // staging hook } else { *p++ = '*'; // committed jit hook } } else { *p++ = ' '; // no hook } } #else *p++ = ' '; // no hook #endif if (!d->noraw) { p = DisColumn(DisRaw(d, p), p, plen * 2 + 1 + blen * 2); } else { *p++ = ' '; *p++ = ' '; } p = DisCode(d, p, err); return p; } static char *DisLabel(struct Dis *d, char *p, const char *name) { p = DisColumn(DisAddr(d, p), p, ADDRLEN); p = HighStart(p, g_high.label); p = Demangle(p, name, DIS_MAX_SYMBOL_LENGTH); p = HighEnd(p); *p++ = ':'; *p = '\0'; return p; } long DisFind(struct Dis *d, i64 addr) { int l, r, m; l = 0; r = d->ops.i - 1; while (l <= r) { m = (l + r) >> 1; if (d->ops.p[m].addr < addr) { l = m + 1; } else if (d->ops.p[m].addr > addr) { r = m - 1; } else { return m; } } return -1; } static long DisAppendOpLines(struct Dis *d, struct Machine *m, i64 addr) { u8 *r; i64 ip; unsigned k; u8 *p, b[15]; long n, symbol; struct DisOp op; n = 15; ip = addr - m->cs.base; if ((symbol = DisFindSym(d, ip)) != -1) { if (d->syms.p[symbol].addr <= ip && ip < d->syms.p[symbol].addr + d->syms.p[symbol].size) { n = d->syms.p[symbol].size - (ip - d->syms.p[symbol].addr); } if (ip == d->syms.p[symbol].addr && d->syms.p[symbol].name) { op.addr = addr; op.size = 0; op.active = true; d->addr = addr; DisLabel(d, d->buf, d->syms.p[symbol].name); if (!(op.s = strdup(d->buf))) return -1; if (d->ops.i++ == d->ops.n) { d->ops.n = d->ops.i + (d->ops.i >> 1); d->ops.p = (struct DisOp *)realloc(d->ops.p, d->ops.n * sizeof(*d->ops.p)); } d->ops.p[d->ops.i - 1] = op; } } n = MAX(1, MIN(15, n)); if (!(r = SpyAddress(m, addr))) return -1; k = 0x1000 - (addr & 0xfff); if (n <= k) { p = (u8 *)r; } else { p = b; memcpy(b, r, k); if ((r = SpyAddress(m, addr + k))) { memcpy(b + k, r, n - k); } else { n = k; } } DecodeInstruction(d->xedd, p, n, m->mode.omode); n = d->xedd->length; op.addr = addr; op.size = n; op.active = true; op.s = NULL; if (d->ops.i++ == d->ops.n) { d->ops.n = d->ops.i + (d->ops.i >> 1); d->ops.p = (struct DisOp *)realloc(d->ops.p, d->ops.n * sizeof(*d->ops.p)); } d->ops.p[d->ops.i - 1] = op; return n; } long Dis(struct Dis *d, struct Machine *m, i64 addr, i64 ip, int lines) { i64 i, j, symbol; DisFreeOps(&d->ops); if ((symbol = DisFindSym(d, addr)) != -1 && (d->syms.p[symbol].addr < addr && addr < d->syms.p[symbol].addr + d->syms.p[symbol].size)) { for (i = d->syms.p[symbol].addr; i < addr; i += j) { if ((j = DisAppendOpLines(d, m, i)) == -1) return -1; } } for (i = 0; i < lines; ++i, addr += j) { if ((j = DisAppendOpLines(d, m, addr)) == -1) return -1; } return 0; } const char *DisGetLine(struct Dis *d, struct Machine *m, int i) { int err; if (i >= d->ops.i) return ""; if (d->ops.p[i].s) return d->ops.p[i].s; unassert(d->ops.p[i].size <= 15); err = GetInstruction(m, d->ops.p[i].addr, d->xedd); d->m = m; d->addr = d->ops.p[i].addr; if (DisLineCode(d, d->buf, err) - d->buf >= (int)sizeof(d->buf)) Abort(); return d->buf; } ================================================ FILE: blink/dis.h ================================================ #ifndef BLINK_DIS_H_ #define BLINK_DIS_H_ #include #include #include "blink/loader.h" #include "blink/types.h" #include "blink/x86.h" #define DIS_MAX_SYMBOL_LENGTH 128 struct DisOp { i64 addr; u8 size; bool active; char *s; }; struct DisOps { int i, n; struct DisOp *p; }; struct DisLoad { i64 addr; int size; bool istext; }; struct DisLoads { int i, n; struct DisLoad *p; }; struct DisSym { i64 addr; char *name; int unique; int size; char rank; bool iscode; bool isabs; }; struct DisSyms { int i, n; struct DisSym *p; }; struct DisEdge { i64 src; i64 dst; }; struct DisEdges { int i, n; struct DisEdge *p; }; struct Dis { bool notab; bool noraw; struct DisOps ops; struct DisLoads loads; struct DisSyms syms; struct DisEdges edges; struct XedDecodedInst xedd[1]; struct Machine *m; /* for the segment registers */ u64 addr; /* current effective address */ char buf[1024]; }; long Dis(struct Dis *, struct Machine *, i64, i64, int); long DisFind(struct Dis *, i64); void DisFree(struct Dis *); void DisFreeOp(struct DisOp *); void DisFreeOps(struct DisOps *); void DisLoadElf(struct Dis *, Elf64_Ehdr_ *, size_t, i64); long DisFindSym(struct Dis *, i64); long DisFindSymByName(struct Dis *, const char *); bool DisIsText(struct Dis *, i64); bool DisIsProg(struct Dis *, i64); char *DisInst(struct Dis *, char *, const char *); char *DisArg(struct Dis *, char *, const char *); const char *DisSpec(struct XedDecodedInst *, char *); const char *DisGetLine(struct Dis *, struct Machine *, int); #endif /* BLINK_DIS_H_ */ ================================================ FILE: blink/disarg.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/dis.h" #include "blink/endian.h" #include "blink/high.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/util.h" static const char kRiz[2][4] = {"eiz", "riz"}; static const char kRip[2][4] = {"eip", "rip"}; static const char kSka[4][4] = {"", ",2", ",4", ",8"}; static const char kSeg[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"}; static const char kCtl[8][4] = {"cr0", "wut", "cr2", "cr3", "cr4", "wut", "wut", "wut"}; static const char kBreg[2][2][8][5] = { {{"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}, {"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"}}, {{"wut", "wut", "wut", "wut", "wut", "wut", "wut", "wut"}, {"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"}}, }; static const char kGreg[2][2][2][8][5] = { {{{"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"}, {"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"}}, {{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"}, {"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}}, {{{"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}, {"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"}}, {{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"}, {"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}}, }; static i64 RipRelative(struct Dis *d, i64 i) { return d->addr + d->xedd->length + i; } static i64 ZeroExtend(u64 rde, i64 i) { switch (Mode(rde)) { case XED_MODE_REAL: return i & 0xffff; case XED_MODE_LEGACY: return i & 0xffffffff; default: return i; } } static i64 Unrelative(u64 rde, i64 i) { switch (Eamode(rde)) { case XED_MODE_REAL: return i & 0xffff; case XED_MODE_LEGACY: return i & 0xffffffff; default: return i; } } static const char *GetAddrReg(struct Dis *d, u64 rde, u8 x, u8 r) { return kGreg[Eamode(rde) == XED_MODE_REAL][Eamode(rde) == XED_MODE_LONG] [x & 1][r & 7]; } static char *DisRegister(char *p, const char *s) { p = HighStart(p, g_high.reg); *p++ = '%'; p = stpcpy(p, s); p = HighEnd(p); return p; } static char *DisRegisterByte(struct Dis *d, u64 rde, char *p, bool g, int r) { return DisRegister(p, kBreg[g][Rex(rde)][r]); } static char *DisRegisterWord(struct Dis *d, u64 rde, char *p, bool g, int r) { return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][g][r]); } static char *DisInt(char *p, i64 x) { if (-15 <= x && x <= 15) { p += snprintf(p, 32, "%" PRId64, x); } else if (x == INT64_MIN) { p = stpcpy(p, "-0x8000000000000000"); } else if (x < 0 && -x < 0xFFFFFFFF) { p += snprintf(p, 32, "-0x%" PRIx64, -x); } else { p += snprintf(p, 32, "0x%" PRIx64, x); } return p; } static char *DisSymImpl(struct Dis *d, char *p, i64 x, long sym) { i64 addend; const char *name; addend = x - d->syms.p[sym].addr; name = d->syms.p[sym].name; p = Demangle(p, name, DIS_MAX_SYMBOL_LENGTH); if (addend) { *p++ = '+'; p = DisInt(p, addend); } return p; } static char *DisSym(struct Dis *d, char *p, i64 value, i64 addr) { long sym; if ((sym = DisFindSym(d, addr)) != -1 && (d->syms.p[sym].name && *d->syms.p[sym].name)) { return DisSymImpl(d, p, addr, sym); } else { return DisInt(p, value); } } static char *DisSymLiteral(struct Dis *d, u64 rde, char *p, u64 addr, u64 ip) { *p++ = '$'; p = HighStart(p, g_high.literal); p = DisSym(d, p, addr, addr); p = HighEnd(p); return p; } static char *DisGvqp(struct Dis *d, u64 rde, char *p) { return DisRegisterWord(d, rde, p, Rexr(rde), ModrmReg(rde)); } static char *DisGdqp(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[0][Rexw(rde)][Rexr(rde)][ModrmReg(rde)]); } static char *DisBdqp(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[0][Rexw(rde)][Rexx(rde)][Vreg(rde)]); } static char *DisGb(struct Dis *d, u64 rde, char *p) { return DisRegisterByte(d, rde, p, Rexr(rde), ModrmReg(rde)); } static char *DisSego(struct Dis *d, u64 rde, char *p) { if (Sego(rde)) { p = DisRegister(p, kSeg[Sego(rde) - 1]); *p++ = ':'; } return p; } static bool IsRealModrmAbsolute(u64 rde) { return Eamode(rde) == XED_MODE_REAL && ModrmRm(rde) == 6 && !ModrmMod(rde); } static char *DisDisp(struct Dis *d, u64 rde, char *p) { i64 disp; if (ModrmMod(rde) == 1 || ModrmMod(rde) == 2 || IsRipRelative(rde) || IsRealModrmAbsolute(rde) || (Eamode(rde) != XED_MODE_REAL && ModrmMod(rde) == 0 && ModrmRm(rde) == 4 && SibBase(rde) == 5)) { disp = d->xedd->op.disp; if (IsRipRelative(rde)) { if (Mode(rde) == XED_MODE_LONG) { disp = RipRelative(d, disp); } else { disp = Unrelative(rde, disp); } } else if (IsRealModrmAbsolute(rde)) { disp = Unrelative(rde, disp); } p = DisSym(d, p, disp, disp); } return p; } static char *DisBis(struct Dis *d, u64 rde, char *p) { const char *base, *index, *scale; base = index = scale = NULL; if (Eamode(rde) != XED_MODE_REAL) { if (!SibExists(rde)) { if (IsRipRelative(rde)) { if (Mode(rde) == XED_MODE_LONG) { base = kRip[Eamode(rde) == XED_MODE_LONG]; } } else { base = GetAddrReg(d, rde, Rexb(rde), ModrmRm(rde)); } } else if (!SibIsAbsolute(rde)) { if (SibHasBase(rde)) { base = GetAddrReg(d, rde, Rexb(rde), SibBase(rde)); } if (SibHasIndex(rde)) { index = GetAddrReg(d, rde, Rexx(rde), SibIndex(rde)); } else if (SibScale(rde)) { index = kRiz[Eamode(rde) == XED_MODE_LONG]; } scale = kSka[SibScale(rde)]; } } else { switch (ModrmRm(rde)) { case 0: base = "bx"; index = "si"; break; case 1: base = "bx"; index = "di"; break; case 2: base = "bp"; index = "si"; break; case 3: base = "bp"; index = "di"; break; case 4: base = "si"; break; case 5: base = "di"; break; case 6: if (ModrmMod(rde)) base = "bp"; break; case 7: base = "bx"; break; default: __builtin_unreachable(); } } if (base || index) { *p++ = '('; if (base) { p = DisRegister(p, base); } if (index) { *p++ = ','; p = DisRegister(p, index); if (scale) { p = stpcpy(p, scale); } } *p++ = ')'; } *p = '\0'; return p; } static char *DisM(struct Dis *d, u64 rde, char *p) { p = DisSego(d, rde, p); p = DisDisp(d, rde, p); p = DisBis(d, rde, p); return p; } static char *DisRegMem(struct Dis *d, u64 rde, char *p, char *f(struct Dis *, u64, char *)) { if (IsModrmRegister(rde)) { return f(d, rde, p); } else { return DisM(d, rde, p); } } static char *DisE(struct Dis *d, u64 rde, char *p, char *f(struct Dis *, u64, char *, bool, int)) { if (IsModrmRegister(rde)) { return f(d, rde, p, Rexb(rde), ModrmRm(rde)); } else { return DisM(d, rde, p); } } static char *DisEb(struct Dis *d, u64 rde, char *p) { return DisE(d, rde, p, DisRegisterByte); } static char *DisEvqp(struct Dis *d, u64 rde, char *p) { return DisE(d, rde, p, DisRegisterWord); } static char *DisRv(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]); } static char *DisRvqp(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]); } static char *DisRdqp(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]); } static char *DisEdqp(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisRdqp); } static char *DisEv(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisRv); } static char *DisGvq(struct Dis *d, u64 rde, char *p, int r) { const char *s; if (Mode(rde) == XED_MODE_LONG) { s = kGreg[Osz(rde)][!Osz(rde)][Rexb(rde)][r]; } else { s = kGreg[Osz(rde)][0][Rexb(rde)][r]; } return DisRegister(p, s); } static char *DisZvq(struct Dis *d, u64 rde, char *p) { return DisGvq(d, rde, p, ModrmSrm(rde)); } static char *DisEvqReg(struct Dis *d, u64 rde, char *p) { return DisGvq(d, rde, p, ModrmRm(rde)); } static char *DisEvq(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisEvqReg); } static char *DisEdReg(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[0][0][Rexb(rde)][ModrmRm(rde)]); } static char *DisEd(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisEdReg); } static char *DisEqReg(struct Dis *d, u64 rde, char *p) { const char *r; if (Mode(rde) == XED_MODE_LONG) { r = kGreg[0][1][Rexb(rde)][ModrmRm(rde)]; } else { r = kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]; } return DisRegister(p, r); } static char *DisEq(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisEqReg); } static char *DisIndirEq(struct Dis *d, u64 rde, char *p) { *p++ = '*'; return DisEq(d, rde, p); } static char *DisZvqp(struct Dis *d, u64 rde, char *p) { return DisRegisterWord(d, rde, p, Rexb(rde), ModrmSrm(rde)); } static char *DisZb(struct Dis *d, u64 rde, char *p) { return DisRegisterByte(d, rde, p, Rexb(rde), ModrmSrm(rde)); } static char *DisEax(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[Osz(rde)][0][0][0]); } static char *DisRax(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][0]); } static char *DisRdx(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][2]); } static char *DisPort(struct Dis *d, u64 rde, char *p) { *p++ = '('; p = DisRegister(p, kGreg[1][0][0][2]); *p++ = ')'; *p = '\0'; return p; } static char *DisCd(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kCtl[ModrmReg(rde)]); } static char *DisHd(struct Dis *d, u64 rde, char *p) { return DisRegister(p, kGreg[0][Mode(rde) == XED_MODE_LONG][0][ModrmRm(rde)]); } static char *DisImm(struct Dis *d, u64 rde, char *p) { return DisSymLiteral(d, rde, p, d->xedd->op.uimm0, ZeroExtend(rde, d->xedd->op.uimm0)); } static char *DisIw(struct Dis *d, u64 rde, char *p) { return DisSymLiteral(d, rde, p, d->xedd->op.uimm0 & 0xffff, d->xedd->op.uimm0 & 0xffff); } static char *DisEnterIb(struct Dis *d, u64 rde, char *p) { return DisSymLiteral(d, rde, p, d->xedd->op.uimm0 >> 16 & 0xff, d->xedd->op.uimm0 >> 16 & 0xff); } static char *DisRvds(struct Dis *d, u64 rde, char *p) { return DisSymLiteral(d, rde, p, d->xedd->op.disp, d->xedd->op.disp); } static char *DisKpvds(struct Dis *d, u64 rde, char *p, u64 x) { *p++ = '$'; p = HighStart(p, g_high.literal); p = DisInt(p, x); p = HighEnd(p); return p; } static char *DisKvds(struct Dis *d, u64 rde, char *p) { return DisKpvds(d, rde, p, d->xedd->op.uimm0); } static char *DisPvds(struct Dis *d, u64 rde, char *p) { return DisKpvds(d, rde, p, d->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff)); } static char *DisOne(struct Dis *d, u64 rde, char *p) { *p++ = '$'; p = HighStart(p, g_high.literal); p = stpcpy(p, "1"); p = HighEnd(p); return p; } static char *DisJbs(struct Dis *d, u64 rde, char *p) { if (d->xedd->op.disp > 0) *p++ = '+'; p += snprintf(p, 32, "%" PRId64, d->xedd->op.disp); return p; } static char *DisJb(struct Dis *d, u64 rde, char *p) { if (d->xedd->op.disp > 0) *p++ = '+'; p += snprintf(p, 32, "%d", (int)(d->xedd->op.disp & 0xff)); return p; } static char *DisJvds(struct Dis *d, u64 rde, char *p) { return DisSym(d, p, RipRelative(d, d->xedd->op.disp), RipRelative(d, d->xedd->op.disp) - (d->m ? d->m->cs.base : 0)); } static char *DisAbs(struct Dis *d, u64 rde, char *p) { return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp); } static char *DisSw(struct Dis *d, u64 rde, char *p) { if (kSeg[ModrmReg(rde)][0]) p = DisRegister(p, kSeg[ModrmReg(rde)]); return p; } static char *DisSpecialAddr(struct Dis *d, u64 rde, char *p, int r) { *p++ = '('; p = DisRegister(p, GetAddrReg(d, rde, 0, r)); *p++ = ')'; *p = '\0'; return p; } static char *DisY(struct Dis *d, u64 rde, char *p) { return DisSpecialAddr(d, rde, p, 7); // es:di } static char *DisX(struct Dis *d, u64 rde, char *p) { p = DisSego(d, rde, p); return DisSpecialAddr(d, rde, p, 6); // ds:si } static char *DisBBb(struct Dis *d, u64 rde, char *p) { p = DisSego(d, rde, p); return DisSpecialAddr(d, rde, p, 3); // ds:bx } static char *DisXmm(struct Dis *d, u64 rde, char *p, const char *s, int reg) { p = HighStart(p, g_high.reg); *p++ = '%'; p = stpcpy(p, s); p += snprintf(p, 32, "%u", reg); p = HighEnd(p); return p; } static char *DisNq(struct Dis *d, u64 rde, char *p) { return DisXmm(d, rde, p, "mm", ModrmRm(rde)); } static char *DisPq(struct Dis *d, u64 rde, char *p) { return DisXmm(d, rde, p, "mm", ModrmReg(rde)); } static char *DisUq(struct Dis *d, u64 rde, char *p) { return DisXmm(d, rde, p, "xmm", RexbRm(rde)); } static char *DisUdq(struct Dis *d, u64 rde, char *p) { return DisXmm(d, rde, p, "xmm", RexbRm(rde)); } static char *DisVdq(struct Dis *d, u64 rde, char *p) { return DisXmm(d, rde, p, "xmm", RexrReg(rde)); } static char *DisQq(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisNq); } static char *DisEst(struct Dis *d, u64 rde, char *p) { p = DisRegister(p, "st"); if (ModrmRm(rde) != 0) { *p++ = '('; *p++ = '0' + ModrmRm(rde); *p++ = ')'; *p = '\0'; } return p; } static char *DisEst1(struct Dis *d, u64 rde, char *p) { if (ModrmRm(rde) != 1) { p = DisEst(d, rde, p); } else { *p = '\0'; } return p; } static char *DisEssr(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisEst); } static char *DisWps(struct Dis *d, u64 rde, char *p) { return DisRegMem(d, rde, p, DisUdq); } #define DisEdr DisM #define DisEqp DisEq #define DisEsr DisM #define DisGv DisGvqp #define DisIb DisImm #define DisIbs DisImm #define DisIbss DisImm #define DisIvds DisImm #define DisIvqp DisImm #define DisIvs DisImm #define DisMdi DisM #define DisMdq DisM #define DisMdqp DisM #define DisMdr DisM #define DisMe DisM #define DisMer DisM #define DisMp DisM #define DisMps DisM #define DisMq DisM #define DisMqi DisM #define DisMs DisM #define DisMsr DisEssr #define DisMw DisM #define DisMwi DisM #define DisOb DisAbs #define DisOvqp DisAbs #define DisPpi DisPq #define DisQpi DisQq #define DisVpd DisVdq #define DisVps DisVdq #define DisVq DisVdq #define DisVsd DisVdq #define DisVss DisVdq #define DisWdq DisWps #define DisWpd DisWps #define DisWpsq DisWps #define DisWq DisWps #define DisWsd DisWps #define DisWss DisWps #define DisXb DisX #define DisXv DisX #define DisXvqp DisX #define DisYb DisY #define DisYv DisY #define DisYvqp DisY #define DisZv DisZvqp static const struct DisArg { char s[8]; char *(*f)(struct Dis *, u64, char *); } kDisArgs[] = /* */ { {"$1", DisOne}, // {"%Bdqp", DisBdqp}, // {"%Cd", DisCd}, // {"%Gb", DisGb}, // {"%Gdqp", DisGdqp}, // {"%Gv", DisGv}, // {"%Gvqp", DisGvqp}, // {"%Hd", DisHd}, // {"%Nq", DisNq}, // {"%Ppi", DisPpi}, // {"%Pq", DisPq}, // {"%Rdqp", DisRdqp}, // {"%Rvqp", DisRvqp}, // {"%Sw", DisSw}, // {"%Udq", DisUdq}, // {"%Uq", DisUq}, // {"%Vdq", DisVdq}, // {"%Vpd", DisVpd}, // {"%Vps", DisVps}, // {"%Vq", DisVq}, // {"%Vsd", DisVsd}, // {"%Vss", DisVss}, // {"%Zb", DisZb}, // {"%Zv", DisZv}, // {"%Zvq", DisZvq}, // {"%Zvqp", DisZvqp}, // {"%eAX", DisEax}, // {"%rAX", DisRax}, // {"%rDX", DisRdx}, // {"*Eq", DisIndirEq}, // {">Ib", DisEnterIb}, // {"BBb", DisBBb}, // {"DX", DisPort}, // {"EST", DisEst}, // {"EST1", DisEst1}, // {"ESsr", DisEssr}, // {"Eb", DisEb}, // {"Ed", DisEd}, // {"Edqp", DisEdqp}, // {"Edr", DisEdr}, // {"Eq", DisEq}, // {"Eqp", DisEqp}, // {"Esr", DisEsr}, // {"Ev", DisEv}, // {"Evq", DisEvq}, // {"Evqp", DisEvqp}, // {"Ew", DisEvqp}, // {"Ib", DisIb}, // {"Ibs", DisIbs}, // {"Ibss", DisIbss}, // {"Ivds", DisIvds}, // {"Ivqp", DisIvqp}, // {"Ivs", DisIvs}, // {"Iw", DisIw}, // {"Jb", DisJb}, // {"Jbs", DisJbs}, // {"Jvds", DisJvds}, // {"Kvds", DisKvds}, // {"M", DisM}, // {"Mdi", DisMdi}, // {"Mdq", DisMdq}, // {"Mdqp", DisMdqp}, // {"Mdr", DisMdr}, // {"Me", DisMe}, // {"Mer", DisMer}, // {"Mp", DisMp}, // {"Mps", DisMps}, // {"Mq", DisMq}, // {"Mqi", DisMqi}, // {"Ms", DisMs}, // {"Msr", DisMsr}, // {"Mw", DisMw}, // {"Mwi", DisMwi}, // {"Ob", DisOb}, // {"Ovqp", DisOvqp}, // {"Pvds", DisPvds}, // {"Qpi", DisQpi}, // {"Qq", DisQq}, // {"Rvds", DisRvds}, // {"Wdq", DisWdq}, // {"Wpd", DisWpd}, // {"Wps", DisWps}, // {"Wpsq", DisWpsq}, // {"Wq", DisWq}, // {"Wsd", DisWsd}, // {"Wss", DisWss}, // {"Xb", DisXb}, // {"Xv", DisXv}, // {"Xvqp", DisXvqp}, // {"Yb", DisYb}, // {"Yv", DisYv}, // {"Yvqp", DisYvqp}, // }; static int CompareString8(const char a[8], const char b[8]) { u64 x, y; x = ((u64)(255 & a[0]) << 070 | (u64)(255 & a[1]) << 060 | (u64)(255 & a[2]) << 050 | (u64)(255 & a[3]) << 040 | (u64)(255 & a[4]) << 030 | (u64)(255 & a[5]) << 020 | (u64)(255 & a[6]) << 010 | (u64)(255 & a[7]) << 000); y = ((u64)(255 & b[0]) << 070 | (u64)(255 & b[1]) << 060 | (u64)(255 & b[2]) << 050 | (u64)(255 & b[3]) << 040 | (u64)(255 & b[4]) << 030 | (u64)(255 & b[5]) << 020 | (u64)(255 & b[6]) << 010 | (u64)(255 & b[7]) << 000); return x > y ? 1 : x < y ? -1 : 0; } char *DisArg(struct Dis *d, char *p, const char *s) { char key[8]; int c, m, l, r; l = 0; r = ARRAYLEN(kDisArgs) - 1; memset(key, 0, sizeof(key)); memcpy(key, s, MIN(8, strlen(s))); while (l <= r) { m = (l + r) >> 1; c = CompareString8(kDisArgs[m].s, key); if (c < 0) { l = m + 1; } else if (c > 0) { r = m - 1; } else { return kDisArgs[m].f(d, d->xedd->op.rde, p); } } if (*s == '%') { p = DisRegister(p, s + 1); } else { p = stpcpy(p, s); } return p; } ================================================ FILE: blink/diself.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/assert.h" #include "blink/dis.h" #include "blink/elf.h" #include "blink/endian.h" #include "blink/log.h" #include "blink/util.h" static int DisSymCompare(const void *p1, const void *p2) { const struct DisSym *a = (const struct DisSym *)p1; const struct DisSym *b = (const struct DisSym *)p2; if (a->addr != b->addr) { if (a->addr < b->addr) return -1; if (a->addr > b->addr) return +1; } if (a->rank != b->rank) { if (a->rank > b->rank) return -1; if (a->rank < b->rank) return +1; } if (a->unique != b->unique) { if (a->unique < b->unique) return -1; if (a->unique > b->unique) return +1; } return 0; } static void DisLoadElfLoads(struct Dis *d, Elf64_Ehdr_ *ehdr, size_t esize, i64 eskew) { long i; Elf64_Phdr_ *phdr; for (i = 0; i < Read16(ehdr->phnum); ++i) { phdr = GetElfProgramHeaderAddress(ehdr, esize, i); if (Read32(phdr->type) != PT_LOAD_) continue; if (d->loads.i == d->loads.n) { d->loads.n += 2; d->loads.n += d->loads.n >> 1; unassert(d->loads.p = (struct DisLoad *)realloc( d->loads.p, d->loads.n * sizeof(*d->loads.p))); } d->loads.p[d->loads.i].addr = Read64(phdr->vaddr) + eskew; d->loads.p[d->loads.i].size = Read64(phdr->memsz); d->loads.p[d->loads.i].istext = (Read32(phdr->flags) & PF_X_) == PF_X_; ++d->loads.i; } } static void DisLoadElfSyms(struct Dis *d, Elf64_Ehdr_ *ehdr, size_t esize, i64 eskew) { int n; long i; char *stab; i64 stablen; const Elf64_Sym_ *st; bool isabs, isweak, islocal, isprotected, isfunc, isobject; if ((stab = GetElfStringTable(ehdr, esize))) { if ((st = GetElfSymbolTable(ehdr, esize, &n))) { stablen = (uintptr_t)ehdr + esize - (uintptr_t)stab; for (i = 0; i < n; ++i) { if (ELF64_ST_TYPE_(st[i].info) == STT_SECTION_ || ELF64_ST_TYPE_(st[i].info) == STT_FILE_ || !Read32(st[i].name) || StartsWith(stab + Read32(st[i].name), "v_") || !(0 <= Read32(st[i].name) && Read32(st[i].name) < stablen) || !Read64(st[i].value) || !(-0x800000000000 <= (i64)Read64(st[i].value) && (i64)Read64(st[i].value) < 0x800000000000)) { continue; } isabs = Read16(st[i].shndx) == SHN_ABS_; isweak = ELF64_ST_BIND_(st[i].info) == STB_WEAK_; islocal = ELF64_ST_BIND_(st[i].info) == STB_LOCAL_; isprotected = st[i].other == STV_PROTECTED_; isfunc = ELF64_ST_TYPE_(st[i].info) == STT_FUNC_; isobject = ELF64_ST_TYPE_(st[i].info) == STT_OBJECT_; if (d->syms.i == d->syms.n) { d->syms.n += 2; d->syms.n += d->syms.n >> 1; unassert(d->syms.p = (struct DisSym *)realloc( d->syms.p, d->syms.n * sizeof(*d->syms.p))); } d->syms.p[d->syms.i].unique = i; d->syms.p[d->syms.i].size = Read64(st[i].size); unassert(d->syms.p[d->syms.i].name = strdup(stab + Read32(st[i].name))); d->syms.p[d->syms.i].addr = Read64(st[i].value) + eskew; d->syms.p[d->syms.i].rank = -islocal + -isweak + -isabs + isprotected + isobject + isfunc; d->syms.p[d->syms.i].iscode = DisIsText(d, Read64(st[i].value)) ? !isobject : isfunc; d->syms.p[d->syms.i].isabs = isabs; ++d->syms.i; } } else { LOGF("could not load elf symbol table"); } } else { LOGF("could not load elf string table"); } } static void DisSortSyms(struct Dis *d) { qsort(d->syms.p, d->syms.i, sizeof(struct DisSym), DisSymCompare); } bool DisIsProg(struct Dis *d, i64 addr) { long i; for (i = 0; i < d->loads.i; ++i) { if (addr >= d->loads.p[i].addr && addr < d->loads.p[i].addr + d->loads.p[i].size) { return true; } } return false; } bool DisIsText(struct Dis *d, i64 addr) { long i; for (i = 0; i < d->loads.i; ++i) { if (addr >= d->loads.p[i].addr && addr < d->loads.p[i].addr + d->loads.p[i].size) { return d->loads.p[i].istext; } } return false; } long DisFindSym(struct Dis *d, i64 addr) { long l, r, m; if (DisIsProg(d, addr)) { l = 0; r = d->syms.i; while (l < r) { m = (l + r) >> 1; if (d->syms.p[m].addr > addr) { r = m; } else { l = m + 1; } } // TODO(jart): This was <256 but that broke SectorLISP debugging // Why did the Cosmo binbase bootloader need this? if (r && d->syms.p[r - 1].addr < 32) { return -1; } if (r && (addr == d->syms.p[r - 1].addr || (addr > d->syms.p[r - 1].addr && (addr <= d->syms.p[r - 1].addr + d->syms.p[r - 1].size || !d->syms.p[r - 1].size)))) { return r - 1; } } return -1; } long DisFindSymByName(struct Dis *d, const char *s) { long i; for (i = 0; i < d->syms.i; ++i) { if (strcmp(s, d->syms.p[i].name) == 0) { return i; } } return -1; } void DisLoadElf(struct Dis *d, Elf64_Ehdr_ *ehdr, size_t esize, i64 eskew) { DisLoadElfLoads(d, ehdr, esize, eskew); DisLoadElfSyms(d, ehdr, esize, eskew); DisSortSyms(d); } ================================================ FILE: blink/disfree.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/dis.h" void DisFreeOp(struct DisOp *o) { free(o->s); } void DisFreeOps(struct DisOps *ops) { long i; for (i = 0; i < ops->i; ++i) { DisFreeOp(&ops->p[i]); } free(ops->p); memset(ops, 0, sizeof(*ops)); } void DisFreeSyms(struct DisSyms *syms) { long i; for (i = 0; i < syms->i; ++i) { free(syms->p[i].name); } free(syms->p); memset(syms, 0, sizeof(*syms)); } void DisFree(struct Dis *d) { DisFreeOps(&d->ops); DisFreeSyms(&d->syms); free(d->edges.p); free(d->loads.p); memset(d, 0, sizeof(*d)); } ================================================ FILE: blink/disinst.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/assert.h" #include "blink/dis.h" #include "blink/high.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/util.h" static const char kJcxz[3][6] = {"jcxz", "jecxz", "jrcxz"}; static const char kAluOp[8][4] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; static const char kBitOp[8][4] = {"rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar"}; static const char kCc[16][3] = {"o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "p", "np", "l", "ge", "le", "g"}; static bool IsProbablyByteOp(struct XedDecodedInst *x) { return !(Opcode(x->op.rde) & 1); } static int IsRepOpcode(struct Dis *d) { switch (Opcode(d->xedd->op.rde) & ~1) { case 0x6C: /* INS */ return 1; case 0x6E: /* OUTS */ return 1; case 0xA4: /* MOVS */ return 1; case 0xAA: /* STOS */ return 1; case 0xAC: /* LODS */ return 1; case 0xA6: /* CMPS */ return 2; case 0xAE: /* SCAS */ return 2; default: return 0; } } static char *DisRepPrefix(struct Dis *d, char *p) { if (Rep(d->xedd->op.rde) && Opmap(d->xedd->op.rde) == XED_ILD_MAP0) { switch (IsRepOpcode(d)) { case 0: break; case 1: p = stpcpy(p, "rep "); break; case 2: p = stpcpy(p, Rep(d->xedd->op.rde) == 2 ? "repnz " : "repz "); break; default: break; } } return p; } static char *DisName(struct Dis *d, char *bp, const char *name, bool ambiguous) { u64 rde; char *p; const char *np; bool notbyte, notlong, wantsuffix, wantsuffixsd; p = bp; rde = d->xedd->op.rde; if (Lock(d->xedd->op.rde)) p = stpcpy(p, "lock "); p = DisRepPrefix(d, p); if (strcmp(name, "BIT") == 0) { p = stpcpy(p, kBitOp[ModrmReg(rde)]); } else if (strcmp(name, "nop") == 0 && Rep(d->xedd->op.rde)) { p = stpcpy(p, "pause"); } else if (strcmp(name, "CALL") == 0) { p = stpcpy(p, "call"); } else if (strcmp(name, "JMP") == 0) { p = stpcpy(p, "jmp"); } else if (strcmp(name, "jcxz") == 0) { p = stpcpy(p, kJcxz[Eamode(rde)]); } else if (strcmp(name, "loop") == 0 || strcmp(name, "loope") == 0 || strcmp(name, "loopne") == 0) { p = stpcpy(p, name); if (Eamode(rde) != Mode(rde)) { *p++ = "wl"[Eamode(rde)]; *p = '\0'; } } else if (strcmp(name, "cwtl") == 0) { if (Osz(rde)) name = "cbtw"; if (Rexw(rde)) name = "cltq"; p = stpcpy(p, name); } else if (strcmp(name, "cltd") == 0) { if (Osz(rde)) name = "cwtd"; if (Rexw(rde)) name = "cqto"; p = stpcpy(p, name); } else { notbyte = false; notlong = false; wantsuffix = false; wantsuffixsd = false; for (np = name; *np && (islower(*np) || isdigit(*np)); ++np) { *p++ = *np; } if (strcmp(name, "ALU") == 0) { p = stpcpy(p, kAluOp[(Opcode(rde) & 070) >> 3]); } else if (strcmp(name, "ALU2") == 0) { p = stpcpy(p, kAluOp[ModrmReg(rde)]); } else if (strcmp(np, "WLQ") == 0) { notbyte = true; wantsuffix = true; } else if (strcmp(np, "CC") == 0) { p = stpcpy(p, kCc[Opcode(rde) & 15]); } else if (strcmp(np, "WQ") == 0) { notbyte = true; notlong = Eamode(rde) != XED_MODE_REAL; wantsuffix = true; } else if (strcmp(np, "LQ") == 0 || strcmp(np, "WL") == 0) { notbyte = true; wantsuffix = true; } else if (strcmp(np, "SD") == 0) { notbyte = true; wantsuffixsd = true; } else if (strcmp(np, "ABS") == 0) { if (Rexw(rde)) p = stpcpy(p, "abs"); } if (wantsuffixsd) { if (Osz(rde)) { *p++ = 'd'; } else { *p++ = 's'; } } else if (wantsuffix || (ambiguous && !StartsWith(name, "f") && !StartsWith(name, "set"))) { if (Osz(rde)) { if (ambiguous || Mode(rde) != XED_MODE_REAL) { *p++ = 'w'; } } else if (Rexw(rde)) { *p++ = 'q'; } else if (ambiguous && !notbyte && IsProbablyByteOp(d->xedd)) { *p++ = 'b'; } else if (!notlong) { *p++ = 'l'; } } } *p++ = ' '; if (!d->notab) { while (p - bp < 8) { *p++ = ' '; } } *p = '\0'; return p; } /** * Disassembles instruction based on string spec. * @see DisSpec() */ char *DisInst(struct Dis *d, char *p, const char *spec) { size_t m; long i, n; char sbuf[64]; char args[4][256]; char *s, *name, *state; bool hasarg, hasmodrm, hasregister, hasmemory; unassert(strlen(spec) < 128); hasarg = false; hasmodrm = d->xedd->op.has_modrm; hasmemory = hasmodrm && !IsModrmRegister(d->xedd->op.rde); hasregister = hasmodrm && IsModrmRegister(d->xedd->op.rde); name = strtok_r(strcpy(sbuf, spec), " ", &state); for (n = 0; (s = strtok_r(NULL, " ", &state)); ++n) { hasarg = true; hasregister |= *s == '%'; hasmemory |= *s == 'O'; m = DisArg(d, args[n], s) - args[n]; if (m >= sizeof(args[n])) Abort(); } p = HighStart(p, g_high.keyword); p = DisName(d, p, name, hasarg && !hasregister && hasmemory); p = HighEnd(p); for (i = 0; i < n; ++i) { if (i && args[n - i][0]) { *p++ = ','; } p = stpcpy(p, args[n - i - 1]); } return p; } ================================================ FILE: blink/disspec.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/builtin.h" #include "blink/case.h" #include "blink/rde.h" #include "blink/x86.h" #define UNKNOWN "wut" #define RCASE(x, y) CASE(x, return y) static const char kFpuName[][8][8] = { {"fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr"}, {"fchs", "fabs", UNKNOWN, UNKNOWN, "ftst", "fxam", UNKNOWN, UNKNOWN}, {"fld1", "fldl2t", "fldl2e", "fldpi", "fldlg2", "fldln2", "fldz"}, {"f2xm1", "fyl2x", "fptan", "fpatan", "fxtract", "fprem1", "fdecstp", "fincstp"}, {"fprem", "fyl2xp1", "fsqrt", "fsincos", "frndint", "fscale", "fsin", "fcos"}, {"fneni", "fndisi", "fnclex", "fninit", "fnsetpm"}, }; char *DisOpFpu1(struct XedDecodedInst *x, char *p, const char *extra) { stpcpy(stpcpy(p, kFpuName[0][ModrmReg(x->op.rde)]), extra); return p; } char *DisOp66(struct XedDecodedInst *x, char *p, const char *s, const char *a, const char *b) { stpcpy(stpcpy(p, s), !Osz(x->op.rde) ? a : b); return p; } char *DisOpVpsWpsVssWss(struct XedDecodedInst *x, char *p, const char *s) { return DisOp66(x, p, s, "ps %Vps Wps", "ss %Vss Wss"); } char *DisOpVpdWpdVpsWps(struct XedDecodedInst *x, char *p, const char *s) { return DisOp66(x, p, s, "ps %Vps Wps", "pd %Vpd Wpd"); } char *DisOpPqQqVdqWdq(struct XedDecodedInst *x, char *p, const char *s) { return DisOp66(x, p, s, " %Pq Qq", " %Vdq Wdq"); } char *DisOpPqQqIbVdqWdqIb(struct XedDecodedInst *x, char *p, const char *s) { return DisOp66(x, p, s, " %Pq Qq Ib", " %Vdq Wdq Ib"); } char *DisOpNqIbUdqIb(struct XedDecodedInst *x, char *p, const char *s) { return DisOp66(x, p, s, " %Nq Ib", " %Udq Ib"); } char *DisOpVpsWpsVssWssVpdWpdVsdWsd(struct XedDecodedInst *x, char *p, const char *s) { char *q = stpcpy(p, s); if (Rep(x->op.rde) == 3) { stpcpy(q, "ss %Vss Wss"); } else if (Rep(x->op.rde) == 2) { stpcpy(q, "sd %Vsd Wsd"); } else if (Osz(x->op.rde)) { stpcpy(q, "pd %Vpd Wpd"); } else { stpcpy(q, "ps %Vps Wps"); } return p; } const char *DisSpecFpu0(struct XedDecodedInst *x, int group) { const char *s; s = kFpuName[group][ModrmRm(x->op.rde)]; return *s ? s : UNKNOWN; } const char *DisSpecRegMem(struct XedDecodedInst *x, const char *a, const char *b) { if (IsModrmRegister(x->op.rde)) { return a; } else { return b; } } const char *DisSpecRegMemFpu0(struct XedDecodedInst *x, int group, const char *b) { return DisSpecRegMem(x, DisSpecFpu0(x, group), b); } const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { switch (Opcode(x->op.rde)) { RCASE(0x00, "ALU Eb %Gb"); RCASE(0x01, "ALU Evqp %Gvqp"); RCASE(0x02, "ALU %Gb Eb"); RCASE(0x03, "ALU %Gvqp Evqp"); RCASE(0x04, "ALU %al Ib"); RCASE(0x05, "ALU %rAX Ivds"); RCASE(0x06, "push %es"); RCASE(0x07, "pop %es"); RCASE(0x08, "ALU Eb %Gb"); RCASE(0x09, "ALU Evqp %Gvqp"); RCASE(0x0a, "ALU %Gb Eb"); RCASE(0x0b, "ALU %Gvqp Evqp"); RCASE(0x0c, "ALU %al Ib"); RCASE(0x0d, "ALU %rAX Ivds"); RCASE(0x0e, "push %cs"); RCASE(0x0f, "pop %cs"); RCASE(0x10, "ALU Eb %Gb"); RCASE(0x11, "ALU Evqp %Gvqp"); RCASE(0x12, "ALU %Gb Eb"); RCASE(0x13, "ALU %Gvqp Evqp"); RCASE(0x14, "ALU %al Ib"); RCASE(0x15, "ALU %rAX Ivds"); RCASE(0x16, "push %ss"); RCASE(0x17, "pop %ss"); RCASE(0x18, "ALU Eb %Gb"); RCASE(0x19, "ALU Evqp %Gvqp"); RCASE(0x1a, "ALU %Gb Eb"); RCASE(0x1b, "ALU %Gvqp Evqp"); RCASE(0x1c, "ALU %al Ib"); RCASE(0x1d, "ALU %rAX Ivds"); RCASE(0x1e, "push %ds"); RCASE(0x1f, "pop %ds"); RCASE(0x20, "ALU Eb %Gb"); RCASE(0x21, "ALU Evqp %Gvqp"); RCASE(0x22, "ALU %Gb Eb"); RCASE(0x23, "ALU %Gvqp Evqp"); RCASE(0x24, "ALU %al Ib"); RCASE(0x25, "ALU %rAX Ivds"); RCASE(0x26, "push %es"); RCASE(0x27, "pop %es"); RCASE(0x28, "ALU Eb %Gb"); RCASE(0x29, "ALU Evqp %Gvqp"); RCASE(0x2a, "ALU %Gb Eb"); RCASE(0x2b, "ALU %Gvqp Evqp"); RCASE(0x2c, "ALU %al Ib"); RCASE(0x2d, "ALU %rAX Ivds"); RCASE(0x2F, "das"); RCASE(0x30, "ALU Eb %Gb"); RCASE(0x31, "ALU Evqp %Gvqp"); RCASE(0x32, "ALU %Gb Eb"); RCASE(0x33, "ALU %Gvqp Evqp"); RCASE(0x34, "ALU %al Ib"); RCASE(0x35, "ALU %rAX Ivds"); RCASE(0x37, "aaa"); RCASE(0x38, "ALU Eb %Gb"); RCASE(0x39, "ALU Evqp %Gvqp"); RCASE(0x3A, "ALU %Gb Eb"); RCASE(0x3B, "ALU %Gvqp Evqp"); RCASE(0x3C, "ALU %al Ib"); RCASE(0x3D, "ALU %rAX Ivds"); RCASE(0x3F, "aas"); RCASE(0x60, "pusha"); RCASE(0x61, "popa"); RCASE(0x62, "bound"); RCASE(0x63, "movslLQ %Gdqp Ed"); RCASE(0x68, "pushWQ Ivs"); RCASE(0x69, "imul %Gvqp Evqp Ivds"); RCASE(0x6A, "pushWQ Ibss"); RCASE(0x6B, "imul %Gvqp Evqp Ibs"); RCASE(0x6C, "insb Yb DX"); RCASE(0x6D, "insWL Yv DX"); RCASE(0x6E, "outsb DX Xb"); RCASE(0x6F, "outsWL DX Xv"); RCASE(0x80, "ALU2 Eb Ib"); RCASE(0x81, "ALU2 Evqp Ivds"); RCASE(0x82, "ALU2 Eb Ib"); RCASE(0x83, "ALU2 Evqp Ibs"); RCASE(0x84, "test Eb %Gb"); RCASE(0x85, "test %Gvqp Evqp"); RCASE(0x86, "xchg %Gb Eb"); RCASE(0x87, "xchg %Gvqp Evqp"); RCASE(0x88, "mov Eb %Gb"); RCASE(0x89, "mov Evqp %Gvqp"); RCASE(0x8A, "mov %Gb Eb"); RCASE(0x8B, "mov %Gvqp Evqp"); RCASE(0x8C, "mov Evqp %Sw"); RCASE(0x8D, "lea %Gvqp M"); RCASE(0x8E, "mov %Sw Evqp"); RCASE(0x90, "nop"); RCASE(0x98, "cwtl"); RCASE(0x99, "cltd"); RCASE(0x9A, "lcall Pvds Kvds"); RCASE(0x9B, "fwait"); RCASE(0x9C, "pushfWQ"); RCASE(0x9D, "popfWQ"); RCASE(0x9E, "sahf"); RCASE(0x9F, "lahf"); RCASE(0xA0, "movABS %al Ob"); RCASE(0xA1, "movABS %rAX Ovqp"); RCASE(0xA2, "movABS Ob %al"); RCASE(0xA3, "movABS Ovqp %rAX"); RCASE(0xA4, "movsb Yb Xb"); RCASE(0xA5, "movsWLQ Yvqp Xvqp"); RCASE(0xA6, "cmpsb Yb Xb"); RCASE(0xA7, "cmpsWLQ Yvqp Xvqp"); RCASE(0xA8, "test %al Ib"); RCASE(0xA9, "test %rAX Ivds"); RCASE(0xAA, "stosb Yb %al"); RCASE(0xAB, "stosWLQ Yvqp %rAX"); RCASE(0xAC, "lodsb %al Xb"); RCASE(0xAD, "lodsWLQ %rAX Xvqp"); RCASE(0xAE, "scasb %al Yb"); RCASE(0xAF, "scasWLQ %rAX Yvqp"); RCASE(0xC0, "BIT Eb Ib"); RCASE(0xC1, "BIT Evqp Ib"); RCASE(0xC2, "ret Iw"); RCASE(0xC3, "ret"); RCASE(0xC4, "les %Gv Mp"); RCASE(0xC5, "lds %Gv Mp"); RCASE(0xC6, "mov Eb Ib"); RCASE(0xC7, "mov Evqp Ivds"); RCASE(0xC8, "enter >Ib Iw"); RCASE(0xC9, "leave"); RCASE(0xCA, "lret Iw"); RCASE(0xCB, "lret"); RCASE(0xCC, "int3"); RCASE(0xCD, "int Ib"); RCASE(0xCE, "into"); RCASE(0xCF, "iret"); RCASE(0xD0, "BIT Eb"); RCASE(0xD1, "BIT Evqp"); RCASE(0xD2, "BIT Evqp %cl"); RCASE(0xD3, "BIT Evqp %cl"); RCASE(0xD4, x->op.uimm0 == 0x0a ? "aam" : "aam Ib"); RCASE(0xD5, x->op.uimm0 == 0x0a ? "aad" : "aad Ib"); RCASE(0xD6, "salc"); RCASE(0xD7, "xlat BBb"); RCASE(0xE0, "loopne Jbs"); RCASE(0xE1, "loope Jbs"); RCASE(0xE2, "loop Jbs"); RCASE(0xE3, "jcxz Jbs"); RCASE(0xE4, "in %al Ib"); RCASE(0xE5, "in %eAX Ib"); RCASE(0xE6, "out Ib %al"); RCASE(0xE7, "out Ib %eAX"); RCASE(0xE8, "call Jvds"); RCASE(0xE9, "jmp Jvds"); RCASE(0xEA, "ljmp Rvds Kvds"); RCASE(0xEB, "jmp Jbs"); RCASE(0xEC, "in %al DX"); RCASE(0xED, "in %eAX DX"); RCASE(0xEE, "out DX %al"); RCASE(0xEF, "out DX %eAX"); RCASE(0xF1, "int1"); RCASE(0xF4, "hlt"); RCASE(0xF5, "cmc"); RCASE(0xF8, "clc"); RCASE(0xF9, "stc"); RCASE(0xFA, "cli"); RCASE(0xFB, "sti"); RCASE(0xFC, "cld"); RCASE(0xFD, "std"); case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: return "inc %Zv"; case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: return "dec %Zv"; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: return "push %Zvq"; case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: return "pop %Zvq"; case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: return "jCC Jbs"; case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: return "xchg %Zvqp %rAX"; case 0xB0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: return "mov %Zb Ib"; case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: return "movABS %Zvqp Ivqp"; case 0x8F: switch (ModrmReg(x->op.rde)) { RCASE(0, "popWQ Evq"); default: break; } break; case 0xD9: switch (ModrmReg(x->op.rde)) { RCASE(1, "fxch EST1"); RCASE(3, "fstps Msr %st"); RCASE(0, DisSpecRegMem(x, "fld EST", "flds Msr")); RCASE(2, DisSpecRegMem(x, "fnop", "fsts Msr %st")); RCASE(4, DisSpecRegMemFpu0(x, 1, "fldenv Me")); RCASE(5, DisSpecRegMemFpu0(x, 2, "fldcw Mw")); RCASE(6, DisSpecRegMemFpu0(x, 3, "fnstenv M")); RCASE(7, DisSpecRegMemFpu0(x, 4, "fnstcw Mw")); } break; case 0xDA: switch (ModrmReg(x->op.rde)) { RCASE(0, DisSpecRegMem(x, "fcmovb %st EST", "fiaddl Mdi")); RCASE(1, DisSpecRegMem(x, "fcmove %st EST", "fimull Mdi")); RCASE(2, DisSpecRegMem(x, "fcmovbe %st EST", "ficoml Mdi")); RCASE(3, DisSpecRegMem(x, "fcmovu %st EST", "ficompl Mdi")); RCASE(4, DisSpecRegMem(x, "fisubr Mdi", "fisubl Mdi")); RCASE(5, DisSpecRegMem(x, "fucompp", "fisubrl Mdi")); RCASE(6, DisSpecRegMem(x, "fidivl Mdi", "UNKNOWN")); RCASE(7, DisSpecRegMem(x, "fidivrl Mdi", "UNKNOWN")); } break; case 0xDB: switch (ModrmReg(x->op.rde)) { RCASE(0, DisSpecRegMem(x, "fcmovnb %st EST", "fildl Mdi")); RCASE(1, DisSpecRegMem(x, "fcmovne %st EST", "fisttpl Mdi")); RCASE(2, DisSpecRegMem(x, "fcmovnbe %st EST", "fistl Mdi")); RCASE(3, DisSpecRegMem(x, "fcmovnu %st EST", "fistpl Mdi")); RCASE(4, DisSpecFpu0(x, 5)); RCASE(5, DisSpecRegMem(x, "fucomi %st EST", "fldt Mer")); RCASE(6, DisSpecRegMem(x, "fcomi %st EST", UNKNOWN)); RCASE(7, DisSpecRegMem(x, UNKNOWN, "fstpt Mer")); } break; case 0xD8: return DisOpFpu1(x, p, !IsModrmRegister(x->op.rde) ? "s Msr" : " EST1"); case 0xDC: if (!IsModrmRegister(x->op.rde)) { return DisOpFpu1(x, p, "l Mdr"); } else { switch (ModrmReg(x->op.rde)) { RCASE(0, "fadd EST %st"); RCASE(1, "fmul EST %st"); RCASE(2, "fcom %st EST"); RCASE(3, "fcomp %st EST"); RCASE(4, "fsub EST %st"); RCASE(5, "fsubr EST %st"); RCASE(6, "fdiv EST %st"); RCASE(7, "fdivr EST %st"); } } break; case 0xDD: if (!IsModrmRegister(x->op.rde)) { switch (ModrmReg(x->op.rde)) { RCASE(0, "fldl Mdr"); RCASE(1, "fisttpll Mqi"); RCASE(2, "fstl Mdr"); RCASE(3, "fstpl Mdr"); RCASE(4, "frstor Mdr"); RCASE(6, "fnsave Mst"); RCASE(7, "fnstsw Mst"); } } else { switch (ModrmReg(x->op.rde)) { RCASE(0, "ffree EST"); RCASE(1, "fxch EST"); RCASE(2, "fst EST"); RCASE(3, "fstp EST"); RCASE(4, "fucom EST1"); RCASE(5, "fucomp EST1"); } } break; case 0xDE: if (!IsModrmRegister(x->op.rde)) { switch (ModrmReg(x->op.rde)) { RCASE(0, "fiadds Mwi"); RCASE(1, "fimuls Mwi"); RCASE(2, "ficoms Mwi"); RCASE(3, "ficomps Mwi"); RCASE(4, "fisubs Mwi"); RCASE(5, "fisubrs Mwi"); RCASE(6, "fidivs Mwi"); RCASE(7, "fidivrs Mwi"); } } else { switch (ModrmReg(x->op.rde)) { RCASE(0, "faddp EST1"); RCASE(1, "fmulp EST1"); RCASE(2, "fcomp EST1"); RCASE(3, "fcompp"); RCASE(4, "fsubp EST1"); RCASE(5, "fsubrp EST1"); RCASE(6, "fdivp EST1"); RCASE(7, "fdivrp EST1"); } } break; case 0xDF: if (!IsModrmRegister(x->op.rde)) { switch (ModrmReg(x->op.rde)) { RCASE(0, "filds Mwi"); RCASE(1, "fisttps Mwi"); RCASE(2, "fists Mwi"); RCASE(3, "fistps Mwi"); RCASE(4, "fbld"); RCASE(5, "fildll Mqi"); RCASE(6, "fbstp"); RCASE(7, "fistpll Mqi"); } } else { switch (ModrmReg(x->op.rde)) { RCASE(0, "ffreep EST"); RCASE(1, "fxch"); RCASE(2, "fstp EST"); RCASE(3, "fstp EST"); RCASE(4, "fnstsw"); RCASE(5, "fucomip EST"); RCASE(6, "fcomip EST"); } } break; case 0xF6: switch (ModrmReg(x->op.rde)) { RCASE(0, "test Eb Ib"); RCASE(1, "test Eb Ib"); RCASE(2, "not Eb"); RCASE(3, "neg Eb"); RCASE(4, "mulb Eb"); RCASE(5, "imulb Eb"); RCASE(6, "divb Eb"); RCASE(7, "idivb Eb"); } break; case 0xF7: switch (ModrmReg(x->op.rde)) { RCASE(0, "test Evqp Ivds"); RCASE(1, "test Evqp Ivds"); RCASE(2, "not Evqp"); RCASE(3, "neg Evqp"); RCASE(4, "mul Evqp"); RCASE(5, "imul Evqp"); RCASE(6, "div Evqp"); RCASE(7, "idiv Evqp"); } break; case 0xFE: switch (ModrmReg(x->op.rde)) { RCASE(0, "inc Eb"); RCASE(1, "dec Eb"); } break; case 0xFF: switch (ModrmReg(x->op.rde)) { RCASE(0, "inc Evqp"); RCASE(1, "dec Evqp"); RCASE(2, "CALL *Eq"); RCASE(3, "lcall *Eq"); RCASE(4, "JMP *Eq"); RCASE(5, "ljmp *Eq"); RCASE(6, "pushWQ Evq"); } break; } return UNKNOWN; } const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { bool isreg; isreg = IsModrmRegister(x->op.rde); switch (Opcode(x->op.rde)) { RCASE(0x02, "lar %Gvqp Ev"); RCASE(0x03, "lsl %Gvqp Ev"); RCASE(0x05, "syscall"); RCASE(0x06, "clts"); RCASE(0x09, "wbinvd"); RCASE(0x0B, "ud2"); RCASE(0x20, "mov %Hd %Cd"); RCASE(0x22, "mov %Cd %Hd"); RCASE(0x28, "movapSD %Vps Wps"); RCASE(0x29, "movapSD Wps %Vps"); RCASE(0x2B, "movntpSD Mps %Vps"); RCASE(0x2E, Osz(x->op.rde) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss"); RCASE(0x2F, Osz(x->op.rde) ? "comisd %Vsd Wsd" : "comiss %Vss Wss"); RCASE(0x30, "wrmsr"); RCASE(0x31, "rdtsc"); RCASE(0x32, "rdmsr"); RCASE(0x33, "rdpmc"); RCASE(0x34, "sysenter"); RCASE(0x35, "sysexit"); RCASE(0x50, Osz(x->op.rde) ? "movmskpd %Gdqp %Udq" : "movmskps %Gdqp %Nq"); RCASE(0x52, DisOpVpsWpsVssWss(x, p, "rsqrt")); RCASE(0x53, DisOpVpsWpsVssWss(x, p, "rcp")); RCASE(0x54, DisOpVpdWpdVpsWps(x, p, "and")); RCASE(0x55, DisOpVpdWpdVpsWps(x, p, "andn")); RCASE(0x56, DisOpVpdWpdVpsWps(x, p, "or")); RCASE(0x57, DisOpVpdWpdVpsWps(x, p, "xor")); RCASE(0x58, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "add")); RCASE(0x59, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "mul")); RCASE(0x5C, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "sub")); RCASE(0x5D, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "min")); RCASE(0x5E, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "div")); RCASE(0x5F, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "max")); RCASE(0x60, DisOpPqQqVdqWdq(x, p, "punpcklbw")); RCASE(0x61, DisOpPqQqVdqWdq(x, p, "punpcklwd")); RCASE(0x62, DisOpPqQqVdqWdq(x, p, "punpckldq")); RCASE(0x63, DisOpPqQqVdqWdq(x, p, "packsswb")); RCASE(0x64, DisOpPqQqVdqWdq(x, p, "pcmpgtb")); RCASE(0x65, DisOpPqQqVdqWdq(x, p, "pcmpgtw")); RCASE(0x66, DisOpPqQqVdqWdq(x, p, "pcmpgtd")); RCASE(0x67, DisOpPqQqVdqWdq(x, p, "packuswb")); RCASE(0x68, DisOpPqQqVdqWdq(x, p, "punpckhbw")); RCASE(0x69, DisOpPqQqVdqWdq(x, p, "punpckhwd")); RCASE(0x6A, DisOpPqQqVdqWdq(x, p, "punpckhdq")); RCASE(0x6B, DisOpPqQqVdqWdq(x, p, "packssdw")); RCASE(0x6C, DisOpPqQqVdqWdq(x, p, "punpcklqdq")); RCASE(0x6D, DisOpPqQqVdqWdq(x, p, "punpckhqdq")); RCASE(0x74, DisOpPqQqVdqWdq(x, p, "pcmpeqb")); RCASE(0x75, DisOpPqQqVdqWdq(x, p, "pcmpeqw")); RCASE(0x76, DisOpPqQqVdqWdq(x, p, "pcmpeqd")); RCASE(0x77, "emms"); RCASE(0xA0, "push %fs"); RCASE(0xA1, "pop %fs"); RCASE(0xA2, "cpuid"); RCASE(0xA3, "bt Evqp %Gvqp"); RCASE(0xA4, "shld Evqp %Gvqp Ib"); RCASE(0xA5, "shld Evqp %Gvqp %cl"); RCASE(0xA8, "push %gs"); RCASE(0xA9, "pop %gs"); RCASE(0xAB, "bts Evqp %Gvqp"); RCASE(0xAC, "shrd Evqp %Gvqp Ib"); RCASE(0xAD, "shrd Evqp %Gvqp %cl"); RCASE(0xAF, "imul %Gvqp Evqp"); RCASE(0xB0, "cmpxchg Eb %Gb"); RCASE(0xB1, "cmpxchg Evqp %Gvqp"); RCASE(0xB2, "lss %Gv Mp"); RCASE(0xB3, "btr Evqp %Gvqp"); RCASE(0xB4, "lfs %Gv Mp"); RCASE(0xB5, "lgs %Gv Mp"); RCASE(0xB6, "movzbWLQ %Gvqp Eb"); RCASE(0xB7, "movzwWLQ %Gvqp Ew"); RCASE(0xB9, "ud %Gvqp Evqp"); RCASE(0xBB, "btc Evqp %Gvqp"); RCASE(0xBE, "movsbWLQ %Gvqp Eb"); RCASE(0xBF, "movswWLQ %Gvqp Ew"); RCASE(0xC0, "xadd Eb %Gb"); RCASE(0xC1, "xadd Evqp %Gvqp"); RCASE(0xC2, DisOpVpsWpsVssWssVpdWpdVsdWsd(x, p, "cmp")); RCASE(0xC3, "movnti Mdqp %Gdqp"); RCASE(0xD1, DisOpPqQqVdqWdq(x, p, "psrlw")); RCASE(0xD2, DisOpPqQqVdqWdq(x, p, "psrld")); RCASE(0xD3, DisOpPqQqVdqWdq(x, p, "psrlq")); RCASE(0xD4, DisOpPqQqVdqWdq(x, p, "paddq")); RCASE(0xD5, DisOpPqQqVdqWdq(x, p, "pmullw")); RCASE(0xD7, Osz(x->op.rde) ? "pmovmskb %Gdqp %Udq" : "pmovmskb %Gdqp %Nq"); RCASE(0xD8, DisOpPqQqVdqWdq(x, p, "psubusb")); RCASE(0xD9, DisOpPqQqVdqWdq(x, p, "psubusw")); RCASE(0xDA, DisOpPqQqVdqWdq(x, p, "pminub")); RCASE(0xDB, DisOpPqQqVdqWdq(x, p, "pand")); RCASE(0xDC, DisOpPqQqVdqWdq(x, p, "paddusb")); RCASE(0xDD, DisOpPqQqVdqWdq(x, p, "paddusw")); RCASE(0xDE, DisOpPqQqVdqWdq(x, p, "pmaxub")); RCASE(0xDF, DisOpPqQqVdqWdq(x, p, "pandn")); RCASE(0xE0, DisOpPqQqVdqWdq(x, p, "pavgb")); RCASE(0xE1, DisOpPqQqVdqWdq(x, p, "psrawv")); RCASE(0xE2, DisOpPqQqVdqWdq(x, p, "psradv")); RCASE(0xE3, DisOpPqQqVdqWdq(x, p, "pavgw")); RCASE(0xE4, DisOpPqQqVdqWdq(x, p, "pmulhuw")); RCASE(0xE5, DisOpPqQqVdqWdq(x, p, "pmulhw")); RCASE(0xE7, Osz(x->op.rde) ? "movntdq Mdq %Vdq" : "movntq Mq %Pq"); RCASE(0xE8, DisOpPqQqVdqWdq(x, p, "psubsb")); RCASE(0xE9, DisOpPqQqVdqWdq(x, p, "psubsw")); RCASE(0xEA, DisOpPqQqVdqWdq(x, p, "pminsw")); RCASE(0xEB, DisOpPqQqVdqWdq(x, p, "por")); RCASE(0xEC, DisOpPqQqVdqWdq(x, p, "paddsb")); RCASE(0xED, DisOpPqQqVdqWdq(x, p, "paddsw")); RCASE(0xEE, DisOpPqQqVdqWdq(x, p, "pmaxsw")); RCASE(0xEF, DisOpPqQqVdqWdq(x, p, "pxor")); RCASE(0xF0, "lddqu %Vdq Mdq"); RCASE(0xF1, DisOpPqQqVdqWdq(x, p, "psllwv")); RCASE(0xF2, DisOpPqQqVdqWdq(x, p, "pslldv")); RCASE(0xF3, DisOpPqQqVdqWdq(x, p, "psllqv")); RCASE(0xF4, DisOpPqQqVdqWdq(x, p, "pmuludq")); RCASE(0xF5, DisOpPqQqVdqWdq(x, p, "pmaddwd")); RCASE(0xF6, DisOpPqQqVdqWdq(x, p, "psadbw")); RCASE(0xF8, DisOpPqQqVdqWdq(x, p, "psubb")); RCASE(0xF9, DisOpPqQqVdqWdq(x, p, "psubw")); RCASE(0xFA, DisOpPqQqVdqWdq(x, p, "psubd")); RCASE(0xFB, DisOpPqQqVdqWdq(x, p, "psubq")); RCASE(0xFC, DisOpPqQqVdqWdq(x, p, "paddb")); RCASE(0xFD, DisOpPqQqVdqWdq(x, p, "paddw")); RCASE(0xFE, DisOpPqQqVdqWdq(x, p, "paddd")); case 0x0D: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: return "nop Ev"; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: return "cmovCC %Gvqp Evqp"; case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: return "jCC Jvds"; case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: return "setCC Eb"; case 0xC8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: return "bswap %Zvqp"; case 0xBC: if (Rep(x->op.rde) == 3) { return "tzcnt %Gvqp Evqp"; } else { return "bsf %Gvqp Evqp"; } case 0xBD: if (Rep(x->op.rde) == 3) { return "lzcnt %Gvqp Evqp"; } else { return "bsr %Gvqp Evqp"; } case 0x00: switch (ModrmReg(x->op.rde)) { case 0: return "sldt Ew"; case 1: return "str Ew"; case 2: return "lldt Ew"; case 3: return "ltr Ew"; case 4: return "verr Ew"; case 5: return "verw Ew"; default: return UNKNOWN; } case 0x01: switch (ModrmReg(x->op.rde)) { case 0: if (!isreg) { return "sgdt Ms"; } else { switch (ModrmRm(x->op.rde)) { case 1: return "vmcall"; case 2: return "vmlaunch"; case 3: return "vmresume"; case 4: return "vmxoff"; default: return UNKNOWN; } } break; case 1: if (!isreg) { return "sidt Ms"; } else { switch (ModrmRm(x->op.rde)) { case 0: return "monitor"; case 1: return "mwait"; default: return UNKNOWN; } } break; case 2: if (!isreg) { return "lgdt Ms"; } else if (ModrmRm(x->op.rde) == 0) { return "xgetbv"; } else if (ModrmRm(x->op.rde) == 1) { return "xsetbv"; } else { return UNKNOWN; } break; case 3: if (!isreg) { return "lidt Ms"; } else { return UNKNOWN; } case 4: return "smsw Ew"; case 6: return "lmsw Ew"; case 7: if (!isreg) { return "invlpg M"; } else { switch (ModrmRm(x->op.rde)) { case 0: return "swapgs"; case 1: return "rdtscp"; default: return UNKNOWN; } } default: return UNKNOWN; } case 0x1F: if (ModrmMod(x->op.rde) == 1 && ModrmReg(x->op.rde) == 0 && ModrmRm(x->op.rde) == 5) { return "bofram Jb"; } else { return "nop Ev"; } break; case 0x70: switch (Rep(x->op.rde) | Osz(x->op.rde)) { RCASE(0, "pshufw %Pq Qq Ib"); RCASE(1, "pshufd %Vdq Wdq Ib"); RCASE(2, "pshuflw %Vdq Wdq Ib"); RCASE(3, "pshufhw %Vdq Wdq Ib"); } break; case 0x71: switch (ModrmReg(x->op.rde)) { RCASE(2, DisOpNqIbUdqIb(x, p, "psrlw")); RCASE(4, DisOpNqIbUdqIb(x, p, "psraw")); RCASE(6, DisOpNqIbUdqIb(x, p, "psllw")); } break; case 0x72: switch (ModrmReg(x->op.rde)) { RCASE(2, DisOpNqIbUdqIb(x, p, "psrld")); RCASE(4, DisOpNqIbUdqIb(x, p, "psrad")); RCASE(6, DisOpNqIbUdqIb(x, p, "pslld")); } break; case 0x73: switch (ModrmReg(x->op.rde)) { RCASE(2, DisOpNqIbUdqIb(x, p, "psrlq")); RCASE(3, DisOpNqIbUdqIb(x, p, "psrldq")); RCASE(6, DisOpNqIbUdqIb(x, p, "psllq")); RCASE(7, DisOpNqIbUdqIb(x, p, "pslldq")); } break; case 0xAE: switch (ModrmReg(x->op.rde)) { case 0: if (isreg) { return "rdfsbase %Rdqp"; } else { return "fxsave M"; } case 1: if (isreg) { return "rdgsbase %Rdqp"; } else { return "fxrstor M"; } case 2: if (isreg) { return "wrfsbase %Rdqp"; } else { return "ldmxcsr Md"; } case 3: if (isreg) { return "wrgsbase %Rdqp"; } else { return "stmxcsr Md"; } case 4: if (isreg) { return UNKNOWN; } else { return "xsave M %edx %eax"; } case 5: return "lfence"; case 6: return "mfence"; case 7: if (isreg && ModrmReg(x->op.rde) == 7) { return "sfence"; } else { return "clflush"; } } break; case 0xBA: switch (ModrmReg(x->op.rde)) { RCASE(4, "btWLQ Evqp Ib"); RCASE(5, "btsWLQ Evqp Ib"); RCASE(6, "btrWLQ Evqp Ib"); RCASE(7, "btcWLQ Evqp Ib"); } break; case 0x10: if (Rep(x->op.rde) == 3) { return "movss %Vss Wss"; } else if (Rep(x->op.rde) == 2) { return "movsd %Vsd Wsd"; } else if (Osz(x->op.rde)) { return "movupd %Vpd Wpd"; } else { return "movups %Vps Wps"; } break; case 0x11: if (Rep(x->op.rde) == 3) { return "movss Wss %Vss"; } else if (Rep(x->op.rde) == 2) { return "movsd Wsd %Vsd"; } else if (Osz(x->op.rde)) { return "movupd Wpd %Vpd"; } else { return "movups Wps %Vps"; } break; case 0xC4: if (!Osz(x->op.rde)) { if (isreg) { return "pinsrw %Pq %Rdqp Ib"; } else { return "pinsrw %Pq Mw Ib"; } } else { if (isreg) { return "pinsrw %Vdq %Rdqp Ib"; } else { return "pinsrw %Vdq Mw Ib"; } } break; case 0xC5: if (!Osz(x->op.rde)) { return "pextrw %Gdqp %Nq Ib"; } else { return "pextrw %Gdqp %Udq Ib"; } break; case 0xC6: if (!Osz(x->op.rde)) { return "shufps %Vps Wps Ib"; } else { return "shufpd %Vpd Wpd Ib"; } break; case 0xC7: switch (ModrmReg(x->op.rde)) { case 1: if (!isreg) { if (Rexw(x->op.rde)) { return "cmpxchg16b Mdq"; } else { return "cmpxchg8b Mq"; } } else { return UNKNOWN; } break; case 6: if (isreg) { return "rdrand %Rdqp"; } else { return UNKNOWN; } break; case 7: if (isreg) { if (Rep(x->op.rde) == 3) { return "rdpid %Rdqp"; } else { return "rdseed %Rdqp"; } } else { return UNKNOWN; } break; default: return UNKNOWN; } break; case 0xD6: if (Osz(x->op.rde)) { return "movq Wq %Vq"; } else if (Rep(x->op.rde) == 3) { return "movq2dq %Vdq %Nq"; } else if (Rep(x->op.rde) == 2) { return "movq2dq %Pq %Uq"; } break; case 0x12: switch (Rep(x->op.rde) | Osz(x->op.rde)) { case 0: if (isreg) { return "movhlps %Vq %Uq"; } else { return "movlps %Vq Mq"; } break; case 1: return "movlpd %Vq Mq"; case 2: return "movddup %Vq Wq"; case 3: return "movsldup %Vq Wq"; default: __builtin_unreachable(); } break; case 0x13: if (Osz(x->op.rde)) { return "movlpd Mq %Vq"; } else { return "movlps Mq %Vq"; } break; case 0x16: switch (Rep(x->op.rde) | Osz(x->op.rde)) { case 0: if (isreg) { return "movlhps %Vq %Uq"; } else { return "movhps %Vq Mq"; } break; case 1: return "movhpd %Vq Mq"; case 3: return "movshdup %Vq Wq"; default: break; } break; case 0x17: if (Osz(x->op.rde)) { return "movhpd Mq %Vq"; } else { return "movhps Mq %Vq"; } break; case 0x2A: if (Rep(x->op.rde) == 3) { return "cvtsi2ss %Vss Edqp"; } else if (Rep(x->op.rde) == 2) { return "cvtsi2sd %Vsd Edqp"; } else if (Osz(x->op.rde)) { return "cvtpi2pd %Vpd Qpi"; } else { return "cvtpi2ps %Vps Qpi"; } break; case 0x2C: if (Rep(x->op.rde) == 3) { return "cvttss2si %Gdqp Wss"; } else if (Rep(x->op.rde) == 2) { return "cvttsd2si %Gdqp Wsd"; } else if (Osz(x->op.rde)) { return "cvttpd2pi %Ppi Wpd"; } else { return "cvttps2pi %Ppi Wpsq"; } break; case 0x2D: if (Rep(x->op.rde) == 3) { return "cvtss2si %Gdqp Wss"; } else if (Rep(x->op.rde) == 2) { return "cvtsd2si %Gdqp Wsd"; } else if (Osz(x->op.rde)) { return "cvtpd2pi %Ppi Wpd"; } else { return "cvtps2pi %Ppi Wpsq"; } break; case 0x5a: if (Rep(x->op.rde) == 3) { return "cvtss2sd %Vsd Wss"; } else if (Rep(x->op.rde) == 2) { return "cvtsd2ss %Vss Wsd"; } else if (Osz(x->op.rde)) { return "cvtpd2ps %Vps Wpd"; } else { return "cvtps2pd %Vpd Wps"; } break; case 0x5b: if (Rep(x->op.rde) == 3) { return "cvttps2dq %Vdq Wps"; } else if (Osz(x->op.rde)) { return "cvtps2dq %Vdq Wps"; } else { return "cvtdq2ps %Vps Wdq"; } break; case 0x51: if (Rep(x->op.rde) == 3) { return "sqrtss %Vss Wss"; } else if (Rep(x->op.rde) == 2) { return "sqrtsd %Vsd Wsd"; } else if (Osz(x->op.rde)) { return "sqrtpd %Vpd Wpd"; } else { return "sqrtps %Vps Wps"; } break; case 0x6E: if (Osz(x->op.rde)) { if (Rexw(x->op.rde)) { return "movq %Vdq Eqp"; } else { return "movd %Vdq Ed"; } } else { if (Rexw(x->op.rde)) { return "movq %Pq Eqp"; } else { return "movd %Pq Ed"; } } break; case 0x6F: if (Rep(x->op.rde) == 3) { return "movdqu %Vdq Wdq"; } else if (Osz(x->op.rde)) { return "movdqa %Vdq Wdq"; } else { return "movq %Pq Qq"; } break; case 0x7E: if (Rep(x->op.rde) == 3) { return "movq %Vq Wq"; } else if (Osz(x->op.rde)) { if (Rexw(x->op.rde)) { return "movq Eqp %Vdq"; } else { return "movd Ed %Vdq"; } } else { if (Rexw(x->op.rde)) { return "movq Eqp %Pq"; } else { return "movd Ed %Pq"; } } break; case 0x7F: if (Rep(x->op.rde) == 3) { return "movdqu Wdq %Vdq"; } else if (Osz(x->op.rde)) { return "movdqa Wdq %Vdq"; } else { return "movq Qq %Pq"; } break; case 0xE6: if (Rep(x->op.rde) == 2) { return "cvtpd2dq %Vdq Wpd"; } else if (Osz(x->op.rde)) { return "cvttpd2dq %Vdq Wpd"; } else if (Rep(x->op.rde) == 3) { return "cvtdq2pd %Vpd Wdq"; } break; case 0xFF: switch (Rep(x->op.rde) << 9 | ModrmMod(x->op.rde) << 6 | ModrmReg(x->op.rde) << 3 | ModrmRm(x->op.rde)) { case 00067: case 00167: case 00267: return "hvtailcall Ovqp"; case 00077: case 00177: case 00277: return "hvcall Ovqp"; default: return "ud0 %Gvqp Evqp"; } } return UNKNOWN; } const char *DisSpecMap2(struct XedDecodedInst *x, char *p) { switch (Opcode(x->op.rde)) { RCASE(0x00, DisOpPqQqVdqWdq(x, p, "pshufb")); RCASE(0x01, DisOpPqQqVdqWdq(x, p, "phaddw")); RCASE(0x02, DisOpPqQqVdqWdq(x, p, "phaddd")); RCASE(0x03, DisOpPqQqVdqWdq(x, p, "phaddsw")); RCASE(0x04, DisOpPqQqVdqWdq(x, p, "pmaddubsw")); RCASE(0x05, DisOpPqQqVdqWdq(x, p, "phsubw")); RCASE(0x06, DisOpPqQqVdqWdq(x, p, "phsubd")); RCASE(0x07, DisOpPqQqVdqWdq(x, p, "phsubsw")); RCASE(0x08, DisOpPqQqVdqWdq(x, p, "psignb")); RCASE(0x09, DisOpPqQqVdqWdq(x, p, "psignw")); RCASE(0x0A, DisOpPqQqVdqWdq(x, p, "psignd")); RCASE(0x0B, DisOpPqQqVdqWdq(x, p, "pmulhrsw")); RCASE(0x10, "pblendvb %Vdq Wdq"); RCASE(0x14, "blendvps Vps Wps"); RCASE(0x15, "blendvpd Vpd Wpd"); RCASE(0x17, "ptest %Vdq Wdq"); RCASE(0x1C, DisOpPqQqVdqWdq(x, p, "pabsb")); RCASE(0x1D, DisOpPqQqVdqWdq(x, p, "pabsw")); RCASE(0x1E, DisOpPqQqVdqWdq(x, p, "pabsd")); RCASE(0x20, "pmovsxbw %Vdq Mq"); RCASE(0x21, "pmovsxbd %Vdq Md"); RCASE(0x22, "pmovsxbq %Vdq Mw"); RCASE(0x23, "pmovsxwd %Vdq Mq"); RCASE(0x24, "pmovsxwq %Vdq Md"); RCASE(0x25, "pmovsxdq %Vdq Mq"); RCASE(0x28, "pmuldq %Vdq Wdq"); RCASE(0x29, "pcmpeqq %Vdq Wdq"); RCASE(0x2A, "movntdqa %Vdq Mdq"); RCASE(0x2B, "packusdw %Vdq Wdq"); RCASE(0x30, "pmovzxbw %Vdq Mq"); RCASE(0x31, "pmovzxbd %Vdq Md"); RCASE(0x32, "pmovzxbq %Vdq Mw"); RCASE(0x33, "pmovzxwd %Vdq Mq"); RCASE(0x34, "pmovzxwq %Vdq Md"); RCASE(0x35, "pmovzxdq %Vdq Mq"); RCASE(0x37, "pcmpgtq %Vdq Wdq"); RCASE(0x38, "pminsb %Vdq Wdq"); RCASE(0x39, "pminsd %Vdq Wdq"); RCASE(0x3A, "pminuw %Vdq Wdq"); RCASE(0x3B, "pminud %Vdq Wdq"); RCASE(0x3C, "pmaxsb %Vdq Wdq"); RCASE(0x3D, "pmaxsd %Vdq Wdq"); RCASE(0x3E, "pmaxuw %Vdq Wdq"); RCASE(0x3F, "pmaxud %Vdq Wdq"); RCASE(0x40, "pmulld %Vdq Wdq"); RCASE(0x41, "phminposuw %Vdq Wdq"); RCASE(0x80, "invept %Gq Mdq"); RCASE(0x81, "invvpid %Gq Mdq"); case 0xF0: if (Rep(x->op.rde) == 2) { return "crc32 %Gvqp Eb"; } else { return "movbe %Gvqp M"; } break; case 0xF1: if (Rep(x->op.rde) == 2) { return "crc32 %Gvqp Evqp"; } else { return "movbe M %Gvqp"; } break; case 0xF5: if (Rep(x->op.rde) == 2) { return "pdep %Gdqp %Bdqp Edqp"; } else if (Rep(x->op.rde) == 3) { return "pext %Gdqp %Bdqp Edqp"; } else if (!Osz(x->op.rde)) { return "bzhi %Gdqp %Bdqp Edqp"; } else { return "wut"; } case 0xF6: if (Osz(x->op.rde)) { return "adcx %Gdqp Edqp"; } else if (Rep(x->op.rde) == 2) { return "mulx %Gdqp %Bdqp Edqp"; } else if (Rep(x->op.rde) == 3) { return "adox %Gdqp Edqp"; } else { return "wut"; } case 0xF7: if (Osz(x->op.rde)) { return "shlx %Gdqp %Bdqp Edqp"; } else if (Rep(x->op.rde) == 2) { return "shrx %Gdqp %Bdqp Edqp"; } else if (Rep(x->op.rde) == 3) { return "sarx %Gdqp %Bdqp Edqp"; } else { return "wut"; } default: return UNKNOWN; } } const char *DisSpecMap3(struct XedDecodedInst *x, char *p) { switch (Opcode(x->op.rde)) { RCASE(0x0F, DisOpPqQqIbVdqWdqIb(x, p, "palignr")); RCASE(0xF0, "rorx %Gdqp Edqp Ib"); case 0x44: // pclmulqdq if (Osz(x->op.rde)) { switch (x->op.uimm0) { case 0x00: return "pclmullqlqdq Wdq %Vdq"; case 0x01: return "pclmulhqlqdq Wdq %Vdq"; case 0x10: return "pclmullqhqdq Wdq %Vdq"; case 0x11: return "pclmulhqhqdq Wdq %Vdq"; default: return "wut"; } } else { return "wut"; } default: return UNKNOWN; } } const char *DisSpec(struct XedDecodedInst *x, char *p) { switch (Opmap(x->op.rde)) { case XED_ILD_MAP0: return DisSpecMap0(x, p); case XED_ILD_MAP1: return DisSpecMap1(x, p); case XED_ILD_MAP2: return DisSpecMap2(x, p); case XED_ILD_MAP3: return DisSpecMap3(x, p); default: return UNKNOWN; } } ================================================ FILE: blink/divmul.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/alu.h" #include "blink/assert.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/machine.h" #include "blink/modrm.h" struct Dubble { u64 lo; u64 hi; }; static inline struct Dubble DubbleNeg(struct Dubble x) { struct Dubble d; d.lo = -x.lo; d.hi = ~(x.hi - (x.lo - 1 > x.lo)); return d; } static inline struct Dubble DubbleShl(struct Dubble x) { struct Dubble d; d.lo = x.lo << 1; d.hi = x.hi << 1 | x.lo >> 63; return d; } static inline struct Dubble DubbleShr(struct Dubble x) { struct Dubble d; d.lo = x.lo >> 1 | x.hi << 63; d.hi = x.hi >> 1; return d; } static inline unsigned DubbleLte(struct Dubble a, struct Dubble b) { return a.hi == b.hi ? a.lo <= b.lo : a.hi <= b.hi; } static struct Dubble DubbleMul(u64 a, u64 b) { u64 x, y, t; struct Dubble d; x = (a & 0xffffffff) * (b & 0xffffffff); t = x >> 32; x &= 0xffffffff; t += (a >> 32) * (b & 0xffffffff); x += (t & 0xffffffff) << 32; y = t >> 32; t = x >> 32; x &= 0xffffffff; t += (b >> 32) * (a & 0xffffffff); x += (t & 0xffffffff) << 32; y += t >> 32; y += (a >> 32) * (b >> 32); d.lo = x; d.hi = y; return d; } static struct Dubble DubbleImul(u64 a, u64 b) { unsigned s, t; struct Dubble p; if ((s = a >> 63)) a = -a; if ((t = b >> 63)) b = -b; p = DubbleMul(a, b); return s ^ t ? DubbleNeg(p) : p; } static struct Dubble DubbleDiv(struct Dubble a, u64 b, u64 *r) { u64 s; int n, c; struct Dubble d, q, t; d.lo = b, d.hi = 0; q.lo = 0, q.hi = 0; for (n = 0; DubbleLte(d, a) && n < 128; ++n) { d = DubbleShl(d); } for (; n > 0; --n) { t = a; d = DubbleShr(d); q = DubbleShl(q); s = a.lo, a.lo -= d.lo + 0, c = a.lo > s; s = a.hi, a.hi -= d.hi + c, c = a.hi > s; if (c) { a = t; } else { q.lo++; } } *r = a.lo; return q; } static struct Dubble DubbleIdiv(struct Dubble a, u64 b, u64 *r) { unsigned s, t; struct Dubble q; if ((s = a.hi >> 63)) a = DubbleNeg(a); if ((t = b >> 63)) b = -b; q = DubbleDiv(a, b, r); if (s ^ t) q = DubbleNeg(q); if (s) *r = -*r; return q; } void OpDivAlAhAxEbSigned(P) { i8 y, r; i16 x, q; x = Get16(m->ax); y = Load8(GetModrmRegisterBytePointerRead1(A)); if (!y) RaiseDivideError(m); if (x == INT16_MIN) RaiseDivideError(m); q = x / y; r = x % y; if (q != (i8)q) RaiseDivideError(m); m->al = q & 0xff; m->ah = r & 0xff; } void OpDivAlAhAxEbUnsigned(P) { u8 y, r; u16 x, q; x = Get16(m->ax); y = Load8(GetModrmRegisterBytePointerRead1(A)); if (!y) RaiseDivideError(m); q = x / y; r = x % y; if (q > UINT8_MAX) RaiseDivideError(m); m->al = q & 0xff; m->ah = r & 0xff; } static void OpDivRdxRaxEvqpSigned64(P, u8 *p) { #ifdef HAVE_INT128 i64 y, r; __int128 x, q; x = (unsigned __int128)Get64(m->dx) << 64 | Get64(m->ax); y = Load64(p); if (!y) RaiseDivideError(m); if (x == (unsigned __int128)UINT64_C(0x8000000000000000) << 64) { RaiseDivideError(m); } q = x / y; r = x % y; if (q != (i64)q) RaiseDivideError(m); Put64(m->ax, q); Put64(m->dx, r); #else u64 d, r; struct Dubble q; q.lo = Get64(m->ax); q.hi = Get64(m->dx); d = Load64(p); if (!d) RaiseDivideError(m); if (!q.lo && q.hi == 0x8000000000000000) RaiseDivideError(m); q = DubbleIdiv(q, d, &r); if ((i64)q.lo < 0 && (i64)q.hi != -1) RaiseDivideError(m); if ((i64)q.lo >= 0 && q.hi) RaiseDivideError(m); Put64(m->ax, q.lo); Put64(m->dx, r); #endif } static void OpDivRdxRaxEvqpSigned32(P, u8 *p) { i32 y, r; i64 x, q; x = (u64)Get32(m->dx) << 32 | Get32(m->ax); y = Load32(p); if (!y) RaiseDivideError(m); if (x == INT64_MIN) RaiseDivideError(m); q = x / y; r = x % y; if (q != (i32)q) RaiseDivideError(m); Put64(m->ax, (u32)q); Put64(m->dx, (u32)r); } static void OpDivRdxRaxEvqpSigned16(P, u8 *p) { i16 y, r; i32 x, q; x = (u32)Get16(m->dx) << 16 | Get16(m->ax); y = Load16(p); if (!y) RaiseDivideError(m); if (x == INT32_MIN) RaiseDivideError(m); q = x / y; r = x % y; if (q != (i16)q) RaiseDivideError(m); Put16(m->ax, q); Put16(m->dx, r); } static void OpDivRdxRaxEvqpUnsigned16(P, u8 *p) { u16 y, r; u32 x, q; x = (u32)Get16(m->dx) << 16 | Get16(m->ax); y = Load16(p); if (!y) RaiseDivideError(m); q = x / y; r = x % y; if (q > UINT16_MAX) RaiseDivideError(m); Put16(m->ax, q); Put16(m->dx, r); } static void OpDivRdxRaxEvqpUnsigned32(P, u8 *p) { u32 y, r; u64 x, q; x = (u64)Get32(m->dx) << 32 | Get32(m->ax); y = Load32(p); if (!y) RaiseDivideError(m); q = x / y; r = x % y; if (q > UINT32_MAX) RaiseDivideError(m); Put64(m->ax, (u32)q); Put64(m->dx, (u32)r); } static void OpDivRdxRaxEvqpUnsigned64(P, u8 *p) { #ifdef HAVE_INT128 u64 y, r; unsigned __int128 x, q; x = (unsigned __int128)Get64(m->dx) << 64 | Get64(m->ax); y = Load64(p); if (!y) RaiseDivideError(m); q = x / y; r = x % y; if (q > UINT64_MAX) RaiseDivideError(m); Put64(m->ax, q); Put64(m->dx, r); #else u64 d, r; struct Dubble q; q.lo = Get64(m->ax); q.hi = Get64(m->dx); d = Load64(p); if (!d) RaiseDivideError(m); q = DubbleDiv(q, d, &r); if (q.hi) RaiseDivideError(m); Put64(m->ax, q.lo); Put64(m->dx, r); #endif } void OpDivRdxRaxEvqpSigned(P) { u8 *p = GetModrmRegisterWordPointerReadOszRexw(A); if (Rexw(rde)) { OpDivRdxRaxEvqpSigned64(A, p); } else if (!Osz(rde)) { OpDivRdxRaxEvqpSigned32(A, p); } else { OpDivRdxRaxEvqpSigned16(A, p); } } void OpDivRdxRaxEvqpUnsigned(P) { u8 *p = GetModrmRegisterWordPointerReadOszRexw(A); if (Rexw(rde)) { OpDivRdxRaxEvqpUnsigned64(A, p); } else if (!Osz(rde)) { OpDivRdxRaxEvqpUnsigned32(A, p); } else { OpDivRdxRaxEvqpUnsigned16(A, p); } } void OpMulAxAlEbSigned(P) { u8 *p; i16 ax; unsigned of; p = GetModrmRegisterBytePointerRead1(A); ax = (i8)Get8(m->ax) * (i8)Load8(p); of = ax != (i8)ax; m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); Put16(m->ax, ax); } void OpMulAxAlEbUnsigned(P) { u8 *p; int ax; unsigned of; p = GetModrmRegisterBytePointerRead1(A); ax = Get8(m->ax) * Load8(p); of = ax != (u8)ax; m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); Put16(m->ax, ax); } static void OpMulRdxRaxEvqpSigned64(struct Machine *m, i64 x) { #ifdef HAVE_INT128 __int128 rdxrax = (__int128)(i64)Get64(m->ax) * x; unsigned of = rdxrax != (i64)rdxrax; Put64(m->ax, rdxrax); Put64(m->dx, rdxrax >> 64); #else struct Dubble rdxrax = DubbleImul(Get64(m->ax), x); unsigned of = !!(rdxrax.hi + (rdxrax.lo >> 63)); Put64(m->ax, rdxrax.lo); Put64(m->dx, rdxrax.hi); #endif m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); } void OpMulRdxRaxEvqpSigned(P) { u8 *p = GetModrmRegisterWordPointerReadOszRexw(A); if (Rexw(rde)) { OpMulRdxRaxEvqpSigned64(m, Load64(p)); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = sav0 "c", // call function OpMulRdxRaxEvqpSigned64); } } else if (!Osz(rde)) { i64 edxeax = (i64)(i32)Get32(m->ax) * (i32)Load32(p); unsigned of = edxeax != (i32)edxeax; Put64(m->ax, (u32)edxeax); Put64(m->dx, edxeax >> 32); m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); } else { i32 dxax = (i32)(i16)Get16(m->ax) * (i16)Load16(p); unsigned of = dxax != (i16)dxax; Put16(m->ax, dxax); Put16(m->dx, dxax >> 16); m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); } } static void OpMulRdxRaxEvqpUnsigned64(struct Machine *m, u64 x) { #ifdef HAVE_INT128 unsigned __int128 rdxrax = (unsigned __int128)Get64(m->ax) * x; unsigned of = (u64)rdxrax != rdxrax; Put64(m->ax, rdxrax); Put64(m->dx, rdxrax >> 64); #else struct Dubble rdxrax = DubbleMul(Get64(m->ax), x); unsigned of = !!rdxrax.hi; Put64(m->ax, rdxrax.lo); Put64(m->dx, rdxrax.hi); #endif m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); } static void OpMulRdxRaxEvqpUnsigned32(struct Machine *m, u64 x) { u64 edxeax; unsigned of; edxeax = (u64)Get32(m->ax) * x; of = (u32)edxeax != edxeax; Put64(m->ax, (u32)edxeax); Put64(m->dx, edxeax >> 32); m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); } void OpMulRdxRaxEvqpUnsigned(P) { u8 *p; u32 dxax; unsigned of; p = GetModrmRegisterWordPointerReadOszRexw(A); if (Rexw(rde)) { OpMulRdxRaxEvqpUnsigned64(m, Load64(p)); if (IsMakingPath(m)) { #ifdef HAVE_INT128 Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call micro-op !GetNeededFlags(m, m->ip, CF | OF) ? (u64)(uintptr_t)JustMulAxDx : (u64)(uintptr_t)MulAxDx); #else Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = sav0 "c", // call function OpMulRdxRaxEvqpUnsigned64); #endif } } else if (!Osz(rde)) { OpMulRdxRaxEvqpUnsigned32(m, Load32(p)); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = sav0 "c", // call function OpMulRdxRaxEvqpUnsigned32); } } else { dxax = (u32)(u16)Get16(m->ax) * (u16)Load16(p); of = (u16)dxax != dxax; Put16(m->ax, dxax); Put16(m->dx, dxax >> 16); m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); } } static void AluImul(P, u8 *a, u8 *b) { unsigned of; if (Rexw(rde)) { #ifdef HAVE_INT128 __int128 z; z = (__int128)(i64)Get64(a) * (i64)Load64(b); of = z != (i64)z; Put64(RegRexrReg(m, rde), z); #else struct Dubble p; p = DubbleImul(Get64(a), Load64(b)); of = !!(p.hi + (p.lo >> 63)); Put64(RegRexrReg(m, rde), p.lo); #endif } else if (!Osz(rde)) { i64 z; z = (i64)(i32)Get32(a) * (i32)Load32(b); of = z != (i32)z; Put64(RegRexrReg(m, rde), (u32)z); } else { i32 z; z = (i32)(i16)Get16(a) * (i16)Load16(b); of = z != (i16)z; Put16(RegRexrReg(m, rde), z); } m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); } void OpImulGvqpEvqp(P) { AluImul(A, RegRexrReg(m, rde), GetModrmRegisterWordPointerReadOszRexw(A)); #ifdef HAVE_INT128 if (IsMakingPath(m) && Rexw(rde)) { Jitter(A, "z3A" // res0 = GetReg[force64bit](RexrReg) "r0s1=" // sav1 = res0 "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "s0a2=" // arg2 = machine "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "m" // res0 = Imul64(arg0, arg1, machine) "r0z3C", // PutReg[force64bit](RexrReg, res0) !GetNeededFlags(m, m->ip, CF | OF) ? (u64)(uintptr_t)JustMul64 : (u64)(uintptr_t)Imul64); } #endif if (IsMakingPath(m) && !Rexw(rde) && !Osz(rde)) { Jitter(A, "z2A" // res0 = GetReg[force32bit](RexrReg) "r0s1=" // sav1 = res0 "z2B" // res0 = GetRegOrMem[force32bit](RexbRm) "s0a2=" // arg2 = machine "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "m" // res0 = Imul32(arg0, arg1, machine) "r0z2C", // PutReg[force32bit](RexrReg, res0) !GetNeededFlags(m, m->ip, CF | OF) ? (u64)(uintptr_t)JustMul32 : (u64)(uintptr_t)Imul32); } } void OpImulGvqpEvqpImm(P) { u8 b[8]; Put64(b, uimm0); AluImul(A, GetModrmRegisterWordPointerReadOszRexw(A), b); #ifdef HAVE_INT128 if (IsMakingPath(m) && Rexw(rde)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "s0a2=" // arg2 = machine "a1i" // arg1 = uimm0 "t" // arg0 = res0 "m" // res0 = Imul64(arg0, arg1, machine) "r0z3C", // PutReg[force64bit](RexrReg, res0) uimm0, !GetNeededFlags(m, m->ip, CF | OF) ? (u64)(uintptr_t)JustMul64 : (u64)(uintptr_t)Imul64); } #endif if (IsMakingPath(m) && !Rexw(rde) && !Osz(rde)) { Jitter(A, "z2B" // res0 = GetRegOrMem[force32bit](RexbRm) "s0a2=" // arg2 = machine "a1i" // arg1 = uimm0 "t" // arg0 = res0 "m" // res0 = Imul32(arg0, arg1, machine) "r0z2C", // PutReg[force32bit](RexrReg, res0) uimm0, !GetNeededFlags(m, m->ip, CF | OF) ? (u64)(uintptr_t)JustMul32 : (u64)(uintptr_t)Imul32); } } #ifndef DISABLE_BMI2 static void OpAdx(P, i64 op64(u64, u64, struct Machine *), i64 op32(u64, u64, struct Machine *)) { if (Rexw(rde)) { Put64(RegRexrReg(m, rde), op64(Get64(RegRexrReg(m, rde)), Load64(GetModrmRegisterWordPointerRead8(A)), m)); if (IsMakingPath(m)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force32bit](RexbRm) "r0s1=" // sav1 = res0 "z3A" // res0 = GetReg[force32bit](RexrReg) "s0a2=" // arg2 = machine "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "m" // call micro-op "r0z3C", // PutReg(RexrReg, ) op64); } } else { Put64(RegRexrReg(m, rde), (u32)op32(Get32(RegRexrReg(m, rde)), Load32(GetModrmRegisterWordPointerRead4(A)), m)); if (IsMakingPath(m)) { Jitter(A, "z2B" // res0 = GetRegOrMem[force32bit](RexbRm) "r0s1=" // sav1 = res0 "z2A" // res0 = GetReg[force32bit](RexrReg) "s0a2=" // arg2 = machine "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "m" // call micro-op "r0z2C", // PutReg(RexrReg, ) op32); } } } static void OpMulx(P) { if (Rexw(rde)) { u64 x, y; x = Load64(GetModrmRegisterWordPointerRead8(A)); y = Get64(m->dx); #ifdef HAVE_INT128 unsigned __int128 z = (unsigned __int128)y * x; Put64(RegVreg(m, rde), z); Put64(RegRexrReg(m, rde), z >> 64); if (IsMakingPath(m)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "a3i" // arg3 = rexrreg "a2i" // arg2 = vreg "s0a1=" // arg1 = sav0 (machine) "t" // arg0 = res0 "m", // call micro-op RexrReg(rde), Vreg(rde), Mulx64); } #else struct Dubble z = DubbleMul(y, x); Put64(RegVreg(m, rde), z.lo); Put64(RegRexrReg(m, rde), z.hi); #endif } else { u64 x; x = Load32(GetModrmRegisterWordPointerRead4(A)); x *= Get32(m->dx); Put64(RegVreg(m, rde), (u32)x); Put64(RegRexrReg(m, rde), x >> 32); } } void Op2f6(P) { if (Osz(rde)) { OpAdx(A, Adcx64, Adcx32); } else if (Rep(rde) == 3) { OpAdx(A, Adox64, Adox32); } else if (Rep(rde) == 2) { OpMulx(A); } else { OpUdImpl(m); } } #endif /* DISABLE_BMI2 */ ================================================ FILE: blink/dll.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/dll.h" /** * Makes `succ` and its successors come after `elem`. * * It's required that `elem` and `succ` aren't part of the same list. */ void dll_splice_after(struct Dll *elem, struct Dll *succ) { struct Dll *tmp1, *tmp2; tmp1 = elem->next; tmp2 = succ->prev; elem->next = succ; succ->prev = elem; tmp2->next = tmp1; tmp1->prev = tmp2; } /** * Removes item from doubly-linked list. * * @param list is a doubly-linked list, where `!*list` means empty */ void dll_remove(struct Dll **list, struct Dll *elem) { if (*list == elem) { if ((*list)->prev == *list) { *list = 0; } else { *list = (*list)->prev; } } elem->next->prev = elem->prev; elem->prev->next = elem->next; elem->next = elem; elem->prev = elem; } /** * Inserts items into list, at the beginning. * * The resulting list will start with `elem`, followed by other items in * `elem`, followed by the items previously in `*list`. * * @param list is a doubly-linked list, where `!*list` means empty * @param elem must not be a member of `list`, or null for no-op */ void dll_make_first(struct Dll **list, struct Dll *elem) { if (elem) { if (!*list) { *list = elem->prev; } else { dll_splice_after(*list, elem); } } } /** * Inserts items into list, at the end. * * The resulting `*list` will end with `elem`, preceded by the other * items in `elem`, preceded by the items previously in `*list`. * * @param list is a doubly-linked list, where `!*list` means empty * @param elem must not be a member of `list`, or null for no-op */ void dll_make_last(struct Dll **list, struct Dll *elem) { if (elem) { dll_make_first(list, elem->next); *list = elem; } } ================================================ FILE: blink/dll.h ================================================ #ifndef BLINK_DLL_H_ #define BLINK_DLL_H_ #include #define DLL_CONTAINER(t, f, p) ((t *)(((char *)(p)) - offsetof(t, f))) struct Dll { struct Dll *next; struct Dll *prev; }; static inline void dll_init(struct Dll *e) { e->next = e; e->prev = e; } static inline int dll_is_empty(struct Dll *list) { return !list; } static inline struct Dll *dll_last(struct Dll *list) { return list; } static inline struct Dll *dll_first(struct Dll *list) { struct Dll *first = 0; if (list) first = list->next; return first; } static inline struct Dll *dll_next(struct Dll *list, struct Dll *e) { struct Dll *next = 0; if (e != list) next = e->next; return next; } static inline struct Dll *dll_prev(struct Dll *list, struct Dll *e) { struct Dll *prev = 0; if (e != list->next) prev = e->prev; return prev; } void dll_make_first(struct Dll **, struct Dll *); void dll_make_last(struct Dll **, struct Dll *); void dll_remove(struct Dll **, struct Dll *); void dll_splice_after(struct Dll *, struct Dll *); #endif /* BLINK_DLL_H_ */ ================================================ FILE: blink/doublenul.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/util.h" const char *doublenul(const char *s, unsigned i) { size_t n; while (i--) { if ((n = strlen(s))) { s += n + 1; } else { return 0; } } return s; } ================================================ FILE: blink/elf.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/elf.h" #include #include #include #include #include #include "blink/builtin.h" #include "blink/checked.h" #include "blink/endian.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/util.h" i64 GetElfMemorySize(const Elf64_Ehdr_ *ehdr, size_t size, i64 *base) { size_t off; unsigned i; i64 x, y, lo, hi, res; const Elf64_Phdr_ *phdr; lo = INT64_MAX; hi = INT64_MIN; if (Read64(ehdr->phoff) < size) { for (i = 0; i < Read16(ehdr->phnum); ++i) { off = Read64(ehdr->phoff) + Read16(ehdr->phentsize) * i; if (off + Read16(ehdr->phentsize) > size) return -1; phdr = (const Elf64_Phdr_ *)((const u8 *)ehdr + off); if (Read32(phdr->type) == PT_LOAD_) { x = Read64(phdr->vaddr); if (ckd_add(&y, x, (i64)Read64(phdr->memsz))) return -1; lo = MIN(x, lo); hi = MAX(y, hi); } } } lo &= -FLAG_pagesize; if (ckd_sub(&res, hi, lo)) return -1; *base = lo; return res; } char *GetElfString(const Elf64_Ehdr_ *elf, // validated size_t mapsize, // validated const char *strtab, // validated size_t rva) { // foreign if (!strtab) return 0; if (rva >= mapsize) return 0; const char *addr = strtab + rva; if (!memchr(addr, 0, mapsize - rva)) return 0; return (char *)addr; } Elf64_Phdr_ *GetElfProgramHeaderAddress(const Elf64_Ehdr_ *elf, // size_t mapsize, // u16 i) { // uint64_t off; if (i >= Read16(elf->phnum)) return 0; if (Read64(elf->phoff) <= 0) return 0; if (Read64(elf->phoff) >= mapsize) return 0; if (Read16(elf->phentsize) < sizeof(Elf64_Phdr_)) return 0; off = Read64(elf->phoff) + (unsigned)i * Read16(elf->phentsize); if (off > mapsize) return 0; return (Elf64_Phdr_ *)((char *)elf + off); } Elf64_Shdr_ *GetElfSectionHeaderAddress(const Elf64_Ehdr_ *elf, // size_t mapsize, // u16 i) { // uint64_t off; if (i >= Read16(elf->shnum)) return 0; if (Read64(elf->shoff) <= 0) return 0; if (Read64(elf->shoff) >= mapsize) return 0; if (Read16(elf->shentsize) < sizeof(Elf64_Shdr_)) return 0; off = Read64(elf->shoff) + (unsigned)i * Read16(elf->shentsize); if (off > mapsize) return 0; return (Elf64_Shdr_ *)((char *)elf + off); } // note: should not be used on bss section void *GetElfSectionAddress(const Elf64_Ehdr_ *elf, // validated size_t mapsize, // validated const Elf64_Shdr_ *shdr) { // foreign uint64_t last; if (!shdr) return 0; if (!Read64(shdr->size)) return 0; if (ckd_add(&last, Read64(shdr->offset), Read64(shdr->size))) return 0; if (last > mapsize) return 0; return (char *)elf + Read64(shdr->offset); } char *GetElfSectionNameStringTable(const Elf64_Ehdr_ *elf, // size_t mapsize) { // return (char *)GetElfSectionAddress( elf, mapsize, GetElfSectionHeaderAddress(elf, mapsize, Read16(elf->shstrndx))); } const char *GetElfSectionName(const Elf64_Ehdr_ *elf, // size_t mapsize, // Elf64_Shdr_ *shdr) { // if (!shdr) return 0; return GetElfString(elf, mapsize, GetElfSectionNameStringTable(elf, mapsize), Read32(shdr->name)); } static char *GetElfStringTableImpl(const Elf64_Ehdr_ *elf, // size_t mapsize, // const char *kind) { // int i; const char *name; Elf64_Shdr_ *shdr; for (i = 0; i < Read16(elf->shnum); ++i) { if ((shdr = GetElfSectionHeaderAddress(elf, mapsize, i)) && Read32(shdr->type) == SHT_STRTAB_ && (name = GetElfSectionName(elf, mapsize, shdr)) && !strcmp(name, kind)) { return (char *)GetElfSectionAddress(elf, mapsize, shdr); } } return 0; } char *GetElfStringTable(const Elf64_Ehdr_ *elf, size_t mapsize) { char *res; if (!(res = GetElfStringTableImpl(elf, mapsize, ".strtab"))) { res = GetElfStringTableImpl(elf, mapsize, ".dynstr"); } return res; } static Elf64_Sym_ *GetElfSymbolTableImpl(const Elf64_Ehdr_ *elf, // size_t mapsize, // int *out_count, // u32 kind) { // int i; Elf64_Shdr_ *shdr; for (i = Read16(elf->shnum); i > 0; --i) { if ((shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1)) && Read64(shdr->entsize) == sizeof(Elf64_Sym_) && Read32(shdr->type) == kind) { if (out_count) { *out_count = Read64(shdr->size) / sizeof(Elf64_Sym_); } return (Elf64_Sym_ *)GetElfSectionAddress(elf, mapsize, shdr); } } return 0; } Elf64_Sym_ *GetElfSymbolTable(const Elf64_Ehdr_ *elf, // size_t mapsize, // int *out_count) { // Elf64_Sym_ *res; if (!(res = GetElfSymbolTableImpl(elf, mapsize, out_count, SHT_SYMTAB_))) { res = GetElfSymbolTableImpl(elf, mapsize, out_count, SHT_DYNSYM_); } return res; } ================================================ FILE: blink/elf.h ================================================ #ifndef BLINK_ELF_H_ #define BLINK_ELF_H_ #include #include "blink/types.h" /** * @fileoverview Executable and Linkable Format Definitions. */ #define EI_MAG0_ 0 #define EI_MAG1_ 1 #define EI_MAG2_ 2 #define EI_MAG3_ 3 #define EI_NIDENT_ 16 #define ELFMAG_ "\177ELF" #define ELFMAG0_ 0x7f #define ELFMAG1_ 'E' #define ELFMAG2_ 'L' #define ELFMAG3_ 'F' #define SELFMAG_ 4 #define EI_CLASS_ 4 #define ELFCLASSNONE_ 0 #define ELFCLASS32_ 1 #define ELFCLASS64_ 2 #define ELFCLASSNUM_ 3 #define EI_DATA_ 5 #define ELFDATANONE_ 0 #define ELFDATA2LSB_ 1 #define ELFDATA2MSB_ 2 #define ELFDATANUM_ 3 #define EI_VERSION_ 6 #define EI_OSABI_ 7 #define ELFOSABI_NONE_ 0 #define ELFOSABI_SYSV_ 0 #define ELFOSABI_HPUX_ 1 #define ELFOSABI_NETBSD_ 2 #define ELFOSABI_LINUX_ 3 #define ELFOSABI_GNU_ 3 #define ELFOSABI_SOLARIS_ 6 #define ELFOSABI_AIX_ 7 #define ELFOSABI_IRIX_ 8 #define ELFOSABI_FREEBSD_ 9 #define ELFOSABI_TRU64_ 10 #define ELFOSABI_MODESTO_ 11 #define ELFOSABI_OPENBSD_ 12 #define ELFOSABI_ARM_ 97 #define ELFOSABI_STANDALONE_ 255 #define EI_ABIVERSION_ 8 #define EI_PAD_ 9 #define ET_NONE_ 0 #define ET_REL_ 1 #define ET_EXEC_ 2 #define ET_DYN_ 3 #define ET_CORE_ 4 #define ET_NUM_ 5 #define ET_LOOS_ 0xfe00 #define ET_HIOS_ 0xfeff #define ET_LOPROC_ 0xff00 #define ET_HIPROC_ 0xffff #define EM_NONE_ 0 #define EM_M32_ 1 #define EM_386_ 3 #define EM_S390_ 22 #define EM_ARM_ 40 #define EM_NEXGEN32E_ 62 #define EM_X86_64_ EM_NEXGEN32E #define EM_IA32E_ EM_NEXGEN32E #define EM_AMD64_ EM_NEXGEN32E #define EM_PDP11_ 65 #define EM_CRAYNV2_ 172 #define EM_L10M_ 180 #define EM_K10M_ 181 #define EM_AARCH64_ 183 #define EM_CUDA_ 190 #define EM_Z80_ 220 #define EM_RISCV_ 243 #define EM_BPF_ 247 #define GRP_COMDAT_ 0x1 #define STN_UNDEF_ 0 #define EV_NONE_ 0 #define EV_CURRENT_ 1 #define EV_NUM_ 2 #define SYMINFO_NONE_ 0 #define SYMINFO_CURRENT_ 1 #define SYMINFO_NUM_ 2 #define SYMINFO_BT_SELF_ 0xffff #define SYMINFO_BT_PARENT_ 0xfffe #define SYMINFO_BT_LOWRESERVE_ 0xff00 #define SYMINFO_FLG_DIRECT_ 0x0001 #define SYMINFO_FLG_PASSTHRU_ 0x0002 #define SYMINFO_FLG_COPY_ 0x0004 #define SYMINFO_FLG_LAZYLOAD_ 0x0008 #define PT_NULL_ 0 #define PT_LOAD_ 1 #define PT_DYNAMIC_ 2 #define PT_INTERP_ 3 #define PT_NOTE_ 4 #define PT_SHLIB_ 5 #define PT_PHDR_ 6 #define PT_TLS_ 7 #define PT_NUM_ 8 #define PT_LOOS_ 0x60000000 #define PT_GNU_EH_FRAME_ 0x6474e550 #define PT_GNU_STACK_ 0x6474e551 #define PT_GNU_RELRO_ 0x6474e552 #define PT_OPENBSD_RANDOMIZE_ 0x65a3dbe6 #define PT_LOSUNW_ 0x6ffffffa #define PT_SUNWBSS_ 0x6ffffffa #define PT_SUNWSTACK_ 0x6ffffffb #define PT_HISUNW_ 0x6fffffff #define PT_HIOS_ 0x6fffffff #define PT_LOPROC_ 0x70000000 #define PT_HIPROC_ 0x7fffffff #define PN_XNUM_ 0xffff #define PF_X_ 1 #define PF_W_ 2 #define PF_R_ 4 #define PF_MASKOS_ 0x0ff00000 #define PF_MASKPROC_ 0xf0000000 #define R_X86_64_NONE_ 0 #define R_X86_64_64_ 1 #define R_X86_64_PC32_ 2 #define R_X86_64_GOT32_ 3 #define R_X86_64_PLT32_ 4 #define R_X86_64_COPY_ 5 #define R_X86_64_GLOB_DAT_ 6 #define R_X86_64_JUMP_SLOT_ 7 #define R_X86_64_RELATIVE_ 8 #define R_X86_64_GOTPCREL_ 9 #define R_X86_64_32_ 10 #define R_X86_64_32S_ 11 #define R_X86_64_16_ 12 #define R_X86_64_PC16_ 13 #define R_X86_64_8_ 14 #define R_X86_64_PC8_ 15 #define R_X86_64_DTPMOD64_ 16 #define R_X86_64_DTPOFF64_ 17 #define R_X86_64_TPOFF64_ 18 #define R_X86_64_TLSGD_ 19 #define R_X86_64_TLSLD_ 20 #define R_X86_64_DTPOFF32_ 21 #define R_X86_64_GOTTPOFF_ 22 #define R_X86_64_TPOFF32_ 23 #define R_X86_64_PC64_ 24 #define R_X86_64_GOTOFF64_ 25 #define R_X86_64_GOTPC32_ 26 #define R_X86_64_GOT64_ 27 #define R_X86_64_GOTPCREL64_ 28 #define R_X86_64_GOTPC64_ 29 #define R_X86_64_GOTPLT64_ 30 #define R_X86_64_PLTOFF64_ 31 #define R_X86_64_SIZE32_ 32 #define R_X86_64_SIZE64_ 33 #define R_X86_64_GOTPC32_TLSDESC_ 34 #define R_X86_64_TLSDESC_CALL_ 35 #define R_X86_64_TLSDESC_ 36 #define R_X86_64_IRELATIVE_ 37 #define R_X86_64_RELATIVE64_ 38 #define R_X86_64_GOTPCRELX_ 41 // 6 bytes #define R_X86_64_REX_GOTPCRELX_ 42 // 7 bytes #define R_X86_64_NUM_ 43 #define STB_LOCAL_ 0 #define STB_GLOBAL_ 1 #define STB_WEAK_ 2 #define STB_NUM_ 3 #define STB_LOOS_ 10 #define STB_GNU_UNIQUE_ 10 #define STB_HIOS_ 12 #define STB_LOPROC_ 13 #define STB_HIPROC_ 15 #define STT_NOTYPE_ 0 #define STT_OBJECT_ 1 #define STT_FUNC_ 2 #define STT_SECTION_ 3 #define STT_FILE_ 4 #define STT_COMMON_ 5 #define STT_TLS_ 6 #define STT_NUM_ 7 #define STT_LOOS_ 10 #define STT_GNU_IFUNC_ 10 #define STT_HIOS_ 12 #define STT_LOPROC_ 13 #define STT_HIPROC_ 15 #define STV_DEFAULT_ 0 #define STV_INTERNAL_ 1 #define STV_HIDDEN_ 2 #define STV_PROTECTED_ 3 #define SHN_UNDEF_ 0 #define SHN_LORESERVE_ 0xff00 #define SHN_LOPROC_ 0xff00 #define SHN_BEFORE_ 0xff00 #define SHN_AFTER_ 0xff01 #define SHN_HIPROC_ 0xff1f #define SHN_LOOS_ 0xff20 #define SHN_HIOS_ 0xff3f #define SHN_ABS_ 0xfff1 #define SHN_COMMON_ 0xfff2 #define SHN_XINDEX_ 0xffff #define SHN_HIRESERVE_ 0xffff #define SHF_WRITE_ (1 << 0) #define SHF_ALLOC_ (1 << 1) #define SHF_EXECINSTR_ (1 << 2) #define SHF_MERGE_ (1 << 4) #define SHF_STRINGS_ (1 << 5) #define SHF_INFO_LINK_ (1 << 6) #define SHF_LINK_ORDER_ (1 << 7) #define SHF_OS_NONCONFORMING_ (1 << 8) #define SHF_GROUP_ (1 << 9) #define SHF_TLS_ (1 << 10) #define SHF_COMPRESSED_ (1 << 11) #define SHF_MASKOS_ 0x0ff00000 #define SHF_MASKPROC_ 0xf0000000 #define SHF_ORDERED_ (1 << 30) #define SHF_EXCLUDE_ (1U << 31) #define ELFCOMPRESS_ZLIB_ 1 #define ELFCOMPRESS_LOOS_ 0x60000000 #define ELFCOMPRESS_HIOS_ 0x6fffffff #define ELFCOMPRESS_LOPROC_ 0x70000000 #define ELFCOMPRESS_HIPROC_ 0x7fffffff #define SHT_NULL_ 0 #define SHT_PROGBITS_ 1 #define SHT_SYMTAB_ 2 #define SHT_STRTAB_ 3 #define SHT_RELA_ 4 #define SHT_HASH_ 5 #define SHT_DYNAMIC_ 6 #define SHT_NOTE_ 7 #define SHT_NOBITS_ 8 #define SHT_REL_ 9 #define SHT_SHLIB_ 10 #define SHT_DYNSYM_ 11 #define SHT_INIT_ARRAY_ 14 #define SHT_FINI_ARRAY_ 15 #define SHT_PREINIT_ARRAY_ 16 #define SHT_GROUP_ 17 #define SHT_SYMTAB_SHNDX_ 18 #define SHT_NUM_ 19 #define SHT_LOOS_ 0x60000000 #define SHT_GNU_ATTRIBUTES_ 0x6ffffff5 #define SHT_GNU_HASH_ 0x6ffffff6 #define SHT_GNU_LIBLIST_ 0x6ffffff7 #define SHT_CHECKSUM_ 0x6ffffff8 #define SHT_LOSUNW_ 0x6ffffffa #define SHT_SUNW_move_ 0x6ffffffa #define SHT_SUNW_COMDAT_ 0x6ffffffb #define SHT_SUNW_syminfo_ 0x6ffffffc #define SHT_GNU_verdef_ 0x6ffffffd #define SHT_GNU_verneed_ 0x6ffffffe #define SHT_GNU_versym_ 0x6fffffff #define SHT_HISUNW_ 0x6fffffff #define SHT_HIOS_ 0x6fffffff #define SHT_LOPROC_ 0x70000000 #define SHT_HIPROC_ 0x7fffffff #define SHT_LOUSER_ 0x80000000 #define SHT_HIUSER_ 0x8fffffff #define DT_NULL_ 0 #define DT_NEEDED_ 1 #define DT_PLTRELSZ_ 2 #define DT_PLTGOT_ 3 #define DT_HASH_ 4 #define DT_STRTAB_ 5 #define DT_SYMTAB_ 6 #define DT_RELA_ 7 #define DT_RELASZ_ 8 #define DT_RELAENT_ 9 #define DT_STRSZ_ 10 #define DT_SYMENT_ 11 #define DT_INIT_ 12 #define DT_FINI_ 13 #define DT_SONAME_ 14 #define DT_RPATH_ 15 #define DT_SYMBOLIC_ 16 #define DT_REL_ 17 #define DT_RELSZ_ 18 #define DT_RELENT_ 19 #define DT_PLTREL_ 20 #define DT_DEBUG_ 21 #define DT_TEXTREL_ 22 #define DT_JMPREL_ 23 #define DT_BIND_NOW_ 24 #define DT_INIT_ARRAY_ 25 #define DT_FINI_ARRAY_ 26 #define DT_INIT_ARRAYSZ_ 27 #define DT_FINI_ARRAYSZ_ 28 #define DT_RUNPATH_ 29 #define DT_FLAGS_ 30 #define DT_ENCODING_ 32 #define DT_PREINIT_ARRAY_ 32 #define DT_PREINIT_ARRAYSZ_ 33 #define DT_SYMTAB_SHNDX_ 34 #define DT_NUM_ 35 #define DT_LOOS_ 0x6000000d #define DT_HIOS_ 0x6ffff000 #define DT_LOPROC_ 0x70000000 #define DT_HIPROC_ 0x7fffffff #define DT_VALRNGLO_ 0x6ffffd00 #define DT_GNU_PRELINKED_ 0x6ffffdf5 #define DT_GNU_CONFLICTSZ_ 0x6ffffdf6 #define DT_GNU_LIBLISTSZ_ 0x6ffffdf7 #define DT_CHECKSUM_ 0x6ffffdf8 #define DT_PLTPADSZ_ 0x6ffffdf9 #define DT_MOVEENT_ 0x6ffffdfa #define DT_MOVESZ_ 0x6ffffdfb #define DT_FEATURE_1_ 0x6ffffdfc #define DT_POSFLAG_1_ 0x6ffffdfd #define DT_SYMINSZ_ 0x6ffffdfe #define DT_SYMINENT_ 0x6ffffdff #define DT_VALRNGHI_ 0x6ffffdff #define DT_VALTAGIDX_(tag) (DT_VALRNGHI - (tag)) #define DT_VALNUM_ 12 #define DT_ADDRRNGLO_ 0x6ffffe00 #define DT_GNU_HASH_ 0x6ffffef5 #define DT_TLSDESC_PLT_ 0x6ffffef6 #define DT_TLSDESC_GOT_ 0x6ffffef7 #define DT_GNU_CONFLICT_ 0x6ffffef8 #define DT_GNU_LIBLIST_ 0x6ffffef9 #define DT_CONFIG_ 0x6ffffefa #define DT_DEPAUDIT_ 0x6ffffefb #define DT_AUDIT_ 0x6ffffefc #define DT_PLTPAD_ 0x6ffffefd #define DT_MOVETAB_ 0x6ffffefe #define DT_SYMINFO_ 0x6ffffeff #define DT_ADDRRNGHI_ 0x6ffffeff #define DT_ADDRTAGIDX_(tag) (DT_ADDRRNGHI - (tag)) #define DT_ADDRNUM_ 11 #define DT_VERSYM_ 0x6ffffff0 #define DT_RELACOUNT_ 0x6ffffff9 #define DT_RELCOUNT_ 0x6ffffffa #define DT_FLAGS_1_ 0x6ffffffb #define DT_VERDEF_ 0x6ffffffc #define DT_VERDEFNUM_ 0x6ffffffd #define DT_VERNEED_ 0x6ffffffe #define DT_VERNEEDNUM_ 0x6fffffff #define DT_VERSIONTAGIDX_(tag) (DT_VERNEEDNUM - (tag)) #define DT_VERSIONTAGNUM_ 16 #define DT_AUXILIARY_ 0x7ffffffd #define DT_FILTER_ 0x7fffffff #define DT_EXTRATAGIDX_(tag) ((Elf32_Word) - ((Elf32_Sword)(tag) << 1 >> 1) - 1) #define DT_EXTRANUM_ 3 #define VER_NEED_NONE_ 0 #define VER_NEED_CURRENT_ 1 #define VER_NEED_NUM_ 2 #define VER_FLG_WEAK_ 0x2 #define ELF_NOTE_SOLARIS_ "SUNW Solaris" #define ELF_NOTE_GNU_ "GNU" #define ELF_NOTE_PAGESIZE_HINT_ 1 #define ELF_NOTE_ABI_ NT_GNU_ABI_TAG #define ELF_NOTE_OS_LINUX_ 0 #define ELF_NOTE_OS_GNU_ 1 #define ELF_NOTE_OS_SOLARIS2_ 2 #define ELF_NOTE_OS_FREEBSD_ 3 #define NT_GNU_ABI_TAG_ 1 #define NT_GNU_BUILD_ID_ 3 #define NT_GNU_GOLD_VERSION_ 4 #define EF_CPU32_ 0x00810000 #define DF_ORIGIN_ 0x00000001 #define DF_SYMBOLIC_ 0x00000002 #define DF_TEXTREL_ 0x00000004 #define DF_BIND_NOW_ 0x00000008 #define DF_STATIC_TLS_ 0x00000010 #define DF_1_NOW_ 0x00000001 #define DF_1_GLOBAL_ 0x00000002 #define DF_1_GROUP_ 0x00000004 #define DF_1_NODELETE_ 0x00000008 #define DF_1_LOADFLTR_ 0x00000010 #define DF_1_INITFIRST_ 0x00000020 #define DF_1_NOOPEN_ 0x00000040 #define DF_1_ORIGIN_ 0x00000080 #define DF_1_DIRECT_ 0x00000100 #define DF_1_TRANS_ 0x00000200 #define DF_1_INTERPOSE_ 0x00000400 #define DF_1_NODEFLIB_ 0x00000800 #define DF_1_NODUMP_ 0x00001000 #define DF_1_CONFALT_ 0x00002000 #define DF_1_ENDFILTEE_ 0x00004000 #define DF_1_DISPRELDNE_ 0x00008000 #define DF_1_DISPRELPND_ 0x00010000 #define DF_1_NODIRECT_ 0x00020000 #define DF_1_IGNMULDEF_ 0x00040000 #define DF_1_NOKSYMS_ 0x00080000 #define DF_1_NOHDR_ 0x00100000 #define DF_1_EDITED_ 0x00200000 #define DF_1_NORELOC_ 0x00400000 #define DF_1_SYMINTPOSE_ 0x00800000 #define DF_1_GLOBAUDIT_ 0x01000000 #define DF_1_SINGLETON_ 0x02000000 #define DF_1_STUB_ 0x04000000 #define DF_1_PIE_ 0x08000000 #define DTF_1_PARINIT_ 0x00000001 #define DTF_1_CONFEXP_ 0x00000002 #define DF_P1_LAZYLOAD_ 0x00000001 #define DF_P1_GROUPPERM_ 0x00000002 #define ELF64_ST_BIND_(val) (((u8)(val)) >> 4) #define ELF64_ST_TYPE_(val) ((val)&0xf) #define ELF64_ST_INFO_(bind, type) (((bind) << 4) + ((type)&0xf)) #define ELF64_ST_VISIBILITY_(o) ((o)&0x03) #define ELF64_R_SYM_(i) ((i) >> 32) #define ELF64_R_TYPE_(i) ((i)&0xffffffff) #define ELF64_R_INFO_(sym, type) ((((u64)(sym)) << 32) + (type)) #define ELF64_M_SYM_(info) ((info) >> 8) #define ELF64_M_SIZE_(info) ((u8)(info)) #define ELF64_M_INFO_(sym, size) (((sym) << 8) + (u8)(size)) #define NT_PRSTATUS_ 1 #define NT_PRFPREG_ 2 #define NT_FPREGSET_ 2 #define NT_PRPSINFO_ 3 #define NT_PRXREG_ 4 #define NT_TASKSTRUCT_ 4 #define NT_PLATFORM_ 5 #define NT_AUXV_ 6 #define NT_GWINDOWS_ 7 #define NT_ASRS_ 8 #define NT_PSTATUS_ 10 #define NT_PSINFO_ 13 #define NT_PRCRED_ 14 #define NT_UTSNAME_ 15 #define NT_LWPSTATUS_ 16 #define NT_LWPSINFO_ 17 #define NT_PRFPXREG_ 20 #define NT_SIGINFO_ 0x53494749 #define NT_FILE_ 0x46494c45 #define NT_PRXFPREG_ 0x46e62b7f #define NT_PPC_VMX_ 0x100 #define NT_PPC_SPE_ 0x101 #define NT_PPC_VSX_ 0x102 #define NT_PPC_TAR_ 0x103 #define NT_PPC_PPR_ 0x104 #define NT_PPC_DSCR_ 0x105 #define NT_PPC_EBB_ 0x106 #define NT_PPC_PMU_ 0x107 #define NT_PPC_TM_CGPR_ 0x108 #define NT_PPC_TM_CFPR_ 0x109 #define NT_PPC_TM_CVMX_ 0x10a #define NT_PPC_TM_CVSX_ 0x10b #define NT_PPC_TM_SPR_ 0x10c #define NT_PPC_TM_CTAR_ 0x10d #define NT_PPC_TM_CPPR_ 0x10e #define NT_PPC_TM_CDSCR_ 0x10f #define NT_X86_XSTATE_ 0x202 #define NT_S390_HIGH_GPRS_ 0x300 #define NT_S390_TIMER_ 0x301 #define NT_S390_TODCMP_ 0x302 #define NT_S390_TODPREG_ 0x303 #define NT_S390_CTRS_ 0x304 #define NT_S390_PREFIX_ 0x305 #define NT_S390_LAST_BREAK_ 0x306 #define NT_S390_SYSTEM_CALL_ 0x307 #define NT_S390_TDB_ 0x308 #define NT_S390_VXRS_LOW_ 0x309 #define NT_S390_VXRS_HIGH_ 0x30a #define NT_S390_GS_CB_ 0x30b #define NT_S390_GS_BC_ 0x30c #define NT_S390_RI_CB_ 0x30d #define NT_ARM_VFP_ 0x400 #define NT_ARM_TLS_ 0x401 #define NT_ARM_HW_BREAK_ 0x402 #define NT_ARM_HW_WATCH_ 0x403 #define NT_ARM_SYSTEM_CALL_ 0x404 #define NT_ARM_SVE_ 0x405 #define NT_ARM_PAC_MASK_ 0x406 #define NT_METAG_CBUF_ 0x500 #define NT_METAG_RPIPE_ 0x501 #define NT_METAG_TLS_ 0x502 #define NT_ARC_V2_ 0x600 #define NT_VMCOREDD_ 0x700 #define NT_VERSION_ 1 #define VER_DEF_NONE_ 0 #define VER_DEF_CURRENT_ 1 #define VER_DEF_NUM_ 2 #define VER_FLG_BASE_ 0x1 #define VER_FLG_WEAK_ 0x2 #define VER_NDX_LOCAL_ 0 #define VER_NDX_GLOBAL_ 1 #define VER_NDX_LORESERVE_ 0xff00 #define VER_NDX_ELIMINATE_ 0xff01 #define LL_NONE_ 0 #define LL_EXACT_MATCH_ (1 << 0) #define LL_IGNORE_INT_VER_ (1 << 1) #define LL_REQUIRE_MINOR_ (1 << 2) #define LL_EXPORTS_ (1 << 3) #define LL_DELAY_LOAD_ (1 << 4) #define LL_DELTA_ (1 << 5) #define R_BPF_NONE_ 0 #define R_BPF_MAP_FD_ 1 typedef struct Elf64_Ehdr_ { u8 ident[EI_NIDENT_]; u8 type[2]; // u16 u8 machine[2]; // u16 u8 version[4]; // u32 u8 entry[8]; // u64 u8 phoff[8]; // u64 u8 shoff[8]; // u64 u8 flags[4]; // u32 u8 ehsize[2]; // u16 u8 phentsize[2]; // u16 u8 phnum[2]; // u16 u8 shentsize[2]; // u16 u8 shnum[2]; // u16 u8 shstrndx[2]; // u16 } Elf64_Ehdr_; typedef struct Elf64_Phdr_ { u8 type[4]; // u32 u8 flags[4]; // u32 u8 offset[8]; // u64 u8 vaddr[8]; // u64 u8 paddr[8]; // u64 u8 filesz[8]; // u64 u8 memsz[8]; // u64 u8 align[8]; // u64 } Elf64_Phdr_; typedef struct Elf64_Shdr_ { u8 name[4]; // u32 u8 type[4]; // u32 u8 flags[8]; // u64 u8 addr[8]; // u64 u8 offset[8]; // u64 u8 size[8]; // u64 u8 link[4]; // u32 u8 info[4]; // u32 u8 addralign[8]; // u64 u8 entsize[8]; // u64 } Elf64_Shdr_; typedef struct Elf64_Rel_ { u8 offset[8]; // u64 u8 info[8]; // u64 } Elf64_Rel_; typedef struct Elf64_Rela_ { u8 offset[8]; // u64 u8 info[8]; // u64 u8 addend[8]; // i64 } Elf64_Rela_; typedef struct Elf64_Sym_ { u8 name[4]; // u32 u8 info; u8 other; u8 shndx[2]; // u16 u8 value[8]; // u64 u8 size[8]; // u64 } Elf64_Sym_; typedef struct Elf64_Syminfo_ { u8 boundto[2]; // u16 u8 flags[2]; // u16 } Elf64_Syminfo_; typedef struct Elf64_Chdr_ { u8 type[4]; // u32 u8 reserved[4]; // u32 u8 size[8]; // u64 u8 addralign[8]; // u64 } Elf64_Chdr_; typedef struct Elf64_Dyn_ { u8 tag[8]; // i64 u8 val[8]; // u64 } Elf64_Dyn_; typedef struct Elf64_Lib_ { u8 name[4]; // u32 u8 time_stamp[4]; // u32 u8 checksum[4]; // u32 u8 version[4]; // u32 u8 flags[4]; // u32 } Elf64_Lib_; typedef struct Elf64_Move_ { u8 value[8]; // u64 u8 info[8]; // u64 u8 poffset[8]; // u64 u8 repeat[2]; // u16 u8 stride[2]; // u16 } Elf64_Move_; typedef struct Elf64_Nhdr_ { u8 namesz[4]; // u32 u8 descsz[4]; // u32 u8 type[4]; // u32 } Elf64_Nhdr_; Elf64_Phdr_ *GetElfProgramHeaderAddress(const Elf64_Ehdr_ *, size_t, u16); char *GetElfStringTable(const Elf64_Ehdr_ *, size_t); Elf64_Shdr_ *GetElfSectionHeaderAddress(const Elf64_Ehdr_ *, size_t, u16); const char *GetElfSectionName(const Elf64_Ehdr_ *, size_t, Elf64_Shdr_ *); char *GetElfString(const Elf64_Ehdr_ *, size_t, const char *, size_t); char *GetElfSectionNameStringTable(const Elf64_Ehdr_ *, size_t); void *GetElfSectionAddress(const Elf64_Ehdr_ *, size_t, const Elf64_Shdr_ *); Elf64_Sym_ *GetElfSymbolTable(const Elf64_Ehdr_ *, size_t, int *); i64 GetElfMemorySize(const Elf64_Ehdr_ *, size_t, i64 *); #endif /* BLINK_ELF_H_ */ ================================================ FILE: blink/end.h ================================================ #ifndef BLINK_END_H_ #define BLINK_END_H_ #include "blink/flag.h" // many platforms complain about `end` / `_end` so we'll just pick some // arbitarry variable in the .bss section, which should be close enough #define IMAGE_END ((u8 *)&FLAG_noconnect) #endif /* BLINK_END_H_ */ ================================================ FILE: blink/endian.h ================================================ #ifndef BLINK_ENDIAN_H_ #define BLINK_ENDIAN_H_ #include "blink/builtin.h" #include "blink/swap.h" #include "blink/types.h" MICRO_OP_SAFE u8 Little8(u8 x) { return x; } MICRO_OP_SAFE u16 Little16(u16 x) { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ return SWAP16(x); #else return x; #endif } MICRO_OP_SAFE u32 Little32(u32 x) { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ return SWAP32(x); #else return x; #endif } MICRO_OP_SAFE u64 Little64(u64 x) { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ return SWAP64(x); #else return x; #endif } MICRO_OP_SAFE u8 Get8(const u8 *p) { return *p; } MICRO_OP_SAFE u16 Get16(const u8 *p) { #ifdef __OPTIMIZE__ u16 x; __builtin_memcpy(&x, p, 16 / 8); return Little16(x); #else return p[1] << 8 | p[0]; #endif } MICRO_OP_SAFE u32 Get32(const u8 *p) { #ifdef __OPTIMIZE__ u32 x; __builtin_memcpy(&x, p, 32 / 8); return Little32(x); #else return ((u32)p[0] << 000 | // (u32)p[1] << 010 | // (u32)p[2] << 020 | // (u32)p[3] << 030); #endif } MICRO_OP_SAFE u64 Get64(const u8 *p) { #ifdef __OPTIMIZE__ u64 x; __builtin_memcpy(&x, p, 64 / 8); return Little64(x); #else return ((u64)p[0] << 000 | // (u64)p[1] << 010 | // (u64)p[2] << 020 | // (u64)p[3] << 030 | // (u64)p[4] << 040 | // (u64)p[5] << 050 | // (u64)p[6] << 060 | // (u64)p[7] << 070); #endif } MICRO_OP_SAFE void Put8(u8 *p, u8 v) { *p = v; } MICRO_OP_SAFE void Put16(u8 *p, u16 v) { #ifdef __OPTIMIZE__ v = Little16(v); __builtin_memcpy(p, &v, 16 / 8); #else p[0] = v >> 000; p[1] = v >> 010; #endif } MICRO_OP_SAFE void Put32(u8 *p, u32 v) { #ifdef __OPTIMIZE__ v = Little32(v); __builtin_memcpy(p, &v, 32 / 8); #else p[0] = v >> 000; p[1] = v >> 010; p[2] = v >> 020; p[3] = v >> 030; #endif } MICRO_OP_SAFE void Put64(u8 *p, u64 v) { #ifdef __OPTIMIZE__ v = Little64(v); __builtin_memcpy(p, &v, 64 / 8); #else p[0] = v >> 000; p[1] = v >> 010; p[2] = v >> 020; p[3] = v >> 030; p[4] = v >> 040; p[5] = v >> 050; p[6] = v >> 060; p[7] = v >> 070; #endif } #define Read8 Get8 #define Read16 Get16 #define Read32 Get32 #define Read64 Get64 #define Write8 Put8 #define Write16 Put16 #define Write32 Put32 #define Write64 Put64 #endif /* BLINK_ENDIAN_H_ */ ================================================ FILE: blink/endswith.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/util.h" bool EndsWith(const char *s, const char *suffix) { size_t n, m; n = strlen(s); m = strlen(suffix); if (m > n) return false; return !memcmp(s + n - m, suffix, m); } ================================================ FILE: blink/errfd.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include "blink/assert.h" #include "blink/log.h" #include "blink/thread.h" #include "blink/tunables.h" #define EXIT_FAILURE_ERRFD_INIT 200 static int g_errfd; int WriteErrorString(const char *buf) { return WriteError(0, buf, strlen(buf)); } int WriteError(int fd, const char *buf, int len) { int rc, cs; #ifdef HAVE_PTHREAD_SETCANCELSTATE unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs)); #endif do rc = write(fd > 0 ? fd : g_errfd, buf, len); while (rc == -1 && errno == EINTR); #ifdef HAVE_PTHREAD_SETCANCELSTATE unassert(!pthread_setcancelstate(cs, 0)); #endif return rc; } void WriteErrorInit(void) { if (g_errfd) return; g_errfd = fcntl(2, F_DUPFD_CLOEXEC, kMinBlinkFd); if (g_errfd == -1) exit(EXIT_FAILURE_ERRFD_INIT); } ================================================ FILE: blink/errno.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/errno.h" #include #include "blink/builtin.h" static dontinline long ReturnErrno(int e) { errno = e; return -1; } long ebadf(void) { return ReturnErrno(EBADF); } long einval(void) { return ReturnErrno(EINVAL); } long eagain(void) { return ReturnErrno(EAGAIN); } long enomem(void) { return ReturnErrno(ENOMEM); } long enosys(void) { return ReturnErrno(ENOSYS); } long emfile(void) { return ReturnErrno(EMFILE); } long efault(void) { return ReturnErrno(EFAULT); } void *efault0(void) { efault(); return 0; } long eintr(void) { return ReturnErrno(EINTR); } long eoverflow(void) { return ReturnErrno(EOVERFLOW); } long enfile(void) { return ReturnErrno(ENFILE); } long esrch(void) { return ReturnErrno(ESRCH); } long eperm(void) { return ReturnErrno(EPERM); } long enotsup(void) { return ReturnErrno(ENOTSUP); } long enoent(void) { return ReturnErrno(ENOENT); } long enotdir(void) { return ReturnErrno(ENOTDIR); } long erange(void) { return ReturnErrno(ERANGE); } long eopnotsupp(void) { return ReturnErrno(EOPNOTSUPP); } long enodev(void) { return ReturnErrno(ENODEV); } long eacces(void) { return ReturnErrno(EACCES); } long eisdir(void) { return ReturnErrno(EISDIR); } long eexist(void) { return ReturnErrno(EEXIST); } long eloop(void) { return ReturnErrno(ELOOP); } long exdev(void) { return ReturnErrno(EXDEV); } long enametoolong(void) { return ReturnErrno(ENAMETOOLONG); } ================================================ FILE: blink/errno.h ================================================ #ifndef BLINK_ERRNO_H_ #define BLINK_ERRNO_H_ long eagain(void); long ebadf(void); long efault(void); void *efault0(void); long eintr(void); long einval(void); long enfile(void); long enoent(void); long enomem(void); long enosys(void); long emfile(void); long enotdir(void); long enotsup(void); long eoverflow(void); long eopnotsupp(void); long erange(void); long eperm(void); long esrch(void); long enodev(void); long eacces(void); long eisdir(void); long eexist(void); long eloop(void); long exdev(void); long enametoolong(void); #endif /* BLINK_ERRNO_H_ */ ================================================ FILE: blink/fds.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/fds.h" #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/errno.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/thread.h" #include "blink/vfs.h" void InitFds(struct Fds *fds) { fds->list = 0; unassert(!pthread_mutex_init(&fds->lock, 0)); } struct Fd *AddFd(struct Fds *fds, int fildes, int oflags) { struct Fd *fd; if (fildes >= 0) { if ((fd = (struct Fd *)calloc(1, sizeof(*fd)))) { dll_init(&fd->elem); fd->cb = &kFdCbHost; fd->fildes = fildes; fd->oflags = oflags; unassert(!pthread_mutex_init(&fd->lock, 0)); dll_make_first(&fds->list, &fd->elem); } return fd; } else { einval(); return 0; } } struct Fd *ForkFd(struct Fds *fds, struct Fd *fd, int fildes, int oflags) { struct Fd *fd2; if ((fd2 = AddFd(fds, fildes, oflags))) { if (fd) { fd2->path = fd->path ? strdup(fd->path) : 0; fd2->socktype = fd->socktype; fd2->norestart = fd->norestart; memcpy(&fd2->saddr, &fd->saddr, sizeof(fd->saddr)); } } return fd2; } struct Fd *GetFd(struct Fds *fds, int fildes) { bool lru; struct Dll *e; if (fildes >= 0) { lru = false; for (e = dll_first(fds->list); e; e = dll_next(fds->list, e)) { if (FD_CONTAINER(e)->fildes == fildes) { if (lru) { dll_remove(&fds->list, e); dll_make_first(&fds->list, e); } return FD_CONTAINER(e); } lru = true; } } ebadf(); return 0; } void LockFd(struct Fd *fd) { LOCK(&fd->lock); } void UnlockFd(struct Fd *fd) { UNLOCK(&fd->lock); } int CountFds(struct Fds *fds) { int n = 0; struct Dll *e; for (e = dll_first(fds->list); e; e = dll_next(fds->list, e)) { ++n; } return n; } void FreeFd(struct Fd *fd) { if (fd) { unassert(!pthread_mutex_destroy(&fd->lock)); free(fd->path); free(fd); } } void DestroyFds(struct Fds *fds) { struct Dll *e, *e2; for (e = dll_first(fds->list); e; e = e2) { e2 = dll_next(fds->list, e); dll_remove(&fds->list, e); FreeFd(FD_CONTAINER(e)); } unassert(!fds->list); unassert(!pthread_mutex_destroy(&fds->lock)); } static int GetFdSocketType(int fildes, int *type) { socklen_t len = sizeof(*type); return VfsGetsockopt(fildes, SOL_SOCKET, SO_TYPE, type, &len); } static bool IsNoRestartSocket(int fildes) { struct timeval tv = {0}; socklen_t len = sizeof(tv); VfsGetsockopt(fildes, SOL_SOCKET, SO_RCVTIMEO, &tv, &len); return tv.tv_sec || tv.tv_usec; } void InheritFd(struct Fd *fd) { #ifndef DISABLE_SOCKETS socklen_t addrlen; if (!fd) return; if (!GetFdSocketType(fd->fildes, &fd->socktype)) { fd->norestart = IsNoRestartSocket(fd->fildes); addrlen = sizeof(fd->saddr); VfsGetsockname(fd->fildes, (struct sockaddr *)&fd->saddr, &addrlen); } #endif } void AddStdFd(struct Fds *fds, int fildes) { int flags; if ((flags = VfsFcntl(fildes, F_GETFL, 0)) >= 0) { InheritFd(AddFd(fds, fildes, flags)); } } ================================================ FILE: blink/fds.h ================================================ #ifndef BLINK_FDS_H_ #define BLINK_FDS_H_ #include #include #include #include #include #include #include #include #include "blink/dll.h" #include "blink/thread.h" #include "blink/types.h" #define FD_CONTAINER(e) DLL_CONTAINER(struct Fd, elem, e) struct winsize; struct FdCb { int (*close)(int); ssize_t (*readv)(int, const struct iovec *, int); ssize_t (*writev)(int, const struct iovec *, int); int (*poll)(struct pollfd *, nfds_t, int); int (*tcgetattr)(int, struct termios *); int (*tcsetattr)(int, int, const struct termios *); int (*tcgetwinsize)(int, struct winsize *); int (*tcsetwinsize)(int, const struct winsize *); }; struct Fd { int fildes; // file descriptor int oflags; // host O_XXX constants int socktype; // host SOCK_XXX constants bool norestart; // is SO_RCVTIMEO in play? DIR *dirstream; // for getdents() lazilly struct Dll elem; pthread_mutex_t_ lock; const struct FdCb *cb; char *path; union { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_in6 sin6; } saddr; }; struct Fds { struct Dll *list; pthread_mutex_t_ lock; }; extern const struct FdCb kFdCbHost; void InitFds(struct Fds *); struct Fd *AddFd(struct Fds *, int, int); struct Fd *ForkFd(struct Fds *, struct Fd *, int, int); struct Fd *GetFd(struct Fds *, int); void LockFd(struct Fd *); void UnlockFd(struct Fd *); int CountFds(struct Fds *); void FreeFd(struct Fd *); void DestroyFds(struct Fds *); void InheritFd(struct Fd *); #endif /* BLINK_FDS_H_ */ ================================================ FILE: blink/flag.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/flag.h" #include "blink/builtin.h" bool FLAG_zero; bool FLAG_wantjit; bool FLAG_nolinear; bool FLAG_noconnect; bool FLAG_nologstderr; bool FLAG_alsologtostderr; int FLAG_strace; int FLAG_vabits; long FLAG_pagesize; u64 FLAG_skew; u64 FLAG_vaspace; u64 FLAG_aslrmask; u64 FLAG_stacktop; u64 FLAG_imagestart; i64 FLAG_automapend; i64 FLAG_automapstart; u64 FLAG_dyninterpaddr; const char *FLAG_logpath; #ifndef DISABLE_OVERLAYS const char *FLAG_overlays; #endif #ifndef DISABLE_VFS const char *FLAG_prefix; #endif const char *FLAG_bios; ================================================ FILE: blink/flag.h ================================================ #ifndef BLINK_FLAG_H_ #define BLINK_FLAG_H_ #include #include "blink/types.h" extern bool FLAG_zero; extern bool FLAG_wantjit; extern bool FLAG_nolinear; extern bool FLAG_noconnect; extern bool FLAG_nologstderr; extern bool FLAG_alsologtostderr; extern int FLAG_strace; extern int FLAG_vabits; extern long FLAG_pagesize; extern u64 FLAG_skew; extern u64 FLAG_vaspace; extern u64 FLAG_stacktop; extern u64 FLAG_aslrmask; extern u64 FLAG_imagestart; extern i64 FLAG_automapend; extern i64 FLAG_automapstart; extern u64 FLAG_dyninterpaddr; extern const char *FLAG_logpath; extern const char *FLAG_overlays; extern const char *FLAG_prefix; extern const char *FLAG_bios; #endif /* BLINK_FLAG_H_ */ ================================================ FILE: blink/flags.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/flags.h" #include "blink/builtin.h" #include "blink/debug.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/rde.h" #include "blink/stats.h" #include "blink/x86.h" bool GetParity(u8 b) { b ^= b >> 4; b ^= b >> 2; b ^= b >> 1; return ~b & 1; } void ImportFlags(struct Machine *m, u64 flags) { u64 mask = 0; mask |= 1 << FLAGS_CF; mask |= 1 << FLAGS_PF; mask |= 1 << FLAGS_AF; mask |= 1 << FLAGS_ZF; mask |= 1 << FLAGS_SF; mask |= 1 << FLAGS_TF; mask |= 1 << FLAGS_IF; mask |= 1 << FLAGS_DF; mask |= 1 << FLAGS_OF; mask |= 1 << FLAGS_NT; mask |= 1 << FLAGS_AC; mask |= 1 << FLAGS_ID; m->flags = (flags & mask) | (m->flags & ~mask); m->flags = SetFlag(m->flags, FLAGS_RF, false); m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1)); } u64 ExportFlags(u64 flags) { flags = SetFlag(flags, FLAGS_IOPL, 3); flags = SetFlag(flags, FLAGS_F1, true); flags = SetFlag(flags, FLAGS_F0, false); flags = flags & ~((u64)1 << FLAGS_PF); flags |= GetLazyParityBool(flags) << FLAGS_PF; return flags; } ================================================ FILE: blink/flags.h ================================================ #ifndef BLINK_FLAGS_H_ #define BLINK_FLAGS_H_ #include "blink/builtin.h" #include "blink/machine.h" #define FLAGS_CF 0 // carry flag #define FLAGS_VF 1 // always 1 #define FLAGS_PF 2 // parity flag #define FLAGS_F1 3 // always 0 #define FLAGS_AF 4 // auxiliary carry flag #define FLAGS_KF 5 // always 0 #define FLAGS_ZF 6 // zero flag #define FLAGS_SF 7 // sign flag #define FLAGS_TF 8 // trap flag #define FLAGS_IF 9 // interrupt enable flag #define FLAGS_DF 10 // direction flag #define FLAGS_OF 11 // overflow flag #define FLAGS_IOPL 12 // [12,13] i/o privilege level #define FLAGS_NT 14 // nested task #define FLAGS_F0 15 // always 0 #define FLAGS_RF 16 // resume flag #define FLAGS_VM 17 // virtual-8086 mode #define FLAGS_AC 18 // access control / alignment check #define FLAGS_VIF 19 // virtual interrupt flag #define FLAGS_VIP 20 // virtual interrupt pending #define FLAGS_ID 21 // id flag #define FLAGS_LP 24 // [24,31] low bits of last alu result (supposed to be 0) #define CF (1 << FLAGS_CF) #define PF (1 << FLAGS_PF) #define AF (1 << FLAGS_AF) #define ZF (1 << FLAGS_ZF) #define SF (1 << FLAGS_SF) #define OF (1 << FLAGS_OF) #define DF (1 << FLAGS_DF) #define RF (1 << FLAGS_RF) #define AC (1 << FLAGS_AC) #define ID (1 << FLAGS_ID) #define GetLazyParityBool(f) GetParity((0xff000000 & (f)) >> FLAGS_LP) #define SetLazyParityByte(f, x) ((0x00ffffff & (f)) | (255 & (x)) << FLAGS_LP) u64 ExportFlags(u64); bool GetParity(u8) pureconst; void ImportFlags(struct Machine *, u64); int GetFlagDeps(u64) pureconst; int GetFlagClobbers(u64) pureconst; int GetNeededFlags(struct Machine *, i64, int); static inline bool GetFlag(u32 f, int b) { switch (b) { case FLAGS_PF: return GetLazyParityBool(f); default: return (f >> b) & 1; } } static inline u32 SetFlag(u32 f, int b, bool v) { switch (b) { case FLAGS_PF: return SetLazyParityByte(f, !v); default: return (f & ~(1u << b)) | v << b; } } MICRO_OP_SAFE bool IsParity(struct Machine *m) { return GetFlag(m->flags, FLAGS_PF); } MICRO_OP_SAFE bool IsBelowOrEqual(struct Machine *m) { // CF || ZF return ((m->flags >> 6) | m->flags) & 1; } MICRO_OP_SAFE bool IsAbove(struct Machine *m) { // !CF && ~ZF return ((~m->flags >> 6) & ~m->flags) & 1; } MICRO_OP_SAFE bool IsLess(struct Machine *m) { // SF != OF return (i8)(m->flags ^ (m->flags >> 4)) < 0; } MICRO_OP_SAFE bool IsGreaterOrEqual(struct Machine *m) { // SF == OF return (i8)(~(m->flags ^ (m->flags >> 4))) < 0; } MICRO_OP_SAFE bool IsLessOrEqual(struct Machine *m) { // ZF || SF != OF return (i8)((m->flags ^ (m->flags >> 4)) | (m->flags << 1)) < 0; } MICRO_OP_SAFE bool IsGreater(struct Machine *m) { // !ZF && SF == OF return (i8)(~(m->flags ^ (m->flags >> 4)) & ~(m->flags << 1)) < 0; } #endif /* BLINK_FLAGS_H_ */ ================================================ FILE: blink/formatint64.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2021 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/builtin.h" #include "blink/util.h" /** * Converts unsigned 64-bit integer to string. * * @param p needs at least 21 bytes * @return pointer to nul byte */ dontinline char *FormatUint64(char *p, uint64_t x) { char t; size_t i, a, b; i = 0; do { p[i++] = x % 10 + '0'; x = x / 10; } while (x > 0); p[i] = '\0'; if (i) { for (a = 0, b = i - 1; a < b; ++a, --b) { t = p[a]; p[a] = p[b]; p[b] = t; } } return p + i; } /** * Converts signed 64-bit integer to string. * * @param p needs at least 21 bytes * @return pointer to nul byte */ char *FormatInt64(char *p, int64_t x) { if (x < 0) *p++ = '-', x = -(uint64_t)x; return FormatUint64(p, x); } ================================================ FILE: blink/formatint64thousands.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2021 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/builtin.h" #include "blink/util.h" /** * Converts unsigned 64-bit integer to string w/ commas. * * @param p needs at least 27 bytes * @return pointer to nul byte */ dontinline char *FormatUint64Thousands(char *p, uint64_t x) { size_t i; char m[26]; i = 0; do { m[i++] = x % 10 + '0'; x = x / 10; } while (x); for (;;) { *p++ = m[--i]; if (!i) break; if (!(i % 3)) *p++ = ','; } *p = '\0'; return p; } /** * Converts 64-bit integer to string w/ commas. * * @param p needs at least 27 bytes * @return pointer to nul byte */ char *FormatInt64Thousands(char *p, int64_t x) { if (x < 0) *p++ = '-', x = -(uint64_t)x; return FormatUint64Thousands(p, x); } ================================================ FILE: blink/formatsize.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/macros.h" #include "blink/util.h" /** * Represents size as readable string. * * @param p is output buffer * @param b should be 1024 or 1000 * @return pointer to nul byte */ char *FormatSize(char *p, uint64_t x, uint64_t b) { int i, suffix; struct { char suffix; uint64_t size; } kUnits[] = { {'e', b * b * b * b * b * b}, {'p', b * b * b * b * b}, {'t', b * b * b * b}, {'g', b * b * b}, {'m', b * b}, {'k', b}, }; for (suffix = i = 0; i < ARRAYLEN(kUnits); ++i) { if (x >= kUnits[i].size * 9) { x = (x + kUnits[i].size / 2) / kUnits[i].size; suffix = kUnits[i].suffix; break; } } p = FormatUint64(p, x); if (suffix) *p++ = suffix; *p = 0; return p; } ================================================ FILE: blink/fpu.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/fpu.h" #include #include #include #include #include "blink/builtin.h" #include "blink/case.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/ldbl.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/pun.h" #include "blink/rde.h" #define FPUREG 0 #define MEMORY 1 #define DISP(x, y, z) ((7 & (x)) << 4 | (y) << 3 | (u32)(z)) static i16 FpuGetMemoryShort(struct Machine *m) { u8 b[2]; return Read16(Load(m, m->fpu.dp, 2, b)); } static void FpuSetMemoryShort(struct Machine *m, i16 i) { void *p[2]; u8 b[2]; Write16(BeginStore(m, m->fpu.dp, 2, p, b), i); EndStore(m, m->fpu.dp, 2, p, b); } static void OpFstcw(struct Machine *m) { FpuSetMemoryShort(m, m->fpu.cw); } static void OpFldcw(struct Machine *m) { m->fpu.cw = FpuGetMemoryShort(m); } #ifndef DISABLE_X87 static void OnFpuStackOverflow(struct Machine *m) { m->fpu.sw |= kFpuSwIe | kFpuSwC1 | kFpuSwSf; } static double OnFpuStackUnderflow(struct Machine *m) { m->fpu.sw |= kFpuSwIe | kFpuSwSf; m->fpu.sw &= ~kFpuSwC1; return -NAN; } static double St(struct Machine *m, int i) { if (FpuGetTag(m, i) == kFpuTagEmpty) OnFpuStackUnderflow(m); return *FpuSt(m, i); } static double St0(struct Machine *m) { return St(m, 0); } static double St1(struct Machine *m) { return St(m, 1); } static double StRm(struct Machine *m, u64 rde) { return St(m, ModrmRm(rde)); } static void FpuClearRoundup(struct Machine *m) { m->fpu.sw &= ~kFpuSwC1; } static void FpuClearOutOfRangeIndicator(struct Machine *m) { m->fpu.sw &= ~kFpuSwC2; } static void FpuSetSt0(struct Machine *m, double x) { *FpuSt(m, 0) = x; } static void FpuSetStRm(struct Machine *m, u64 rde, double x) { *FpuSt(m, ModrmRm(rde)) = x; } static void FpuSetStPop(struct Machine *m, int i, double x) { *FpuSt(m, i) = x; FpuPop(m); } static void FpuSetStRmPop(struct Machine *m, u64 rde, double x) { FpuSetStPop(m, ModrmRm(rde), x); } static i32 FpuGetMemoryInt(struct Machine *m) { u8 b[4]; return Read32(Load(m, m->fpu.dp, 4, b)); } static i64 FpuGetMemoryLong(struct Machine *m) { u8 b[8]; return Read64(Load(m, m->fpu.dp, 8, b)); } static float FpuGetMemoryFloat(struct Machine *m) { union FloatPun u; u.i = FpuGetMemoryInt(m); return u.f; } static double FpuGetMemoryDouble(struct Machine *m) { union DoublePun u; u.i = FpuGetMemoryLong(m); return u.f; } static void FpuSetMemoryInt(struct Machine *m, i32 i) { void *p[2]; u8 b[4]; Write32(BeginStore(m, m->fpu.dp, 4, p, b), i); EndStore(m, m->fpu.dp, 4, p, b); } static void FpuSetMemoryLong(struct Machine *m, i64 i) { void *p[2]; u8 b[8]; Write64(BeginStore(m, m->fpu.dp, 8, p, b), i); EndStore(m, m->fpu.dp, 8, p, b); } static void FpuSetMemoryFloat(struct Machine *m, float f) { union FloatPun u = {f}; FpuSetMemoryInt(m, u.i); } static void FpuSetMemoryDouble(struct Machine *m, double f) { union DoublePun u = {f}; FpuSetMemoryLong(m, u.i); } static double FpuGetMemoryLdbl(struct Machine *m) { u8 b[10]; return DeserializeLdbl(Load(m, m->fpu.dp, 10, b)); } static void FpuSetMemoryLdbl(struct Machine *m, double f) { void *p[2]; u8 b[10], t[10]; SerializeLdbl(b, f); memcpy(BeginStore(m, m->fpu.dp, 10, p, t), b, 10); EndStore(m, m->fpu.dp, 10, p, t); } static double f2xm1(double x) { return exp2(x) - 1; } static double fyl2x(double x, double y) { return y * log2(x); } static double fyl2xp1(double x, double y) { return y * log2(x + 1); } static double fscale(double significand, double exponent) { if (isunordered(significand, exponent)) return NAN; return ldexp(significand, exponent); } static double x87remainder(double x, double y, u32 *sw, double rem(double, double), double rnd(double)) { int s; long q; double r; s = 0; r = rem(x, y); q = rnd(x / y); s &= ~kFpuSwC2; /* ty libm */ if (q & 1) s |= kFpuSwC1; if (q & 2) s |= kFpuSwC3; if (q & 4) s |= kFpuSwC0; if (sw) *sw = s | (*sw & ~(kFpuSwC0 | kFpuSwC1 | kFpuSwC2 | kFpuSwC3)); return r; } static double fprem(double dividend, double modulus, u32 *sw) { return x87remainder(dividend, modulus, sw, fmod, trunc); } static double fprem1(double dividend, double modulus, u32 *sw) { return x87remainder(dividend, modulus, sw, remainder, rint); } static double FpuAdd(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { switch (isinf(y) << 1 | isinf(x)) { case 0: return x + y; case 1: return x; case 2: return y; case 3: if (signbit(x) == signbit(y)) { return x; } else { m->fpu.sw |= kFpuSwIe; return copysign(NAN, x); } default: __builtin_unreachable(); } } else { return NAN; } } static double FpuSub(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { switch (isinf(y) << 1 | isinf(x)) { case 0: return x - y; case 1: return -x; case 2: return y; case 3: if (signbit(x) == signbit(y)) { m->fpu.sw |= kFpuSwIe; return copysign(NAN, x); } else { return y; } default: __builtin_unreachable(); } } else { return NAN; } } static double FpuMul(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { if (!((isinf(x) && !y) || (isinf(y) && !x))) { return x * y; } else { m->fpu.sw |= kFpuSwIe; return -NAN; } } else { return NAN; } } static double FpuDiv(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { if (x || y) { if (y) { return x / y; } else { m->fpu.sw |= kFpuSwZe; return copysign(INFINITY, x); } } else { m->fpu.sw |= kFpuSwIe; return copysign(NAN, x); } } else { return NAN; } } static double FpuRound(struct Machine *m, double x) { switch ((m->fpu.cw & kFpuCwRc) >> 10) { case 0: return rint(x); case 1: return floor(x); case 2: return ceil(x); case 3: return trunc(x); default: __builtin_unreachable(); } } static void FpuCompare(struct Machine *m, double y) { double x = St0(m); m->fpu.sw &= ~(kFpuSwC0 | kFpuSwC1 | kFpuSwC2 | kFpuSwC3); if (!isunordered(x, y)) { if (x < y) m->fpu.sw |= kFpuSwC0; if (x == y) m->fpu.sw |= kFpuSwC3; } else { m->fpu.sw |= kFpuSwC0 | kFpuSwC2 | kFpuSwC3 | kFpuSwIe; } } static void OpFxam(struct Machine *m) { double x; x = *FpuSt(m, 0); m->fpu.sw &= ~(kFpuSwC0 | kFpuSwC1 | kFpuSwC2 | kFpuSwC3); if (signbit(x)) m->fpu.sw |= kFpuSwC1; if (FpuGetTag(m, 0) == kFpuTagEmpty) { m->fpu.sw |= kFpuSwC0 | kFpuSwC3; } else { switch (fpclassify(x)) { case FP_NAN: m->fpu.sw |= kFpuSwC0; break; case FP_INFINITE: m->fpu.sw |= kFpuSwC0 | kFpuSwC2; break; case FP_ZERO: m->fpu.sw |= kFpuSwC3; break; case FP_SUBNORMAL: m->fpu.sw |= kFpuSwC2 | kFpuSwC3; break; case FP_NORMAL: m->fpu.sw |= kFpuSwC2; break; default: __builtin_unreachable(); } } } static void OpFtst(struct Machine *m) { FpuCompare(m, 0); } static void OpFcmovb(struct Machine *m, u64 rde) { if (GetFlag(m->flags, FLAGS_CF)) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFcmove(struct Machine *m, u64 rde) { if (GetFlag(m->flags, FLAGS_ZF)) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFcmovbe(struct Machine *m, u64 rde) { if (GetFlag(m->flags, FLAGS_CF) || GetFlag(m->flags, FLAGS_ZF)) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFcmovu(struct Machine *m, u64 rde) { if (GetFlag(m->flags, FLAGS_PF)) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFcmovnb(struct Machine *m, u64 rde) { if (!GetFlag(m->flags, FLAGS_CF)) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFcmovne(struct Machine *m, u64 rde) { if (!GetFlag(m->flags, FLAGS_ZF)) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFcmovnbe(struct Machine *m, u64 rde) { if (!(GetFlag(m->flags, FLAGS_CF) || GetFlag(m->flags, FLAGS_ZF))) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFcmovnu(struct Machine *m, u64 rde) { if (!GetFlag(m->flags, FLAGS_PF)) { FpuSetSt0(m, StRm(m, rde)); } } static void OpFchs(struct Machine *m) { FpuSetSt0(m, -St0(m)); } static void OpFabs(struct Machine *m) { FpuSetSt0(m, fabs(St0(m))); } static void OpF2xm1(struct Machine *m) { FpuSetSt0(m, f2xm1(St0(m))); } static void OpFyl2x(struct Machine *m) { FpuSetStPop(m, 1, fyl2x(St0(m), St1(m))); } static void OpFyl2xp1(struct Machine *m) { FpuSetStPop(m, 1, fyl2xp1(St0(m), St1(m))); } static void OpFcos(struct Machine *m) { FpuClearOutOfRangeIndicator(m); FpuSetSt0(m, cos(St0(m))); } static void OpFsin(struct Machine *m) { FpuClearOutOfRangeIndicator(m); FpuSetSt0(m, sin(St0(m))); } static void OpFptan(struct Machine *m) { FpuClearOutOfRangeIndicator(m); FpuSetSt0(m, tan(St0(m))); FpuPush(m, 1); } static void OpFsincos(struct Machine *m) { double tsin, tcos; FpuClearOutOfRangeIndicator(m); tsin = sin(St0(m)); tcos = cos(St0(m)); FpuSetSt0(m, tsin); FpuPush(m, tcos); } static void OpFpatan(struct Machine *m) { FpuClearRoundup(m); FpuSetStPop(m, 1, atan2(St1(m), St0(m))); } static void OpFcom(struct Machine *m, u64 rde) { FpuCompare(m, StRm(m, rde)); } static void OpFcomp(struct Machine *m, u64 rde) { FpuCompare(m, StRm(m, rde)); FpuPop(m); } static void OpFaddStEst(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuAdd(m, St0(m), StRm(m, rde))); } static void OpFmulStEst(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuMul(m, St0(m), StRm(m, rde))); } static void OpFsubStEst(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuSub(m, St0(m), StRm(m, rde))); } static void OpFsubrStEst(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuSub(m, StRm(m, rde), St0(m))); } static void OpFdivStEst(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuDiv(m, St0(m), StRm(m, rde))); } static void OpFdivrStEst(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuDiv(m, StRm(m, rde), St0(m))); } static void OpFaddEstSt(struct Machine *m, u64 rde) { FpuSetStRm(m, rde, FpuAdd(m, StRm(m, rde), St0(m))); } static void OpFmulEstSt(struct Machine *m, u64 rde) { FpuSetStRm(m, rde, FpuMul(m, StRm(m, rde), St0(m))); } static void OpFsubEstSt(struct Machine *m, u64 rde) { FpuSetStRm(m, rde, FpuSub(m, St0(m), StRm(m, rde))); } static void OpFsubrEstSt(struct Machine *m, u64 rde) { FpuSetStRm(m, rde, FpuSub(m, StRm(m, rde), St0(m))); } static void OpFdivEstSt(struct Machine *m, u64 rde) { FpuSetStRm(m, rde, FpuDiv(m, StRm(m, rde), St0(m))); } static void OpFdivrEstSt(struct Machine *m, u64 rde) { FpuSetStRm(m, rde, FpuDiv(m, St0(m), StRm(m, rde))); } static void OpFaddp(struct Machine *m, u64 rde) { FpuSetStRmPop(m, rde, FpuAdd(m, St0(m), StRm(m, rde))); } static void OpFmulp(struct Machine *m, u64 rde) { FpuSetStRmPop(m, rde, FpuMul(m, St0(m), StRm(m, rde))); } static void OpFcompp(struct Machine *m, u64 rde) { OpFcomp(m, rde); FpuPop(m); } static void OpFsubp(struct Machine *m, u64 rde) { FpuSetStRmPop(m, rde, FpuSub(m, St0(m), StRm(m, rde))); } static void OpFsubrp(struct Machine *m, u64 rde) { FpuSetStPop(m, 1, FpuSub(m, StRm(m, rde), St0(m))); } static void OpFdivp(struct Machine *m, u64 rde) { FpuSetStRmPop(m, rde, FpuDiv(m, St0(m), StRm(m, rde))); } static void OpFdivrp(struct Machine *m, u64 rde) { FpuSetStRmPop(m, rde, FpuDiv(m, StRm(m, rde), St0(m))); } static void OpFadds(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryFloat(m))); } static void OpFmuls(struct Machine *m, u64 rde) { FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryFloat(m))); } static void OpFcoms(struct Machine *m) { FpuCompare(m, FpuGetMemoryFloat(m)); } static void OpFcomps(struct Machine *m) { OpFcoms(m); FpuPop(m); } static void OpFsubs(struct Machine *m) { FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryFloat(m))); } static void OpFsubrs(struct Machine *m) { FpuSetSt0(m, FpuSub(m, FpuGetMemoryFloat(m), St0(m))); } static void OpFdivs(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryFloat(m))); } static void OpFdivrs(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, FpuGetMemoryFloat(m), St0(m))); } static void OpFaddl(struct Machine *m) { FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryDouble(m))); } static void OpFmull(struct Machine *m) { FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryDouble(m))); } static void OpFcoml(struct Machine *m) { FpuCompare(m, FpuGetMemoryDouble(m)); } static void OpFcompl(struct Machine *m) { FpuCompare(m, FpuGetMemoryDouble(m)); FpuPop(m); } static void OpFsubl(struct Machine *m) { FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryDouble(m))); } static void OpFsubrl(struct Machine *m) { FpuSetSt0(m, FpuSub(m, FpuGetMemoryDouble(m), St0(m))); } static void OpFdivl(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryDouble(m))); } static void OpFdivrl(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, FpuGetMemoryDouble(m), St0(m))); } static void OpFiaddl(struct Machine *m) { FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryInt(m))); } static void OpFimull(struct Machine *m) { FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryInt(m))); } static void OpFicoml(struct Machine *m) { FpuCompare(m, FpuGetMemoryInt(m)); } static void OpFicompl(struct Machine *m) { OpFicoml(m); FpuPop(m); } static void OpFisubl(struct Machine *m) { FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryInt(m))); } static void OpFisubrl(struct Machine *m) { FpuSetSt0(m, FpuSub(m, FpuGetMemoryInt(m), St0(m))); } static void OpFidivl(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryInt(m))); } static void OpFidivrl(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, FpuGetMemoryInt(m), St0(m))); } static void OpFiadds(struct Machine *m) { FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryShort(m))); } static void OpFimuls(struct Machine *m) { FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryShort(m))); } static void OpFicoms(struct Machine *m) { FpuCompare(m, FpuGetMemoryShort(m)); } static void OpFicomps(struct Machine *m) { OpFicoms(m); FpuPop(m); } static void OpFisubs(struct Machine *m) { FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryShort(m))); } static void OpFisubrs(struct Machine *m) { FpuSetSt0(m, FpuSub(m, FpuGetMemoryShort(m), St0(m))); } static void OpFidivs(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryShort(m))); } static void OpFidivrs(struct Machine *m) { FpuSetSt0(m, FpuDiv(m, FpuGetMemoryShort(m), St0(m))); } static void OpFsqrt(struct Machine *m) { FpuClearRoundup(m); FpuSetSt0(m, sqrt(St0(m))); } static void OpFrndint(struct Machine *m) { FpuSetSt0(m, FpuRound(m, St0(m))); } static void OpFscale(struct Machine *m) { FpuClearRoundup(m); FpuSetSt0(m, fscale(St0(m), St1(m))); } static void OpFprem(struct Machine *m) { FpuSetSt0(m, fprem(St0(m), St1(m), &m->fpu.sw)); } static void OpFprem1(struct Machine *m) { FpuSetSt0(m, fprem1(St0(m), St1(m), &m->fpu.sw)); } static void OpFdecstp(struct Machine *m) { m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw - (1 << 11)) & kFpuSwSp); } static void OpFincstp(struct Machine *m) { m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw + (1 << 11)) & kFpuSwSp); } static void OpFxtract(struct Machine *m) { double x = St0(m); FpuSetSt0(m, logb(x)); FpuPush(m, ldexp(x, -ilogb(x))); } static void OpFld(struct Machine *m, u64 rde) { FpuPush(m, StRm(m, rde)); } static void OpFlds(struct Machine *m) { FpuPush(m, FpuGetMemoryFloat(m)); } static void OpFsts(struct Machine *m) { FpuSetMemoryFloat(m, St0(m)); } static void OpFstps(struct Machine *m) { OpFsts(m); FpuPop(m); } static void OpFstpt(struct Machine *m) { FpuSetMemoryLdbl(m, FpuPop(m)); } static void OpFstl(struct Machine *m) { FpuSetMemoryDouble(m, St0(m)); } static void OpFstpl(struct Machine *m) { OpFstl(m); FpuPop(m); } static void OpFst(struct Machine *m, u64 rde) { FpuSetStRm(m, rde, St0(m)); } static void OpFstp(struct Machine *m, u64 rde) { FpuSetStRmPop(m, rde, St0(m)); } static void OpFxch(struct Machine *m, u64 rde) { double t = StRm(m, rde); FpuSetStRm(m, rde, St0(m)); FpuSetSt0(m, t); } static void OpFldt(struct Machine *m) { FpuPush(m, FpuGetMemoryLdbl(m)); } static void OpFldl(struct Machine *m) { FpuPush(m, FpuGetMemoryDouble(m)); } static double Fld1(void) { return 1; } static double Fldl2t(void) { return 0xd.49a784bcd1b8afep-2L; /* log₂10 */ } static double Fldl2e(void) { return 0xb.8aa3b295c17f0bcp-3L; /* log₂𝑒 */ } static double Fldpi(void) { return 0x1.921fb54442d1846ap+1L; /* π */ } static double Fldlg2(void) { return 0x9.a209a84fbcff799p-5L; /* log₁₀2 */ } static double Fldln2(void) { return 0xb.17217f7d1cf79acp-4L; /* logₑ2 */ } static double Fldz(void) { return 0; } static void OpFldConstant(struct Machine *m, u64 rde) { double x; switch (ModrmRm(rde)) { CASE(0, x = Fld1()); CASE(1, x = Fldl2t()); CASE(2, x = Fldl2e()); CASE(3, x = Fldpi()); CASE(4, x = Fldlg2()); CASE(5, x = Fldln2()); CASE(6, x = Fldz()); default: OpUdImpl(m); } FpuPush(m, x); } static void OpFilds(struct Machine *m) { FpuPush(m, FpuGetMemoryShort(m)); } static void OpFildl(struct Machine *m) { FpuPush(m, FpuGetMemoryInt(m)); } static void OpFildll(struct Machine *m) { FpuPush(m, FpuGetMemoryLong(m)); } static void OpFisttpl(struct Machine *m) { FpuSetMemoryInt(m, FpuPop(m)); } static void OpFisttpll(struct Machine *m) { FpuSetMemoryLong(m, FpuPop(m)); } static void OpFisttps(struct Machine *m) { FpuSetMemoryShort(m, FpuPop(m)); } static void OpFists(struct Machine *m) { FpuSetMemoryShort(m, FpuRound(m, St0(m))); } static void OpFistl(struct Machine *m) { FpuSetMemoryInt(m, FpuRound(m, St0(m))); } static void OpFistll(struct Machine *m) { FpuSetMemoryLong(m, FpuRound(m, St0(m))); } static void OpFistpl(struct Machine *m) { OpFistl(m); FpuPop(m); } static void OpFistpll(struct Machine *m) { OpFistll(m); FpuPop(m); } static void OpFistps(struct Machine *m) { OpFists(m); FpuPop(m); } static void OpFcomi(struct Machine *m, u64 rde) { double x, y; x = St0(m); y = StRm(m, rde); if (!isunordered(x, y)) { m->flags = SetFlag(m->flags, FLAGS_ZF, x == y); m->flags = SetFlag(m->flags, FLAGS_CF, x < y); m->flags = SetFlag(m->flags, FLAGS_PF, false); } else { m->fpu.sw |= kFpuSwIe; m->flags = SetFlag(m->flags, FLAGS_ZF, true); m->flags = SetFlag(m->flags, FLAGS_CF, true); m->flags = SetFlag(m->flags, FLAGS_PF, true); } } static void OpFucom(struct Machine *m, u64 rde) { FpuCompare(m, StRm(m, rde)); } static void OpFucomp(struct Machine *m, u64 rde) { FpuCompare(m, StRm(m, rde)); FpuPop(m); } static void OpFcomip(struct Machine *m, u64 rde) { OpFcomi(m, rde); FpuPop(m); } static void OpFucomi(struct Machine *m, u64 rde) { OpFcomi(m, rde); } static void OpFucomip(struct Machine *m, u64 rde) { OpFcomip(m, rde); } static void OpFfree(struct Machine *m, u64 rde) { FpuSetTag(m, ModrmRm(rde), kFpuTagEmpty); } static void OpFfreep(struct Machine *m, u64 rde) { if (ModrmRm(rde)) OpFfree(m, rde); FpuPop(m); } static void OpFstswMw(struct Machine *m) { FpuSetMemoryShort(m, m->fpu.sw); } static void OpFstswAx(struct Machine *m) { Write16(m->ax, m->fpu.sw); } static void SetFpuEnv(struct Machine *m, u8 p[28]) { Write16(p + 0, m->fpu.cw); Write16(p + 4, m->fpu.sw); Write16(p + 8, m->fpu.tw); Write64(p + 12, m->fpu.ip); Write16(p + 18, m->fpu.op); Write64(p + 20, m->fpu.dp); } static void GetFpuEnv(struct Machine *m, u8 p[28]) { m->fpu.cw = Read16(p + 0); m->fpu.sw = Read16(p + 4); m->fpu.tw = Read16(p + 8); } static void OpFstenv(struct Machine *m) { void *p[2]; u8 b[28]; SetFpuEnv(m, BeginStore(m, m->fpu.dp, sizeof(b), p, b)); EndStore(m, m->fpu.dp, sizeof(b), p, b); } static void OpFldenv(struct Machine *m) { u8 b[28]; GetFpuEnv(m, Load(m, m->fpu.dp, sizeof(b), b)); } static void OpFsave(struct Machine *m) { int i; void *p[2]; u8 *a, b[108], t[16]; a = BeginStore(m, m->fpu.dp, sizeof(b), p, b); SetFpuEnv(m, a); memset(t, 0, sizeof(t)); for (i = 0; i < 8; ++i) { SerializeLdbl(a + 28 + i * 10, *FpuSt(m, i)); } EndStore(m, m->fpu.dp, sizeof(b), p, b); OpFinit(m); } static void OpFrstor(struct Machine *m) { int i; u8 *a, b[108]; a = Load(m, m->fpu.dp, sizeof(b), b); GetFpuEnv(m, a); for (i = 0; i < 8; ++i) { *FpuSt(m, i) = DeserializeLdbl(a + 28 + i * 10); } } static void OpFnclex(struct Machine *m) { m->fpu.sw &= ~(kFpuSwIe | kFpuSwDe | kFpuSwZe | kFpuSwOe | kFpuSwUe | kFpuSwPe | kFpuSwEs | kFpuSwSf | kFpuSwBf); } static void OpFnop(struct Machine *m) { /* do nothing */ } void OpFinit(struct Machine *m) { m->fpu.cw = 0x037f; m->fpu.sw = 0; m->fpu.tw = -1; } void OpFwait(P) { int sw, cw; sw = m->fpu.sw; cw = m->fpu.cw; if (((sw & kFpuSwIe) && !(cw & kFpuCwIm)) || ((sw & kFpuSwDe) && !(cw & kFpuCwDm)) || ((sw & kFpuSwZe) && !(cw & kFpuCwZm)) || ((sw & kFpuSwOe) && !(cw & kFpuCwOm)) || ((sw & kFpuSwUe) && !(cw & kFpuCwUm)) || ((sw & kFpuSwPe) && !(cw & kFpuCwPm)) || ((sw & kFpuSwSf) && !(cw & kFpuCwIm))) { HaltMachine(m, kMachineFpuException); } } int FpuGetTag(struct Machine *m, unsigned i) { unsigned t; t = m->fpu.tw; i += (m->fpu.sw & kFpuSwSp) >> 11; i &= 7; i *= 2; t &= 3 << i; t >>= i; return t; } void FpuSetTag(struct Machine *m, unsigned i, unsigned t) { i += (m->fpu.sw & kFpuSwSp) >> 11; t &= 3; i &= 7; i *= 2; m->fpu.tw &= ~(3 << i); m->fpu.tw |= t << i; } void FpuPush(struct Machine *m, double x) { if (FpuGetTag(m, -1) != kFpuTagEmpty) OnFpuStackOverflow(m); m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw - (1 << 11)) & kFpuSwSp); *FpuSt(m, 0) = x; FpuSetTag(m, 0, kFpuTagValid); } double FpuPop(struct Machine *m) { double x; if (FpuGetTag(m, 0) != kFpuTagEmpty) { x = *FpuSt(m, 0); FpuSetTag(m, 0, kFpuTagEmpty); } else { x = OnFpuStackUnderflow(m); } m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw + (1 << 11)) & kFpuSwSp); return x; } void OpFpu(P) { unsigned op; bool ismemory; op = Opcode(rde) & 7; ismemory = ModrmMod(rde) != 3; m->fpu.ip = MaskAddress(m->mode.omode, m->ip - Oplength(rde)); m->fpu.op = op << 8 | ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde); m->fpu.dp = ismemory ? ComputeAddress(A) : 0; switch (DISP(op, ismemory, ModrmReg(rde))) { CASE(DISP(0xD8, FPUREG, 0), OpFaddStEst(m, rde)); CASE(DISP(0xD8, FPUREG, 1), OpFmulStEst(m, rde)); CASE(DISP(0xD8, FPUREG, 2), OpFcom(m, rde)); CASE(DISP(0xD8, FPUREG, 3), OpFcomp(m, rde)); CASE(DISP(0xD8, FPUREG, 4), OpFsubStEst(m, rde)); CASE(DISP(0xD8, FPUREG, 5), OpFsubrStEst(m, rde)); CASE(DISP(0xD8, FPUREG, 6), OpFdivStEst(m, rde)); CASE(DISP(0xD8, FPUREG, 7), OpFdivrStEst(m, rde)); CASE(DISP(0xD8, MEMORY, 0), OpFadds(m, rde)); CASE(DISP(0xD8, MEMORY, 1), OpFmuls(m, rde)); CASE(DISP(0xD8, MEMORY, 2), OpFcoms(m)); CASE(DISP(0xD8, MEMORY, 3), OpFcomps(m)); CASE(DISP(0xD8, MEMORY, 4), OpFsubs(m)); CASE(DISP(0xD8, MEMORY, 5), OpFsubrs(m)); CASE(DISP(0xD8, MEMORY, 6), OpFdivs(m)); CASE(DISP(0xD8, MEMORY, 7), OpFdivrs(m)); CASE(DISP(0xD9, FPUREG, 0), OpFld(m, rde)); CASE(DISP(0xD9, FPUREG, 1), OpFxch(m, rde)); CASE(DISP(0xD9, FPUREG, 2), OpFnop(m)); CASE(DISP(0xD9, FPUREG, 3), OpFstp(m, rde)); CASE(DISP(0xD9, FPUREG, 5), OpFldConstant(m, rde)); CASE(DISP(0xD9, MEMORY, 0), OpFlds(m)); CASE(DISP(0xD9, MEMORY, 2), OpFsts(m)); CASE(DISP(0xD9, MEMORY, 3), OpFstps(m)); CASE(DISP(0xD9, MEMORY, 4), OpFldenv(m)); CASE(DISP(0xD9, MEMORY, 5), OpFldcw(m)); CASE(DISP(0xD9, MEMORY, 6), OpFstenv(m)); CASE(DISP(0xD9, MEMORY, 7), OpFstcw(m)); CASE(DISP(0xDA, FPUREG, 0), OpFcmovb(m, rde)); CASE(DISP(0xDA, FPUREG, 1), OpFcmove(m, rde)); CASE(DISP(0xDA, FPUREG, 2), OpFcmovbe(m, rde)); CASE(DISP(0xDA, FPUREG, 3), OpFcmovu(m, rde)); CASE(DISP(0xDA, MEMORY, 0), OpFiaddl(m)); CASE(DISP(0xDA, MEMORY, 1), OpFimull(m)); CASE(DISP(0xDA, MEMORY, 2), OpFicoml(m)); CASE(DISP(0xDA, MEMORY, 3), OpFicompl(m)); CASE(DISP(0xDA, MEMORY, 4), OpFisubl(m)); CASE(DISP(0xDA, MEMORY, 5), OpFisubrl(m)); CASE(DISP(0xDA, MEMORY, 6), OpFidivl(m)); CASE(DISP(0xDA, MEMORY, 7), OpFidivrl(m)); CASE(DISP(0xDB, FPUREG, 0), OpFcmovnb(m, rde)); CASE(DISP(0xDB, FPUREG, 1), OpFcmovne(m, rde)); CASE(DISP(0xDB, FPUREG, 2), OpFcmovnbe(m, rde)); CASE(DISP(0xDB, FPUREG, 3), OpFcmovnu(m, rde)); CASE(DISP(0xDB, FPUREG, 5), OpFucomi(m, rde)); CASE(DISP(0xDB, FPUREG, 6), OpFcomi(m, rde)); CASE(DISP(0xDB, MEMORY, 0), OpFildl(m)); CASE(DISP(0xDB, MEMORY, 1), OpFisttpl(m)); CASE(DISP(0xDB, MEMORY, 2), OpFistl(m)); CASE(DISP(0xDB, MEMORY, 3), OpFistpl(m)); CASE(DISP(0xDB, MEMORY, 5), OpFldt(m)); CASE(DISP(0xDB, MEMORY, 7), OpFstpt(m)); CASE(DISP(0xDC, FPUREG, 0), OpFaddEstSt(m, rde)); CASE(DISP(0xDC, FPUREG, 1), OpFmulEstSt(m, rde)); CASE(DISP(0xDC, FPUREG, 2), OpFcom(m, rde)); CASE(DISP(0xDC, FPUREG, 3), OpFcomp(m, rde)); CASE(DISP(0xDC, FPUREG, 4), OpFsubEstSt(m, rde)); CASE(DISP(0xDC, FPUREG, 5), OpFsubrEstSt(m, rde)); CASE(DISP(0xDC, FPUREG, 6), OpFdivEstSt(m, rde)); CASE(DISP(0xDC, FPUREG, 7), OpFdivrEstSt(m, rde)); CASE(DISP(0xDC, MEMORY, 0), OpFaddl(m)); CASE(DISP(0xDC, MEMORY, 1), OpFmull(m)); CASE(DISP(0xDC, MEMORY, 2), OpFcoml(m)); CASE(DISP(0xDC, MEMORY, 3), OpFcompl(m)); CASE(DISP(0xDC, MEMORY, 4), OpFsubl(m)); CASE(DISP(0xDC, MEMORY, 5), OpFsubrl(m)); CASE(DISP(0xDC, MEMORY, 6), OpFdivl(m)); CASE(DISP(0xDC, MEMORY, 7), OpFdivrl(m)); CASE(DISP(0xDD, FPUREG, 0), OpFfree(m, rde)); CASE(DISP(0xDD, FPUREG, 1), OpFxch(m, rde)); CASE(DISP(0xDD, FPUREG, 2), OpFst(m, rde)); CASE(DISP(0xDD, FPUREG, 3), OpFstp(m, rde)); CASE(DISP(0xDD, FPUREG, 4), OpFucom(m, rde)); CASE(DISP(0xDD, FPUREG, 5), OpFucomp(m, rde)); CASE(DISP(0xDD, MEMORY, 0), OpFldl(m)); CASE(DISP(0xDD, MEMORY, 1), OpFisttpll(m)); CASE(DISP(0xDD, MEMORY, 2), OpFstl(m)); CASE(DISP(0xDD, MEMORY, 3), OpFstpl(m)); CASE(DISP(0xDD, MEMORY, 4), OpFrstor(m)); CASE(DISP(0xDD, MEMORY, 6), OpFsave(m)); CASE(DISP(0xDD, MEMORY, 7), OpFstswMw(m)); CASE(DISP(0xDE, FPUREG, 0), OpFaddp(m, rde)); CASE(DISP(0xDE, FPUREG, 1), OpFmulp(m, rde)); CASE(DISP(0xDE, FPUREG, 2), OpFcomp(m, rde)); CASE(DISP(0xDE, FPUREG, 3), OpFcompp(m, rde)); CASE(DISP(0xDE, FPUREG, 4), OpFsubp(m, rde)); CASE(DISP(0xDE, FPUREG, 5), OpFsubrp(m, rde)); CASE(DISP(0xDE, FPUREG, 6), OpFdivp(m, rde)); CASE(DISP(0xDE, FPUREG, 7), OpFdivrp(m, rde)); CASE(DISP(0xDE, MEMORY, 0), OpFiadds(m)); CASE(DISP(0xDE, MEMORY, 1), OpFimuls(m)); CASE(DISP(0xDE, MEMORY, 2), OpFicoms(m)); CASE(DISP(0xDE, MEMORY, 3), OpFicomps(m)); CASE(DISP(0xDE, MEMORY, 4), OpFisubs(m)); CASE(DISP(0xDE, MEMORY, 5), OpFisubrs(m)); CASE(DISP(0xDE, MEMORY, 6), OpFidivs(m)); CASE(DISP(0xDE, MEMORY, 7), OpFidivrs(m)); CASE(DISP(0xDF, FPUREG, 0), OpFfreep(m, rde)); CASE(DISP(0xDF, FPUREG, 1), OpFxch(m, rde)); CASE(DISP(0xDF, FPUREG, 2), OpFstp(m, rde)); CASE(DISP(0xDF, FPUREG, 3), OpFstp(m, rde)); CASE(DISP(0xDF, FPUREG, 4), OpFstswAx(m)); CASE(DISP(0xDF, FPUREG, 5), OpFucomip(m, rde)); CASE(DISP(0xDF, FPUREG, 6), OpFcomip(m, rde)); CASE(DISP(0xDF, MEMORY, 0), OpFilds(m)); CASE(DISP(0xDF, MEMORY, 1), OpFisttps(m)); CASE(DISP(0xDF, MEMORY, 2), OpFists(m)); CASE(DISP(0xDF, MEMORY, 3), OpFistps(m)); CASE(DISP(0xDF, MEMORY, 5), OpFildll(m)); CASE(DISP(0xDF, MEMORY, 7), OpFistpll(m)); case DISP(0xD9, FPUREG, 4): switch (ModrmRm(rde)) { CASE(0, OpFchs(m)); CASE(1, OpFabs(m)); CASE(4, OpFtst(m)); CASE(5, OpFxam(m)); default: OpUdImpl(m); } break; case DISP(0xD9, FPUREG, 6): switch (ModrmRm(rde)) { CASE(0, OpF2xm1(m)); CASE(1, OpFyl2x(m)); CASE(2, OpFptan(m)); CASE(3, OpFpatan(m)); CASE(4, OpFxtract(m)); CASE(5, OpFprem1(m)); CASE(6, OpFdecstp(m)); CASE(7, OpFincstp(m)); default: __builtin_unreachable(); } break; case DISP(0xD9, FPUREG, 7): switch (ModrmRm(rde)) { CASE(0, OpFprem(m)); CASE(1, OpFyl2xp1(m)); CASE(2, OpFsqrt(m)); CASE(3, OpFsincos(m)); CASE(4, OpFrndint(m)); CASE(5, OpFscale(m)); CASE(6, OpFsin(m)); CASE(7, OpFcos(m)); default: __builtin_unreachable(); } break; case DISP(0xDb, FPUREG, 4): switch (ModrmRm(rde)) { CASE(2, OpFnclex(m)); CASE(3, OpFinit(m)); default: OpUdImpl(m); } break; default: OpUdImpl(m); } } #else /* DISABLE_X87 */ void(OpFpu)(P) { unsigned op; bool ismemory; op = Opcode(rde) & 7; ismemory = ModrmMod(rde) != 3; m->fpu.dp = ismemory ? ComputeAddress(A) : 0; switch (DISP(op, ismemory, ModrmReg(rde))) { CASE(DISP(0xD9, MEMORY, 5), OpFldcw(m)); CASE(DISP(0xD9, MEMORY, 7), OpFstcw(m)); default: OpUdImpl(m); } } #endif /* DISABLE_X87 */ ================================================ FILE: blink/fpu.h ================================================ #ifndef BLINK_FPU_H_ #define BLINK_FPU_H_ #include "blink/machine.h" #define kFpuTagValid 0 #define kFpuTagZero 1 #define kFpuTagSpecial 2 #define kFpuTagEmpty 3 #define kFpuCwIm 0x0001 /* invalid operation mask */ #define kFpuCwDm 0x0002 /* denormal operand mask */ #define kFpuCwZm 0x0004 /* zero divide mask */ #define kFpuCwOm 0x0008 /* overflow mask */ #define kFpuCwUm 0x0010 /* underflow mask */ #define kFpuCwPm 0x0020 /* precision mask */ #define kFpuCwPc 0x0300 /* precision: 32,∅,64,80 */ #define kFpuCwRc 0x0c00 /* rounding: even,→-∞,→+∞,→0 */ #define kFpuSwIe 0x0001 /* invalid operation */ #define kFpuSwDe 0x0002 /* denormalized operand */ #define kFpuSwZe 0x0004 /* zero divide */ #define kFpuSwOe 0x0008 /* overflow */ #define kFpuSwUe 0x0010 /* underflow */ #define kFpuSwPe 0x0020 /* precision */ #define kFpuSwSf 0x0040 /* stack fault */ #define kFpuSwEs 0x0080 /* exception summary status */ #define kFpuSwC0 0x0100 /* condition 0 */ #define kFpuSwC1 0x0200 /* condition 1 */ #define kFpuSwC2 0x0400 /* condition 2 */ #define kFpuSwSp 0x3800 /* top stack */ #define kFpuSwC3 0x4000 /* condition 3 */ #define kFpuSwBf 0x8000 /* busy flag */ #define kMxcsrIe 0x0001 /* invalid operation flag */ #define kMxcsrDe 0x0002 /* denormal flag */ #define kMxcsrZe 0x0004 /* divide by zero flag */ #define kMxcsrOe 0x0008 /* overflow flag */ #define kMxcsrUe 0x0010 /* underflow flag */ #define kMxcsrPe 0x0020 /* precision flag */ #define kMxcsrDaz 0x0040 /* denormals are zeros */ #define kMxcsrIm 0x0080 /* invalid operation mask */ #define kMxcsrDm 0x0100 /* denormal mask */ #define kMxcsrZm 0x0200 /* divide by zero mask */ #define kMxcsrOm 0x0400 /* overflow mask */ #define kMxcsrUm 0x0800 /* underflow mask */ #define kMxcsrPm 0x1000 /* precision mask */ #define kMxcsrRc 0x6000 /* rounding control */ #define kMxcsrFtz 0x8000 /* flush to zero */ #define FpuSt(m, i) ((m)->fpu.st + (((i) + ((m->fpu.sw & kFpuSwSp) >> 11)) & 7)) double FpuPop(struct Machine *); int FpuGetTag(struct Machine *, unsigned); void FpuPush(struct Machine *, double); void FpuSetTag(struct Machine *, unsigned, unsigned); void OpFinit(struct Machine *); void OpFpu(P); void OpFwait(P); #endif /* BLINK_FPU_H_ */ ================================================ FILE: blink/fspath.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/fspath.h" #include #include char *JoinPath(const char *x, const char *y) { char *z, *p; size_t n, m; if (!y || !*y) { return x ? strdup(x) : 0; } if (!x || !*x || *y == '/' || (*x == '.' && !x[1])) { return strdup(y); } n = strlen(x); m = strlen(y); if (!(z = (char *)malloc(n + 1 + m + 1))) return 0; memcpy(z, x, n); p = z + n; if (x[n - 1] != '/') { *p++ = '/'; } memcpy(p, y, m + 1); return z; } char *ExpandUser(const char *path) { const char *home; if (path[0] == '~' && path[1] == '/' && (home = getenv("HOME"))) { return JoinPath(home, &path[2]); } else { return strdup(path); } } ================================================ FILE: blink/fspath.h ================================================ #ifndef BLINK_FSPATH_H_ #define BLINK_FSPATH_H_ char *JoinPath(const char *, const char *); char *ExpandUser(const char *); #endif /* BLINK_FSPATH_H_ */ ================================================ FILE: blink/fusion.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/assert.h" #include "blink/builtin.h" #include "blink/debug.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/machine.h" #include "blink/rde.h" #include "blink/stats.h" /** * @fileoverview Branch Micro-Op Fusion. */ bool FuseBranchTest(P) { #ifdef HAVE_JIT i64 bdisp; u8 *p, jcc, jlen; if (RegLog2(rde) < 2) { LogCodOp(m, "can't fuse test: byte/word fuse unimplemented"); return false; } if (4096 - (m->ip & 4095) < 6) { LogCodOp(m, "can't fuse test: too close to the edge"); return false; } if (RexrReg(rde) != RexbRm(rde)) { LogCodOp(m, "can't fuse test: different operands unimplemented"); return false; } if (!(p = GetAddress(m, m->ip))) { LogCodOp(m, "can't fuse test: null address"); return false; } if ((p[0] & 0xf0) == 0x70) { // Jcc Jbs jlen = 2; jcc = p[0] & 0x0f; bdisp = (i8)Read8(p + 1); } else if (p[0] == 0x0f && (p[1] & 0xf0) == 0x80) { // Jcc Jvds jlen = 6; jcc = p[1] & 0x0f; bdisp = (i32)Read32(p + 2); } else { LogCodOp(m, "can't fuse test: not followed by jump"); return false; } #ifndef __x86_64__ switch (jcc) { case 0x04: // jz break; case 0x05: // jnz break; default: LogCodOp(m, "can't fuse test: unsupported jump operation"); return false; } #endif if (GetNeededFlags(m, m->ip + jlen + bdisp, CF | ZF | SF | OF | AF | PF)) { LogCodOp(m, "can't fuse test: loop carries"); return false; } if (GetNeededFlags(m, m->ip + jlen, CF | ZF | SF | OF | AF | PF)) { LogCodOp(m, "can't fuse test: loop exit carries"); return false; } #if LOG_CPU LogCpu(m); #endif FlushCod(m->path.jb); WriteCod("/\tfusing branch test+jcc\n"); BeginCod(m, m->ip); #if LOG_JIX Jitter(A, "a1i" // arg1 = ip "c" // call function "q", // arg0 = machine m->ip, FuseOp); #endif Jitter(A, "a1i" // arg1 = skew + jlen "m", // call micro-op m->path.skew + jlen, AdvanceIp); m->path.skew = 0; #ifdef __x86_64__ Jitter(A, "A" // res0 = GetReg(RexrReg) "q"); // arg0 = machine if (!Rexw(rde)) { AlignJit(m->path.jb, 8, 4); } else { AlignJit(m->path.jb, 8, 3); AppendJit(m->path.jb, (u8[]){0x48}, 1); // rex.w } u8 code[] = { 0x85, 0300 | kJitRes0 << 3 | kJitRes0, // test %eax,%eax (u8)(0x70 | jcc), 5, // jz/jnz +5 }; #elif defined(__aarch64__) Jitter(A, "A" // res0 = GetReg(RexrReg) "r0a1=" // arg1 = res0 "q"); // arg0 = machine u32 code[] = { // b4000042 cbz x2, #8 // 34000042 cbz w2, #8 // b5000042 cbnz x2, #8 // 35000042 cbnz w2, #8 Rexw(rde) << 31 | 0x30000000 | jcc << 24 | (8 / 4) << 5 | kJitArg1, }; #else #error "architecture not implemented" #endif AppendJit(m->path.jb, code, sizeof(code)); Connect(A, m->ip + jlen, true); Jitter(A, "a1i" // arg1 = disp "m" // call micro-op "q", // arg0 = machine bdisp, AdvanceIp); AlignJit(m->path.jb, 8, 0); Connect(A, m->ip + jlen + bdisp, false); FinishPath(m); m->path.skip = 1; STATISTIC(++fused_branches); return true; #else return false; #endif } bool FuseBranchCmp(P, bool imm) { #ifdef HAVE_JIT i64 bdisp; u8 *p, jcc, jlen; if (RegLog2(rde) < 2) { LogCodOp(m, "can't fuse cmp: byte/word fuse unimplemented"); return false; } if (4096 - (m->ip & 4095) < 6) { LogCodOp(m, "can't fuse cmp: too close to the edge"); return false; } if (!(p = GetAddress(m, m->ip))) { LogCodOp(m, "can't fuse cmp: null address"); return false; } if ((p[0] & 0xf0) == 0x70) { // Jcc Jbs jlen = 2; jcc = p[0] & 0x0f; bdisp = (i8)Read8(p + 1); } else if (p[0] == 0x0f && (p[1] & 0xf0) == 0x80) { // Jcc Jvds jlen = 6; jcc = p[1] & 0x0f; bdisp = (i32)Read32(p + 2); } else { LogCodOp(m, "can't fuse cmp: not followed by jump"); return false; } #ifndef __x86_64__ switch (jcc) { case 0x0: // jo break; case 0x1: // jno break; case 0x2: // jb break; case 0x3: // jae break; case 0x4: // je break; case 0x5: // jne break; case 0x6: // jbe break; case 0x7: // ja break; case 0xC: // jl break; case 0xD: // jge break; case 0xE: // jle break; case 0xF: // jg break; default: LogCodOp(m, "can't fuse cmp: unsupported jump operation"); return false; } #endif if (GetNeededFlags(m, m->ip + jlen + bdisp, CF | ZF | SF | OF | AF | PF)) { LogCodOp(m, "can't fuse cmp: loop carries"); return false; } if (GetNeededFlags(m, m->ip + jlen, CF | ZF | SF | OF | AF | PF)) { LogCodOp(m, "can't fuse cmp: loop exit carries"); return false; } #if LOG_CPU LogCpu(m); #endif FlushCod(m->path.jb); WriteCod("/\tfusing branch cmp+jcc\n"); BeginCod(m, m->ip); #if LOG_JIX Jitter(A, "a1i" // arg1 = ip "c" // call function "q", // arg0 = machine m->ip, FuseOp); #endif if (IsModrmRegister(rde)) { Jitter(A, "a1i" // arg1 = skew + jlen "m", // call micro-op m->path.skew + jlen, AdvanceIp); } else { Jitter(A, "a2i" // arg2 = delta "a1i" // arg1 = oplen "m", // call micro-op m->path.skew + jlen, Oplength(rde) + jlen, SkewIp); } m->path.skew = 0; if (imm) { Jitter(A, "s1i", uimm0); } else { Jitter(A, "A" // res0 = GetReg(RexrReg) "r0s1="); // sav1 = res0 } #ifdef __x86_64__ Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "q"); // arg0 = machine AlignJit(m->path.jb, 8, 3); u8 code[] = { // cmp %r12,%rax (u8)((Rexw(rde) ? kAmdRexw : 0) | (kJitSav1 > 7 ? kAmdRexr : 0)), 0x39, 0300 | (kJitSav1 & 7) << 3 | kJitRes0, // jz/jnz +5 (u8)(0x70 | jcc), 5, }; #elif defined(__aarch64__) Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q"); // arg0 = machine // 54000000 b.eq #0 equal // 54000001 b.ne #0 not equal // 54000002 b.cs #0 carry set // 54000003 b.cc #0 carry clear // 54000004 b.mi #0 less than // 54000005 b.pl #0 positive or zero // 54000006 b.vs #0 signed overflow // 54000007 b.vc #0 no signed overflow // 54000008 b.hi #0 greater than (unsigned) // 54000009 b.ls #0 less than or equal to (unsigned) // 5400000a b.ge #0 greater than or equal to (signed) // 5400000b b.lt #0 less than (signed) // 5400000c b.gt #0 greater than (signed) // 5400000d b.le #0 less than or equal to (signed) switch (jcc) { case 0x0: // jo → b.vs jcc = 0x6; break; case 0x1: // jno → b.vc jcc = 0x7; break; case 0x2: // jb → b.cc jcc = 0x3; break; case 0x3: // jae → b.cs jcc = 0x2; break; case 0x4: // je → b.eq jcc = 0x0; break; case 0x5: // jne → b.ne jcc = 0x1; break; case 0x6: // jbe → b.ls jcc = 0x9; break; case 0x7: // ja → b.hi jcc = 0x8; break; case 0xC: // jl → b.lt jcc = 0xB; break; case 0xD: // jge → b.ge jcc = 0xA; break; case 0xE: // jle → b.le jcc = 0xD; break; case 0xF: // jg → b.gt jcc = 0xC; break; default: __builtin_unreachable(); } u32 code[] = { // 6b07007f cmp w3, w7 // eb07007f cmp x3, x7 Rexw(rde) << 31 | 0x6b00001f | kJitSav1 << 16 | kJitArg1 << 5, // 54000000 b.xx 0x54000000 | (8 / 4) << 5 | jcc, }; #else #error "architecture not implemented" #endif AppendJit(m->path.jb, code, sizeof(code)); Connect(A, m->ip + jlen, true); Jitter(A, "a1i" // arg1 = disp "m" // call micro-op "q", // arg0 = machine bdisp, AdvanceIp); AlignJit(m->path.jb, 8, 0); Connect(A, m->ip + jlen + bdisp, false); FinishPath(m); m->path.skip = 1; STATISTIC(++fused_branches); return true; #else return false; #endif } ================================================ FILE: blink/getopt.c ================================================ /* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */ /* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)getopt.c 8.3 (Berkeley) 4/27/95 * $FreeBSD: src/lib/libc/stdlib/getopt.c,v 1.8 2007/01/09 00:28:10 imp Exp $ * $DragonFly: src/lib/libc/stdlib/getopt.c,v 1.7 2005/11/20 12:37:48 swildner */ #include #include /** * @fileoverview Command Line Argument Parser * * We vendor this ancient NetBSD getopt() implementation because: * * 1. We want the non-GNU behavior where flags must come before the * first argument. GNU systems permit flags to come after arguments, * which isn't a great fit for commands like `blink` whose arguments * are mostly just passed along to a sub-command. * * 2. We've modified it by hand to have a tiny transitive footprint. The * `blink` command can't depend on beefy libc functions like printf() * or even snprintf(). */ #define BADCH '?' #define BADARG ':' int optind_; char *optarg_; static char *getopt_place; static char getopt_emsg[1]; static void getopt_print_badch(int argc, char *const argv[], int optopt, const char *s) { long i = 0; char b[256], *t; if (argc > 0 && (t = argv[0])) { while (*t && i < sizeof(b) - 64) b[i++] = *t++; b[i++] = ':'; b[i++] = ' '; } while (*s) b[i++] = *s++; b[i + 0] = ' '; b[i + 1] = '-'; b[i + 2] = '-'; b[i + 3] = ' '; b[i + 4] = optopt; b[i + 5] = '\n'; (void)!write(2, b, i + 6); } /** * Parses argc/argv argument vector, e.g. * * while ((opt = getopt(argc, argv, "hvx:")) != -1) { * switch (opt) { * case 'x': * x = atoi(optarg_); * break; * case 'v': * ++verbose; * break; * case 'h': * PrintUsage(EXIT_SUCCESS, stdout); * default: * PrintUsage(EX_USAGE, stderr); * } * } * * @see optind_ * @see optarg_ */ int GetOpt(int nargc, char *const nargv[], const char *ostr) { int optopt; const char *oli; /* option letter list index */ if (!optind_) optind_ = 1; if (!getopt_place) getopt_place = getopt_emsg; if (!*getopt_place) { /* update scanning pointer */ getopt_place = nargv[optind_]; if (optind_ >= nargc || *getopt_place++ != '-') { /* Argument is absent or is not an option */ getopt_place = getopt_emsg; return -1; } optopt = *getopt_place++; if (optopt == '-' && *getopt_place == 0) { /* "--" => end of options */ ++optind_; getopt_place = getopt_emsg; return -1; } if (optopt == 0) { /* Solitary '-', treat as a '-' option if the program (eg su) is looking for it. */ getopt_place = getopt_emsg; if (!strchr(ostr, '-')) return -1; optopt = '-'; } } else { optopt = *getopt_place++; } /* See if option letter is one the caller wanted... */ if (optopt == ':' || !(oli = strchr(ostr, optopt))) { if (*getopt_place == 0) ++optind_; if (*ostr != ':') getopt_print_badch(nargc, nargv, optopt, "illegal option"); return BADCH; } /* Does this option need an argument? */ if (oli[1] != ':') { /* don't need argument */ optarg_ = 0; if (*getopt_place == 0) ++optind_; } else { /* Option-argument is either the rest of this argument or the entire next argument. */ if (*getopt_place) { optarg_ = getopt_place; } else if (nargc > ++optind_) { optarg_ = nargv[optind_ & 0xffffffff]; } else { /* option-argument absent */ getopt_place = getopt_emsg; if (*ostr == ':') return BADARG; getopt_print_badch(nargc, nargv, optopt, "option requires an argument"); return BADCH; } getopt_place = getopt_emsg; ++optind_; } return optopt; /* return option letter */ } ================================================ FILE: blink/hex.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/debug.h" #include "blink/log.h" #include "blink/tsan.h" #define APPEND(...) oi += snprintf(ob + oi, oi > on ? 0 : on - oi, __VA_ARGS__) void DumpHex(u8 *p, size_t n) { int oi = 0; int on = n * 100; char *ob = (char *)malloc(on); size_t i, j; IGNORE_RACES_START(); for (i = 0; i < n; i += 16) { APPEND("\n\t%04zx:", i); for (j = 0; j < 16; ++j) { if (i + j < n) { APPEND(" %02x", p[i + j]); } else { APPEND(" "); } } APPEND(" "); for (j = 0; j < 16 && i + j < n; ++j) { APPEND("%c", isprint(p[i + j]) ? p[i + j] : '.'); } } IGNORE_RACES_END(); LOGF("hex dump%s", ob); free(ob); } ================================================ FILE: blink/high.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/high.h" #include #include #include "blink/builtin.h" struct High g_high = { .enabled = true, .active = true, #ifdef __APPLE__ .keyword = 40, #else .keyword = 155, #endif .reg = 215, .literal = 182, .label = 221, .comment = 112, .quote = 215, }; char *HighStart(char *p, int h) { if (g_high.enabled) { if (h) { p = stpcpy(p, "\033[38;5;"); p += snprintf(p, 12, "%u", h); p = stpcpy(p, "m"); g_high.active = true; } } return p; } char *HighEnd(char *p) { if (g_high.enabled) { if (g_high.active) { p = stpcpy(p, "\033[39m"); g_high.active = false; } } return p; } ================================================ FILE: blink/high.h ================================================ #ifndef BLINK_HIGH_H_ #define BLINK_HIGH_H_ #include #include "blink/types.h" #define DISABLE_HIGHLIGHT_BEGIN \ { \ bool high_; \ high_ = g_high.enabled; \ g_high.enabled = false #define DISABLE_HIGHLIGHT_END \ g_high.enabled = high_; \ } struct High { bool enabled; bool active; u8 keyword; u8 reg; u8 literal; u8 label; u8 comment; u8 quote; }; extern struct High g_high; char *HighStart(char *, int); char *HighEnd(char *); #endif /* BLINK_HIGH_H_ */ ================================================ FILE: blink/hostfs.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Trung Nguyen │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/hostfs.h" #include #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/errno.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/syscall.h" #include "blink/vfs.h" #ifndef DISABLE_VFS struct HostfsDevice { const char *source; size_t sourcelen; }; static u64 HostfsHash(u64 parent, const char *data, size_t size) { u64 hash; if (data == NULL) { efault(); return 0; } hash = parent; while (size--) { hash = *data++ + (hash << 6) + (hash << 16) - hash; } return hash; } int HostfsInit(const char *source, u64 flags, const void *data, struct VfsDevice **device, struct VfsMount **mount) { struct HostfsDevice *hostdevice; struct HostfsInfo *hostfsrootinfo; struct stat st; if (source == NULL) { return efault(); } if (stat(source, &st) == -1) { return -1; } if (!S_ISDIR(st.st_mode)) { return enotdir(); } hostdevice = NULL; hostfsrootinfo = NULL; *device = NULL; *mount = NULL; hostdevice = (struct HostfsDevice *)malloc(sizeof(struct HostfsDevice)); if (hostdevice == NULL) { return enomem(); } hostdevice->source = realpath(source, NULL); if (hostdevice->source == NULL) { goto cleananddie; } hostdevice->sourcelen = strlen(hostdevice->source); if (hostdevice->source[hostdevice->sourcelen - 1] == '/') { hostdevice->sourcelen--; } if (VfsCreateDevice(device) == -1) { goto cleananddie; } (*device)->data = hostdevice; (*device)->ops = &g_hostfs.ops; *mount = (struct VfsMount *)malloc(sizeof(struct VfsMount)); if (*mount == NULL) { goto cleananddie; } if (VfsCreateInfo(&(*mount)->root) == -1) { goto cleananddie; } unassert(!VfsAcquireDevice(*device, &(*mount)->root->device)); if (HostfsCreateInfo(&hostfsrootinfo) == -1) { goto cleananddie; } (*mount)->root->data = hostfsrootinfo; hostfsrootinfo->mode = st.st_mode; (*mount)->root->mode = st.st_mode; (*mount)->root->ino = HostfsHash(st.st_dev, (const char *)&st.st_ino, sizeof(st.st_ino)); // Weak reference. (*device)->root = (*mount)->root; VFS_LOGF("Mounted a hostfs device for \"%s\"", source); return 0; cleananddie: if (*device) { unassert(!VfsFreeDevice(*device)); } else { if (hostdevice) { free((void *)hostdevice->source); free(hostdevice); } } if (*mount) { if ((*mount)->root) { unassert(!VfsFreeInfo((*mount)->root)); } else { free(hostfsrootinfo); } free(*mount); } return -1; } int HostfsReadmountentry(struct VfsDevice *device, char **spec, char **type, char **mntops) { struct HostfsDevice *hostfsdevice = (struct HostfsDevice *)device->data; *spec = strdup(hostfsdevice->source); if (*spec == NULL) { return enomem(); } *type = strdup("hostfs"); if (*type == NULL) { free(*spec); return enomem(); } *mntops = NULL; return 0; } int HostfsFreeInfo(void *info) { struct HostfsInfo *hostfsinfo = (struct HostfsInfo *)info; if (info == NULL) { return 0; } VFS_LOGF("HostfsFreeInfo(%p)", info); if (S_ISDIR(hostfsinfo->mode)) { if (hostfsinfo->dirstream) { unassert(!closedir(hostfsinfo->dirstream)); } else if (hostfsinfo->filefd != -1) { unassert(!close(hostfsinfo->filefd)); } } else if (S_ISSOCK(hostfsinfo->mode)) { if (hostfsinfo->filefd != -1) { unassert(!close(hostfsinfo->filefd)); } free(hostfsinfo->socketaddr); free(hostfsinfo->socketpeeraddr); } else { if (hostfsinfo->filefd != -1) { unassert(!close(hostfsinfo->filefd)); } } free(info); return 0; } int HostfsFreeDevice(void *device) { struct HostfsDevice *hostfsdevice = (struct HostfsDevice *)device; if (device == NULL) { return 0; } VFS_LOGF("HostfsFreeDevice(%p)", device); free((void *)hostfsdevice->source); free(hostfsdevice); return 0; } int HostfsCreateInfo(struct HostfsInfo **output) { *output = (struct HostfsInfo *)malloc(sizeof(struct HostfsInfo)); if (!*output) { return 0; } (*output)->mode = 0; (*output)->socketfamily = 0; (*output)->filefd = -1; (*output)->dirstream = NULL; (*output)->socketaddr = NULL; (*output)->socketaddrlen = 0; (*output)->socketpeeraddr = NULL; (*output)->socketpeeraddrlen = 0; return 0; } static ssize_t HostfsGetHostPath(struct VfsInfo *info, char output[VFS_PATH_MAX]) { struct HostfsDevice *hostfsdevice; ssize_t ret = -1; size_t pathlen, sourcelen; if (info == NULL) { efault(); return -1; } hostfsdevice = (struct HostfsDevice *)info->device->data; if ((pathlen = VfsPathBuild(info, info->device->root, true, output)) == -1) { return -1; } sourcelen = hostfsdevice->sourcelen; if (sourcelen && hostfsdevice->source[sourcelen - 1] == '/') { --sourcelen; } pathlen += sourcelen; if (pathlen + 1 >= VFS_PATH_MAX) { ret = enametoolong(); } else { memmove(output + sourcelen, output, pathlen - sourcelen); memcpy(output, hostfsdevice->source, sourcelen); output[pathlen] = '\0'; ret = pathlen; } return ret; } static ssize_t HostfsGetOptimalDirFdName(struct VfsInfo *dir, const char *name, int *hostfd, char hostpath[VFS_PATH_MAX]) { struct VfsInfo *currentdir; struct HostfsDevice *hostdevice; int ret = -1; ssize_t len1, len2; VFS_LOGF("HostfsGetOptimalDirFdName(%p, \"%s\", %p, %p)", dir, name, hostfd, hostpath); if (!S_ISDIR(dir->mode)) { enotdir(); return -1; } currentdir = dir; if (!strcmp(name, "/")) { name = "."; } while (currentdir && currentdir->dev == dir->dev) { if (currentdir->data && ((struct HostfsInfo *)currentdir->data)->filefd != -1) { *hostfd = ((struct HostfsInfo *)currentdir->data)->filefd; if (dir != currentdir) { if ((len1 = VfsPathBuild(dir, currentdir, false, hostpath)) == -1) { ret = -1; } len2 = strlen(name); if (hostpath[len1 - 1] == '/') { --len1; } if (len1 + 1 + len2 >= VFS_PATH_MAX) { ret = enametoolong(); } else { hostpath[len1] = '/'; memcpy(hostpath + len1 + 1, name, len2); hostpath[len1 + 1 + len2] = '\0'; ret = len1 + 1 + len2; } break; } else { len1 = strlen(name); if (len1 >= VFS_PATH_MAX) { ret = enametoolong(); } else { memcpy(hostpath, name, len1 + 1); ret = len1; } break; } } currentdir = currentdir->parent; } if (ret == -1 && (!currentdir || currentdir->dev != dir->dev)) { *hostfd = AT_FDCWD; if ((len1 = VfsPathBuild(dir, dir->device->root, true, hostpath)) == -1) { ret = -1; } else { len2 = strlen(name); hostdevice = (struct HostfsDevice *)dir->device->data; ret = hostdevice->sourcelen + len1 + // add a slash if the host path doesn't end with one ((len2 == 0) ? 0 : len2 + (hostpath[len1 - 1] != '/')); if (ret + 1 >= VFS_PATH_MAX) { ret = enametoolong(); } else { memmove(hostpath + hostdevice->sourcelen, hostpath, len1); memcpy(hostpath, hostdevice->source, hostdevice->sourcelen); if (len2 != 0) { if (hostpath[hostdevice->sourcelen + len1 - 1] != '/') { hostpath[hostdevice->sourcelen + len1] = '/'; ++len1; } memcpy(hostpath + hostdevice->sourcelen + len1, name, len2 + 1); } hostpath[ret] = '\0'; } } } VFS_LOGF("HostfsGetOptimalDirFdName: output=\"%s\"", hostpath); return ret; } int HostfsFinddir(struct VfsInfo *parent, const char *name, struct VfsInfo **output) { struct HostfsInfo *outputinfo; struct stat st; int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsFinddir(%p, \"%s\", %p)", parent, name, output); if (parent == NULL || name == NULL || output == NULL) { efault(); return -1; } if (!S_ISDIR(parent->mode)) { enotdir(); return -1; } *output = NULL; outputinfo = NULL; if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } if (fstatat(hostfd, hostname, &st, AT_SYMLINK_NOFOLLOW) == -1) { VFS_LOGF("HostfsFinddir: fstatat(%d, \"%s\", %p, AT_SYMLINK_NOFOLLOW) " "failed (%d)", hostfd, hostname, &st, errno); goto cleananddie; } if (HostfsCreateInfo(&outputinfo) == -1) { goto cleananddie; } outputinfo->mode = st.st_mode; outputinfo->filefd = -1; if (VfsCreateInfo(output) == -1) { goto cleananddie; } (*output)->name = strdup(name); if ((*output)->name == NULL) { enomem(); goto cleananddie; } (*output)->namelen = strlen(name); (*output)->data = outputinfo; unassert(!VfsAcquireDevice(parent->device, &(*output)->device)); (*output)->dev = parent->dev; (*output)->ino = HostfsHash(st.st_dev, (const char *)&st.st_ino, sizeof(st.st_ino)); (*output)->mode = st.st_mode; (*output)->refcount = 1; unassert(!VfsAcquireInfo(parent, &(*output)->parent)); return 0; cleananddie: if (*output) { unassert(!VfsFreeInfo(*output)); } else { unassert(!HostfsFreeInfo(outputinfo)); } return -1; } int HostfsTraverse(struct VfsInfo **dir, const char **path, struct VfsInfo *root) { char hostpath[VFS_PATH_MAX]; struct VfsInfo *next, *original; struct HostfsInfo *nexthost; const char *currentpath = *path, *nextpath; struct stat st; ssize_t hostpathlen, currentnamelen; u32 currentdev; int hostfd; VFS_LOGF("HostfsTraverse(%s, \"%s\", %p)", (*dir)->name, *path, root); if ((hostpathlen = HostfsGetOptimalDirFdName(*dir, "", &hostfd, hostpath)) == -1) { return -1; } if (hostpathlen > 0 && hostpath[hostpathlen - 1] != '/') { if (hostpathlen + 1 >= VFS_PATH_MAX) { return enametoolong(); } hostpath[hostpathlen] = '/'; ++hostpathlen; } VFS_LOGF("HostfsTraverse: hostpath=\"%s\", hostfd=%d", hostpath, hostfd); original = *dir; next = NULL; nexthost = NULL; currentdev = (*dir)->dev; while (*currentpath) { while (*currentpath == '/') { ++currentpath; } nextpath = currentpath; while (*nextpath && *nextpath != '/') { ++nextpath; } if (nextpath == currentpath) { break; } if (!strcmp(currentpath, ".")) { currentpath = nextpath; continue; } else if (!strcmp(currentpath, "..")) { currentpath = nextpath; if (*dir == root || (*dir)->parent == NULL) { continue; } unassert(!VfsAcquireInfo((*dir)->parent, &next)); unassert(!VfsFreeInfo(*dir)); *dir = next; if (next->dev != currentdev) { *path = currentpath; return 0; } if (hostpathlen > 0) { --hostpathlen; while (hostpathlen > 0 && hostpath[hostpathlen - 1] != '/') { --hostpathlen; } hostpath[hostpathlen] = '\0'; } continue; } currentnamelen = nextpath - currentpath; if (currentnamelen >= VFS_NAME_MAX) { enametoolong(); goto cleananddie; } if (currentnamelen + hostpathlen + 1 >= VFS_PATH_MAX) { enametoolong(); goto cleananddie; } memcpy(hostpath + hostpathlen, currentpath, currentnamelen); hostpath[hostpathlen + currentnamelen] = '\0'; VFS_LOGF("HostfsTraverse: fstatat(%d, \"%s\", %p, AT_SYMLINK_NOFOLLOW)", hostfd, hostpath, &st); if (fstatat(hostfd, hostpath, &st, AT_SYMLINK_NOFOLLOW) == -1) { if (original != *dir) { *path = currentpath; return 0; } else { return enoent(); } } hostpath[hostpathlen + currentnamelen] = '/'; hostpath[hostpathlen + currentnamelen + 1] = '\0'; hostpathlen += currentnamelen + 1; if (HostfsCreateInfo(&nexthost) == -1) { goto cleananddie; } nexthost->mode = st.st_mode; nexthost->filefd = -1; if (VfsCreateInfo(&next) == -1) { unassert(!HostfsFreeInfo(nexthost)); goto cleananddie; } next->name = strndup(currentpath, currentnamelen); if (next->name == NULL) { unassert(!VfsFreeInfo(next)); unassert(!HostfsFreeInfo(nexthost)); enomem(); goto cleananddie; } next->namelen = currentnamelen; next->data = nexthost; unassert(!VfsAcquireDevice((*dir)->device, &next->device)); next->dev = currentdev; next->ino = HostfsHash(st.st_dev, (const char *)&st.st_ino, sizeof(st.st_ino)); next->mode = st.st_mode; next->refcount = 1; next->parent = *dir; *dir = next; currentpath = nextpath; VFS_LOGF("HostfsTraverse: Changed current path to \"%s\"", currentpath); if (!S_ISDIR(st.st_mode)) { break; } } *path = currentpath; return 0; cleananddie: while (original != *dir) { unassert(!VfsAcquireInfo((*dir)->parent, &next)); unassert(!VfsFreeInfo(*dir)); *dir = next; } return -1; } ssize_t HostfsReadlink(struct VfsInfo *info, char **output) { struct HostfsInfo *hostinfo; char *buf; char name[VFS_PATH_MAX]; ssize_t len, reallen; int fd; VFS_LOGF("HostfsReadlink(%p, %p)", info, output); if (info == NULL || output == NULL) { efault(); return -1; } if (!S_ISLNK(info->mode)) { einval(); return -1; } hostinfo = (struct HostfsInfo *)info->data; if (hostinfo->filefd != -1) { fd = hostinfo->filefd; name[0] = '\0'; } else { fd = -1; if (HostfsGetHostPath(info, name) == -1) { return -1; } } len = VFS_PATH_MAX; buf = (char *)malloc(len); if (buf == NULL) { enomem(); goto cleananddie; } while (true) { reallen = readlinkat(fd, name, buf, len); if (reallen == -1) { goto cleananddie; } if (reallen < len) { break; } len *= 2; buf = (char *)realloc(buf, len); if (buf == NULL) { enomem(); goto cleananddie; } } buf[reallen] = '\0'; *output = buf; if (fd != -1) { unassert(!close(fd)); } return reallen; cleananddie: if (fd != -1) { unassert(!close(fd)); } free(buf); return -1; } int HostfsMkdir(struct VfsInfo *parent, const char *name, mode_t mode) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsMkdir(%p, \"%s\", %d)", parent, name, mode); if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } return mkdirat(hostfd, hostname, mode); } int HostfsMkfifo(struct VfsInfo *parent, const char *name, mode_t mode) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsMkfifo(%p, \"%s\", %d)", parent, name, mode); if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } return mkfifoat(hostfd, hostname, mode); } int HostfsOpen(struct VfsInfo *parent, const char *name, int flags, int mode, struct VfsInfo **output) { struct HostfsInfo *outputinfo; struct stat st; int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsOpen(%p, \"%s\", %d, %d, %p)", parent, name, flags, mode, output); if (parent == NULL || name == NULL || output == NULL) { return efault(); } if (!S_ISDIR(parent->mode)) { return enotdir(); } *output = NULL; outputinfo = NULL; if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } if (HostfsCreateInfo(&outputinfo) == -1) { goto cleananddie; } outputinfo->filefd = openat(hostfd, hostname, flags, mode); VFS_LOGF("HostfsOpen: openat(%d, \"%s\", %d, %d) -> %d, %s", hostfd, hostname, flags, mode, outputinfo->filefd, strerror(errno)); if (outputinfo->filefd == -1) { goto cleananddie; } unassert(fstat(outputinfo->filefd, &st) != -1); outputinfo->mode = st.st_mode; if (VfsCreateInfo(output) == -1) { goto cleananddie; } (*output)->data = outputinfo; (*output)->name = strdup(name); if ((*output)->name == NULL) { enomem(); goto cleananddie; } (*output)->namelen = strlen(name); unassert(!VfsAcquireDevice(parent->device, &(*output)->device)); (*output)->dev = parent->dev; (*output)->ino = HostfsHash(st.st_dev, (const char *)&st.st_ino, sizeof(st.st_ino)); (*output)->mode = outputinfo->mode; (*output)->refcount = 1; unassert(!VfsAcquireInfo(parent, &(*output)->parent)); return 0; cleananddie: if (*output) { unassert(!VfsFreeInfo(*output)); } else { unassert(!HostfsFreeInfo(outputinfo)); } return -1; } int HostfsAccess(struct VfsInfo *parent, const char *name, mode_t mode, int flags) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsAccess(%p, \"%s\", %d, %d)", parent, name, mode, flags); if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } return faccessat(hostfd, hostname, mode, flags); } int HostfsStat(struct VfsInfo *parent, const char *name, struct stat *st, int flags) { int hostfd, ret; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsStat(%p, \"%s\", %p, %d)", parent, name, st, flags); if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } ret = fstatat(hostfd, hostname, st, flags); if (ret != -1) { st->st_ino = HostfsHash(st->st_dev, (const char *)&st->st_ino, sizeof(st->st_ino)); st->st_dev = parent->dev; } return ret; } int HostfsFstat(struct VfsInfo *info, struct stat *st) { struct HostfsInfo *hostinfo; int ret; VFS_LOGF("HostfsFstat(%p, %p)", info, st); if (info == NULL || st == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; ret = fstat(hostinfo->filefd, st); if (ret != -1) { st->st_ino = HostfsHash(st->st_dev, (const char *)&st->st_ino, sizeof(st->st_ino)); st->st_dev = info->dev; } return ret; } int HostfsChmod(struct VfsInfo *parent, const char *name, mode_t mode, int flags) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsChmod(%p, \"%s\", %d)", parent, name, mode); if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } return fchmodat(hostfd, hostname, mode, flags); } int HostfsFchmod(struct VfsInfo *info, mode_t mode) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsFchmod(%p, %d)", info, mode); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return fchmod(hostinfo->filefd, mode); } int HostfsChown(struct VfsInfo *parent, const char *name, uid_t uid, gid_t gid, int flags) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsChown(%p, \"%s\", %d, %d)", parent, name, uid, gid); if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } return fchownat(hostfd, hostname, uid, gid, flags); } int HostfsFchown(struct VfsInfo *info, uid_t uid, gid_t gid) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsFchown(%p, %d, %d)", info, uid, gid); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return fchown(hostinfo->filefd, uid, gid); } int HostfsFtruncate(struct VfsInfo *info, off_t length) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsFtruncate(%p, %ld)", info, length); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return ftruncate(hostinfo->filefd, length); } int HostfsClose(struct VfsInfo *info) { struct HostfsInfo *hostinfo; int ret; VFS_LOGF("HostfsClose(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; ret = close(hostinfo->filefd); hostinfo->filefd = -1; return ret; } int HostfsLink(struct VfsInfo *oldparent, const char *oldname, struct VfsInfo *newparent, const char *newname, int flags) { int oldhostfd, newhostfd; char oldhostname[VFS_PATH_MAX], newhostname[VFS_PATH_MAX]; VFS_LOGF("HostfsLink(%p, \"%s\", %p, \"%s\")", oldparent, oldname, newparent, newname); if (HostfsGetOptimalDirFdName(oldparent, oldname, &oldhostfd, oldhostname) == -1) { return -1; } if (HostfsGetOptimalDirFdName(newparent, newname, &newhostfd, newhostname) == -1) { return -1; } return linkat(oldhostfd, oldhostname, newhostfd, newhostname, flags); } int HostfsUnlink(struct VfsInfo *parent, const char *name, int flags) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsUnlink(%p, \"%s\")", parent, name); if (HostfsGetOptimalDirFdName(parent, name, &hostfd, hostname) == -1) { return -1; } return unlinkat(hostfd, hostname, flags); } ssize_t HostfsRead(struct VfsInfo *info, void *buf, size_t size) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsRead(%p, %p, %ld)", info, buf, size); if (info == NULL || buf == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return read(hostinfo->filefd, buf, size); } ssize_t HostfsWrite(struct VfsInfo *info, const void *buf, size_t size) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsWrite(%p, %p, %ld)", info, buf, size); if (info == NULL || buf == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return write(hostinfo->filefd, buf, size); } ssize_t HostfsPread(struct VfsInfo *info, void *buf, size_t size, off_t offset) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsPread(%p, %p, %ld, %ld)", info, buf, size, offset); if (info == NULL || buf == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return pread(hostinfo->filefd, buf, size, offset); } ssize_t HostfsPwrite(struct VfsInfo *info, const void *buf, size_t size, off_t offset) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsPwrite(%p, %p, %ld, %ld)", info, buf, size, offset); if (info == NULL || buf == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return pwrite(hostinfo->filefd, buf, size, offset); } ssize_t HostfsReadv(struct VfsInfo *info, const struct iovec *iov, int iovcnt) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsReadv(%p, %p, %d)", info, iov, iovcnt); if (info == NULL || iov == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return readv(hostinfo->filefd, iov, iovcnt); } ssize_t HostfsWritev(struct VfsInfo *info, const struct iovec *iov, int iovcnt) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsWritev(%p, %p, %d)", info, iov, iovcnt); if (info == NULL || iov == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return writev(hostinfo->filefd, iov, iovcnt); } ssize_t HostfsPreadv(struct VfsInfo *info, const struct iovec *iov, int iovcnt, off_t offset) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsPreadv(%p, %p, %d, %ld)", info, iov, iovcnt, offset); if (info == NULL || iov == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return preadv(hostinfo->filefd, iov, iovcnt, offset); } ssize_t HostfsPwritev(struct VfsInfo *info, const struct iovec *iov, int iovcnt, off_t offset) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsPwritev(%p, %p, %d, %ld)", info, iov, iovcnt, offset); if (info == NULL || iov == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return pwritev(hostinfo->filefd, iov, iovcnt, offset); } off_t HostfsSeek(struct VfsInfo *info, off_t offset, int whence) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsLseek(%p, %ld, %d)", info, offset, whence); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return lseek(hostinfo->filefd, offset, whence); } int HostfsFsync(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsFsync(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return fsync(hostinfo->filefd); } int HostfsFdatasync(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsFdatasync(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; #ifdef HAVE_FDATASYNC return fdatasync(hostinfo->filefd); #else return fsync(hostinfo->filefd); #endif } int HostfsFlock(struct VfsInfo *info, int operation) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsFlock(%p, %d)", info, operation); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return flock(hostinfo->filefd, operation); } int HostfsFcntl(struct VfsInfo *info, int cmd, va_list args) { struct HostfsInfo *hostinfo; int rc; VFS_LOGF("HostfsFcntl(%p, %d, ...)", info, cmd); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (hostinfo == NULL) { return enoent(); } if (cmd == F_GETFD || cmd == F_GETFL || cmd == F_GETOWN #ifdef F_GETSIG || cmd == F_GETSIG #endif #ifdef F_GETLEASE || cmd == F_GETLEASE #endif #ifdef F_GETPIPE_SZ || cmd == F_GETPIPE_SZ #endif #ifdef F_GET_SEALS || cmd == F_GET_SEALS #endif ) { rc = fcntl(hostinfo->filefd, cmd); } else if (cmd == F_SETFD || cmd == F_SETFL || cmd == F_SETOWN #ifdef F_SETSIG || cmd == F_SETSIG #endif #ifdef F_SETLEASE || cmd == F_SETLEASE #endif #ifdef F_NOTIFY || cmd == F_NOTIFY #endif #ifdef F_SETPIPE_SZ || cmd == F_SETPIPE_SZ #endif #ifdef F_ADD_SEALS || cmd == F_ADD_SEALS #endif ) { rc = fcntl(hostinfo->filefd, cmd, va_arg(args, int)); } else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK #ifdef F_OFD_SETLK || cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW || cmd == F_OFD_GETLK #endif ) { rc = fcntl(hostinfo->filefd, cmd, va_arg(args, struct flock *)); #ifdef F_GETOWN_EX } else if (cmd == F_GETOWN_EX || cmd == F_SETOWN_EX) { rc = fcntl(hostinfo->filefd, cmd, va_arg(args, struct f_owner_ex *)); #endif #ifdef F_GET_RW_HINT } else if (cmd == F_GET_RW_HINT || cmd == F_SET_RW_HINT || cmd == F_GET_FILE_RW_HINT || cmd == F_SET_FILE_RW_HINT) { rc = fcntl(hostinfo->filefd, cmd, va_arg(args, uint64_t *)); #endif } else { rc = einval(); } return rc; } int HostfsIoctl(struct VfsInfo *info, unsigned long request, const void *arg) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsIoctl(%p, %lu, %p)", info, request, arg); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return ioctl(hostinfo->filefd, request, arg); } int HostfsDup(struct VfsInfo *info, struct VfsInfo **newinfo) { struct HostfsInfo *hostinfo, *newhostinfo; VFS_LOGF("HostfsDup(%p, %p)", info, newinfo); if (info == NULL || newinfo == NULL) { return efault(); } *newinfo = NULL; newhostinfo = NULL; hostinfo = (struct HostfsInfo *)info->data; if (hostinfo == NULL) { return enoent(); } if (HostfsCreateInfo(&newhostinfo) == -1) { return -1; } newhostinfo->filefd = dup(hostinfo->filefd); if (newhostinfo->filefd == -1) { goto cleananddie; } newhostinfo->mode = hostinfo->mode; if (S_ISSOCK(hostinfo->mode) && hostinfo->socketaddr != NULL) { newhostinfo->socketaddr = (struct sockaddr *)malloc(hostinfo->socketaddrlen); if (newhostinfo->socketaddr != NULL) { memcpy(newhostinfo->socketaddr, hostinfo->socketaddr, hostinfo->socketaddrlen); newhostinfo->socketaddrlen = hostinfo->socketaddrlen; } } else if (S_ISDIR(hostinfo->mode) && hostinfo->dirstream != NULL) { newhostinfo->dirstream = fdopendir(newhostinfo->filefd); if (newhostinfo->dirstream == NULL) { goto cleananddie; } } if (VfsCreateInfo(newinfo) == -1) { goto cleananddie; } if (info->name != NULL) { (*newinfo)->name = strdup(info->name); if ((*newinfo)->name == NULL) { goto cleananddie; } (*newinfo)->namelen = info->namelen; } (*newinfo)->data = newhostinfo; (*newinfo)->dev = info->dev; unassert(!VfsAcquireDevice(info->device, &(*newinfo)->device)); (*newinfo)->ino = info->ino; (*newinfo)->mode = info->mode; unassert(!VfsAcquireInfo(info->parent, &(*newinfo)->parent)); (*newinfo)->refcount = 1; return 0; cleananddie: unassert(!HostfsFreeInfo(newhostinfo)); unassert(!VfsFreeInfo(*newinfo)); return -1; } #ifdef HAVE_DUP3 int HostfsDup3(struct VfsInfo *info, struct VfsInfo **newinfo, int flags) { struct HostfsInfo *hostinfo, *newhostinfo; VFS_LOGF("HostfsDup3(%p, %p, %i)", info, newinfo, flags); if (info == NULL || newinfo == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (hostinfo == NULL) { return enoent(); } if (HostfsCreateInfo(&newhostinfo) == -1) { return -1; } newhostinfo->filefd = dup3(hostinfo->filefd, open("/dev/null", O_RDONLY), flags); if (newhostinfo->filefd == -1) { goto cleananddie; } if (VfsCreateInfo(newinfo) == -1) { goto cleananddie; } if (info->name != NULL) { (*newinfo)->name = strdup(info->name); if ((*newinfo)->name == NULL) { goto cleananddie; } (*newinfo)->namelen = info->namelen; } if (VfsCreateInfo(newinfo) == -1) { goto cleananddie; } (*newinfo)->data = newhostinfo; (*newinfo)->dev = info->dev; unassert(!VfsAcquireDevice(info->device, &(*newinfo)->device)); (*newinfo)->ino = info->ino; (*newinfo)->mode = info->mode; unassert(!VfsAcquireInfo(info->parent, &(*newinfo)->parent)); (*newinfo)->refcount = 1; return 0; cleananddie: unassert(!HostfsFreeInfo(newhostinfo)); unassert(!VfsFreeInfo(*newinfo)); return -1; } #endif int HostfsPoll(struct VfsInfo **infos, struct pollfd *fds, nfds_t nfds, int timeout) { int rc; int oldfd; VFS_LOGF("HostfsPoll(%p, %lli, %i)", infos, (long long)nfds, timeout); if (infos == NULL) { return efault(); } // Same reason as in VfsPoll above unassert(nfds == 1); oldfd = fds->fd; fds->fd = ((struct HostfsInfo *)infos[0]->data)->filefd; rc = poll(fds, nfds, timeout); fds->fd = oldfd; return rc; } int HostfsOpendir(struct VfsInfo *info, struct VfsInfo **output) { struct HostfsInfo *hostinfo; DIR *dirstream; VFS_LOGF("HostfsOpendir(%p)", info); if (info == NULL || output == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; unassert(hostinfo->filefd != -1); dirstream = fdopendir(hostinfo->filefd); if (dirstream == NULL) { return -1; } hostinfo->dirstream = dirstream; unassert(!VfsAcquireInfo(info, output)); return 0; } #ifdef HAVE_SEEKDIR void HostfsSeekdir(struct VfsInfo *info, long loc) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsSeekdir(%p, %ld)", info, loc); if (info == NULL) { efault(); return; } hostinfo = (struct HostfsInfo *)info->data; return seekdir(hostinfo->dirstream, loc); } long HostfsTelldir(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTelldir(%p)", info); if (info == NULL) { efault(); return -1; } hostinfo = (struct HostfsInfo *)info->data; return telldir(hostinfo->dirstream); } #endif struct dirent *HostfsReaddir(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsReaddir(%p)", info); if (info == NULL) { efault(); return NULL; } hostinfo = (struct HostfsInfo *)info->data; return readdir(hostinfo->dirstream); } void HostfsRewinddir(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsRewinddir(%p)", info); if (info == NULL) { efault(); return; } hostinfo = (struct HostfsInfo *)info->data; return rewinddir(hostinfo->dirstream); } int HostfsClosedir(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsClosedir(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (closedir(hostinfo->dirstream) == -1) { return -1; } hostinfo->dirstream = NULL; hostinfo->filefd = -1; unassert(!VfsFreeInfo(info)); return 0; } int HostfsBind(struct VfsInfo *info, const struct sockaddr *addr, socklen_t addrlen) { struct HostfsInfo *hostinfo; struct sockaddr_un *hostun; struct stat st; char hostpath[VFS_PATH_MAX]; size_t len; int ret; VFS_LOGF("HostfsBind(%p, %p, %i)", info, addr, addrlen); if (info == NULL || addr == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (addr->sa_family != AF_UNIX) { ret = bind(hostinfo->filefd, addr, addrlen); if (ret == 0) { hostinfo->socketfamily = addr->sa_family; } } else { if (HostfsGetHostPath(info, hostpath) == -1) { ret = -1; } else { len = strlen(hostpath) + 1 + offsetof(struct sockaddr_un, sun_path); hostun = (struct sockaddr_un *)malloc(len); if (hostun == NULL) { ret = -1; } else { hostun->sun_family = AF_UNIX; strcpy(hostun->sun_path, hostpath); ret = bind(hostinfo->filefd, (struct sockaddr *)hostun, len); if (ret == 0) { hostinfo->socketfamily = AF_UNIX; unassert(!fstat(hostinfo->filefd, &st)); info->dev = info->parent->dev; info->ino = HostfsHash(st.st_dev, (const char *)&st.st_ino, sizeof(st.st_ino)); info->mode = st.st_mode; hostinfo->socketaddr = (struct sockaddr *)malloc(addrlen); if (hostinfo->socketaddr != NULL) { memcpy(hostinfo->socketaddr, addr, addrlen); hostinfo->socketaddrlen = addrlen; } } free(hostun); } } } return ret; } int HostfsConnect(struct VfsInfo *info, const struct sockaddr *addr, socklen_t addrlen) { struct HostfsInfo *hostinfo; int ret; VFS_LOGF("HostfsConnect(%p, %p, %i)", info, addr, addrlen); if (info == NULL || addr == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; ret = connect(hostinfo->filefd, addr, addrlen); if (ret == 0) { hostinfo->socketfamily = addr->sa_family; } return ret; } int HostfsConnectUnix(struct VfsInfo *sock, struct VfsInfo *info, const struct sockaddr_un *addr, socklen_t addrlen) { struct HostfsInfo *hostinfo; struct sockaddr_un *hostun; socklen_t hostlen; char hostpath[VFS_PATH_MAX]; size_t hostpathlen; int ret; VFS_LOGF("HostfsConnectUnix(%p, %p, %p, %i)", sock, info, addr, addrlen); if (sock == NULL || info == NULL || addr == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (HostfsGetHostPath(sock, hostpath) == -1) { return -1; } hostpathlen = strlen(hostpath); hostlen = hostpathlen + 1 + offsetof(struct sockaddr_un, sun_path); hostun = (struct sockaddr_un *)malloc(hostlen); if (hostun == NULL) { return enomem(); } hostun->sun_family = AF_UNIX; memcpy(hostun->sun_path, hostpath, hostpathlen + 1); ret = connect(hostinfo->filefd, (struct sockaddr *)hostun, hostlen); free(hostun); if (ret != -1) { hostinfo->socketpeeraddr = (struct sockaddr *)malloc(addrlen); if (hostinfo->socketpeeraddr != NULL) { memcpy(hostinfo->socketpeeraddr, addr, addrlen); hostinfo->socketpeeraddrlen = addrlen; } } return ret; } int HostfsAccept(struct VfsInfo *info, struct sockaddr *addr, socklen_t *addrlen, struct VfsInfo **output) { struct HostfsInfo *hostinfo, *newhostinfo; int ret; VFS_LOGF("HostfsAccept(%p, %p, %p)", info, addr, addrlen); if (info == NULL || output == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (HostfsCreateInfo(&newhostinfo) == -1) { return -1; } if (VfsCreateInfo(output) == -1) { unassert(!HostfsFreeInfo(newhostinfo)); return -1; } (*output)->data = newhostinfo; unassert(!VfsAcquireDevice(info->device, &(*output)->device)); ret = accept(hostinfo->filefd, addr, addrlen); if (ret != -1) { newhostinfo->filefd = ret; newhostinfo->socketfamily = hostinfo->socketfamily; (*output)->ino = info->ino; (*output)->dev = info->dev; (*output)->mode = info->mode; unassert(!VfsFreeInfo((*output)->parent)); unassert(!VfsAcquireInfo(info->parent, &(*output)->parent)); (*output)->refcount = 1; ret = 0; } else { unassert(!VfsFreeInfo(*output)); } return ret; } int HostfsListen(struct VfsInfo *info, int backlog) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsListen(%p, %i)", info, backlog); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return listen(hostinfo->filefd, backlog); } int HostfsShutdown(struct VfsInfo *info, int how) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsShutdown(%p, %i)", info, how); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return shutdown(hostinfo->filefd, how); } ssize_t HostfsRecvmsg(struct VfsInfo *info, struct msghdr *msg, int flags) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsRecvmsg(%p, %p, %i)", info, msg, flags); if (info == NULL || msg == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return recvmsg(hostinfo->filefd, msg, flags); } ssize_t HostfsSendmsg(struct VfsInfo *info, const struct msghdr *msg, int flags) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsSendmsg(%p, %p, %i)", info, msg, flags); if (info == NULL || msg == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return sendmsg(hostinfo->filefd, msg, flags); } ssize_t HostfsRecvmsgUnix(struct VfsInfo *sock, struct VfsInfo *info, struct msghdr *msg, int flags) { struct HostfsInfo *hostinfo; struct sockaddr_un *hostun, *oldun; socklen_t hostlen, oldlen; char hostpath[VFS_PATH_MAX]; size_t hostpathlen; int ret; VFS_LOGF("HostfsRecvmsgUnix(%p, %p, %p, %i)", sock, info, msg, flags); if (sock == NULL || info == NULL || msg == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (HostfsGetHostPath(sock, hostpath) == -1) { return -1; } hostpathlen = strlen(hostpath); hostlen = hostpathlen + 1 + offsetof(struct sockaddr_un, sun_path); hostun = (struct sockaddr_un *)malloc(hostlen); if (hostun == NULL) { return enomem(); } hostun->sun_family = AF_UNIX; memcpy(hostun->sun_path, hostpath, hostpathlen + 1); oldun = (struct sockaddr_un *)msg->msg_name; oldlen = msg->msg_namelen; msg->msg_name = hostun; msg->msg_namelen = hostlen; ret = recvmsg(hostinfo->filefd, msg, flags); free(hostun); msg->msg_name = oldun; msg->msg_namelen = oldlen; return ret; } ssize_t HostfsSendmsgUnix(struct VfsInfo *sock, struct VfsInfo *info, const struct msghdr *msg, int flags) { struct HostfsInfo *hostinfo; struct msghdr newmsg; struct sockaddr_un *hostun; socklen_t hostlen; char hostpath[VFS_PATH_MAX]; size_t hostpathlen; int ret; VFS_LOGF("HostfsSendmsgUnix(%p, %p, %p, %i)", sock, info, msg, flags); if (sock == NULL || info == NULL || msg == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (HostfsGetHostPath(sock, hostpath) == -1) { return -1; } hostpathlen = strlen(hostpath); hostlen = hostpathlen + 1 + offsetof(struct sockaddr_un, sun_path); hostun = (struct sockaddr_un *)malloc(hostlen); if (hostun == NULL) { return enomem(); } hostun->sun_family = AF_UNIX; memcpy(hostun->sun_path, hostpath, hostpathlen + 1); memcpy(&newmsg, msg, sizeof(struct msghdr)); newmsg.msg_name = hostun; newmsg.msg_namelen = hostlen; ret = sendmsg(hostinfo->filefd, &newmsg, flags); free(hostun); return ret; } int HostfsGetsockopt(struct VfsInfo *info, int level, int optname, void *optval, socklen_t *optlen) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsGetsockopt(%p, %i, %i, %p, %p)", info, level, optname, optval, optlen); if (info == NULL || optval == NULL || optlen == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return getsockopt(hostinfo->filefd, level, optname, optval, optlen); } int HostfsSetsockopt(struct VfsInfo *info, int level, int optname, const void *optval, socklen_t optlen) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsSetsockopt(%p, %i, %i, %p, %i)", info, level, optname, optval, optlen); if (info == NULL || optval == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return setsockopt(hostinfo->filefd, level, optname, optval, optlen); } int HostfsGetsockname(struct VfsInfo *info, struct sockaddr *addr, socklen_t *addrlen) { struct HostfsInfo *hostinfo; struct sockaddr_un *un; char *path; VFS_LOGF("HostfsGetsockname(%p, %p, %p)", info, addr, addrlen); if (info == NULL || addr == NULL || addrlen == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (hostinfo->socketfamily != AF_UNIX) { return getsockname(hostinfo->filefd, addr, addrlen); } if (hostinfo->socketaddr) { memcpy(addr, hostinfo->socketaddr, MIN(*addrlen, hostinfo->socketaddrlen)); *addrlen = hostinfo->socketaddrlen; } else { if (info->parent == NULL) { return getsockname(hostinfo->filefd, addr, addrlen); } un = (struct sockaddr_un *)addr; if (VfsPathBuildFull(info, NULL, &path) == -1) { return -1; } un->sun_family = AF_UNIX; strncpy(un->sun_path, path, *addrlen - offsetof(struct sockaddr_un, sun_path)); *addrlen = strlen(path) + offsetof(struct sockaddr_un, sun_path); } return 0; } int HostfsGetpeername(struct VfsInfo *info, struct sockaddr *addr, socklen_t *addrlen) { struct HostfsInfo *hostinfo; struct sockaddr_un *hostun; socklen_t hostlen = sizeof(*hostun); char *s; VFS_LOGF("HostfsGetpeername(%p, %p, %p)", info, addr, addrlen); if (info == NULL || addr == NULL || addrlen == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (hostinfo->socketfamily != AF_UNIX) { return getpeername(hostinfo->filefd, addr, addrlen); } else { if (hostinfo->socketpeeraddr) { memcpy(addr, hostinfo->socketpeeraddr, MIN(*addrlen, hostinfo->socketpeeraddrlen)); *addrlen = hostinfo->socketpeeraddrlen; return 0; } hostun = (struct sockaddr_un *)malloc(hostlen + 1); if (hostun == NULL) { return enomem(); } memset(hostun, 0, hostlen + 1); if (getpeername(hostinfo->filefd, (struct sockaddr *)hostun, &hostlen) == -1) { return -1; } else { // As we don't manage the socket connections, this is the best we can do. // For relative names we don't know where it's relative from, and for // absolute names we don't know which device it lives on. // VFS_SYSTEM_ROOT_MOUNT may have been unmounted by the user. if (hostun->sun_path[0] == '/') { s = (char *)malloc(sizeof(VFS_SYSTEM_ROOT_MOUNT) + hostlen - offsetof(struct sockaddr_un, sun_path)); if (s == NULL) { free(hostun); return enomem(); } strcpy(s, VFS_SYSTEM_ROOT_MOUNT); strncat(s, hostun->sun_path, hostlen - offsetof(struct sockaddr_un, sun_path)); addr->sa_family = AF_UNIX; strncpy(addr->sa_data, s, *addrlen - offsetof(struct sockaddr_un, sun_path)); *addrlen = strlen(s) + offsetof(struct sockaddr_un, sun_path); free(s); } else { // This also includes abstract names, where sun_path[0] == '\0'. addr->sa_family = AF_UNIX; strncpy(addr->sa_data, hostun->sun_path, *addrlen - offsetof(struct sockaddr_un, sun_path)); *addrlen = strlen(hostun->sun_path) + offsetof(struct sockaddr_un, sun_path); } free(hostun); return 0; } } } int HostfsRename(struct VfsInfo *oldinfo, const char *oldname, struct VfsInfo *newinfo, const char *newname) { int oldhostfd, newhostfd; char oldhostname[VFS_PATH_MAX], newhostname[VFS_PATH_MAX]; VFS_LOGF("HostfsRename(%p, %s, %p, %s)", oldinfo, oldname, newinfo, newname); if (HostfsGetOptimalDirFdName(oldinfo, oldname, &oldhostfd, oldhostname) == -1) { return -1; } if (HostfsGetOptimalDirFdName(newinfo, newname, &newhostfd, newhostname) == -1) { unassert(!close(oldhostfd)); return -1; } return renameat(oldhostfd, oldhostname, newhostfd, newhostname); } int HostfsUtime(struct VfsInfo *info, const char *name, const struct timespec times[2], int flags) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsUtime(%p, %s, %p, %d)", info, name, times, flags); if (HostfsGetOptimalDirFdName(info, name, &hostfd, hostname) == -1) { return -1; } return utimensat(hostfd, hostname, times, flags); } int HostfsFutime(struct VfsInfo *info, const struct timespec times[2]) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsFutime(%p, %p)", info, times); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; if (futimens(hostinfo->filefd, times) == -1) { return -1; } return 0; } int HostfsSymlink(const char *target, struct VfsInfo *info, const char *name) { int hostfd; char hostname[VFS_PATH_MAX]; VFS_LOGF("HostfsSymlink(%s, %p, %s)", target, info, name); if (HostfsGetOptimalDirFdName(info, name, &hostfd, hostname) == -1) { return -1; } return symlinkat(target, hostfd, hostname); } void *HostfsMmap(struct VfsInfo *info, void *addr, size_t len, int prot, int flags, off_t offset) { #ifdef __CYGWIN__ struct stat st; #endif void *ret; int fd; VFS_LOGF("HostfsMmap(%p, %p, %zu, %d, %d, %zd)", info, addr, len, prot, flags, offset); if (info == NULL) { efault(); return MAP_FAILED; } fd = ((struct HostfsInfo *)info->data)->filefd; #ifdef __CYGWIN__ if (fstat(fd, &st) != -1) { if (offset >= st.st_size) { // Cygwin doesn't like mapping files with offset past the end. fd = -1; flags |= MAP_ANONYMOUS; offset = 0; } } #endif ret = mmap(addr, len, prot, flags, fd, offset); VFS_LOGF("mmap(%p, %zu, %d, %d, %d, %zd) -> %p", addr, len, prot, flags, fd, offset, ret); return ret; } int HostfsMunmap(struct VfsInfo *info, void *addr, size_t len) { VFS_LOGF("HostfsMunmap(%p, %p, %zu)", info, addr, len); // Do nothing. The host should handle all the cleanup. return 0; } int HostfsMprotect(struct VfsInfo *info, void *addr, size_t len, int prot) { VFS_LOGF("HostfsMprotect(%p, %p, %zu, %d)", info, addr, len, prot); // Do nothing, as the host should handle the protection details. return 0; } int HostfsMsync(struct VfsInfo *info, void *addr, size_t len, int flags) { VFS_LOGF("HostfsMsync(%p, %p, %zu, %d)", info, addr, len, flags); // Do nothing, as the host should handle the syncing. return 0; } int HostfsTcgetattr(struct VfsInfo *info, struct termios *termios) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcgetattr(%p, %p)", info, termios); if (info == NULL || termios == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcgetattr(hostinfo->filefd, termios); } int HostfsTcsetattr(struct VfsInfo *info, int optional_actions, const struct termios *termios) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcsetattr(%p, %d, %p)", info, optional_actions, termios); if (info == NULL || termios == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcsetattr(hostinfo->filefd, optional_actions, termios); } int HostfsTcflush(struct VfsInfo *info, int queue_selector) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcflush(%p, %d)", info, queue_selector); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcflush(hostinfo->filefd, queue_selector); } int HostfsTcdrain(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcdrain(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcdrain(hostinfo->filefd); } int HostfsTcsendbreak(struct VfsInfo *info, int duration) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcsendbreak(%p, %d)", info, duration); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcsendbreak(hostinfo->filefd, duration); } int HostfsTcflow(struct VfsInfo *info, int action) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcflow(%p, %d)", info, action); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcflow(hostinfo->filefd, action); } pid_t HostfsTcgetsid(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcgetsid(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcgetsid(hostinfo->filefd); } pid_t HostfsTcgetpgrp(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcgetpgrp(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcgetpgrp(hostinfo->filefd); } int HostfsTcsetpgrp(struct VfsInfo *info, pid_t pgrp) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsTcsetpgrp(%p, %d)", info, pgrp); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return tcsetpgrp(hostinfo->filefd, pgrp); } #ifdef HAVE_SOCKATMARK int HostfsSockatmark(struct VfsInfo *info) { struct HostfsInfo *hostinfo; VFS_LOGF("HostfsSockatmark(%p)", info); if (info == NULL) { return efault(); } hostinfo = (struct HostfsInfo *)info->data; return sockatmark(hostinfo->filefd); } #endif int HostfsPipe(struct VfsInfo *infos[2]) { int i; int fds[2]; VFS_LOGF("HostfsPipe(%p)", infos); if (infos == NULL) { return efault(); } fds[0] = fds[1] = -1; infos[0] = infos[1] = NULL; if (pipe(fds) == -1) { return -1; } for (i = 0; i < 2; ++i) { if (HostfsWrapFd(fds[i], false, &infos[i]) == -1) { goto cleananddie; } } return 0; cleananddie: for (i = 0; i < 2; ++i) { if (infos[i] != NULL) { unassert(!VfsFreeInfo(infos[i])); } else if (fds[i] != -1) { unassert(!close(fds[i])); } } return -1; } // TODO(trungnt): pipe2() should be polyfilled not partially disabled #ifdef HAVE_PIPE2 int HostfsPipe2(struct VfsInfo *infos[2], int flags) { int i; int fds[2]; VFS_LOGF("HostfsPipe2(%p, %d)", infos, flags); if (infos == NULL) { return efault(); } fds[0] = fds[1] = -1; infos[0] = infos[1] = NULL; if (pipe2(fds, flags) == -1) { return -1; } for (i = 0; i < 2; ++i) { if (HostfsWrapFd(fds[i], false, &infos[i]) == -1) { goto cleananddie; } } return 0; cleananddie: for (i = 0; i < 2; ++i) { if (infos[i] != NULL) { unassert(!VfsFreeInfo(infos[i])); } else if (fds[i] != -1) { unassert(!close(fds[i])); } } return -1; } #endif int HostfsSocket(int domain, int type, int protocol, struct VfsInfo **output) { int fd; VFS_LOGF("HostfsSocket(%d, %d, %d, %p)", domain, type, protocol, output); if (output == NULL) { return efault(); } fd = -1; *output = NULL; fd = socket(domain, type, protocol); if (fd == -1) { goto cleananddie; } if (HostfsWrapFd(fd, false, output) == -1) { goto cleananddie; } ((struct HostfsInfo *)(*output)->data)->socketfamily = domain; return 0; cleananddie: if (*output != NULL) { unassert(!VfsFreeInfo(*output)); } else if (fd != -1) { unassert(!close(fd)); } return -1; } int HostfsSocketpair(int domain, int type, int protocol, struct VfsInfo *infos[2]) { int i; int fds[2]; VFS_LOGF("HostfsSocketpair(%d, %d, %d, %p)", domain, type, protocol, infos); if (infos == NULL) { return efault(); } fds[0] = fds[1] = -1; infos[0] = infos[1] = NULL; if (socketpair(domain, type, protocol, fds) == -1) { return -1; } for (i = 0; i < 2; ++i) { if (HostfsWrapFd(fds[i], false, &infos[i]) == -1) { goto cleananddie; } ((struct HostfsInfo *)infos[i]->data)->socketfamily = domain; } return 0; cleananddie: for (i = 0; i < 2; ++i) { if (infos[i] != NULL) { unassert(!VfsFreeInfo(infos[i])); } else if (fds[i] != -1) { unassert(!close(fds[i])); } } return -1; } int HostfsFexecve(struct VfsInfo *info, char *const *argv, char *const *envp) { #ifndef HAVE_FEXECVE char path[VFS_PATH_MAX]; #endif VFS_LOGF("HostfsFexecve(%p, %p, %p)", info, argv, envp); #ifdef HAVE_FEXECVE if (info == NULL) { return efault(); } struct HostfsInfo *hostinfo; hostinfo = (struct HostfsInfo *)info->data; return fexecve(hostinfo->filefd, argv, envp); #else if (HostfsGetHostPath(info, path) == -1) { return -1; } return execve(path, argv, envp); #endif } struct VfsDevice g_anondevice = { .mounts = NULL, .ops = &g_hostfs.ops, .data = NULL, .dev = -1u, .refcount = 1u, }; int HostfsWrapFd(int fd, bool dodup, struct VfsInfo **output) { struct stat st; struct HostfsInfo *hostinfo; VFS_LOGF("HostfsWrapFd(%d, %p)", fd, output); if (output == NULL) { return efault(); } hostinfo = NULL; *output = NULL; if (dodup) { fd = dup(fd); if (fd == -1) { return -1; } } if (fstat(fd, &st) == -1) { goto cleananddie; } if (HostfsCreateInfo(&hostinfo) == -1) { goto cleananddie; } hostinfo->filefd = fd; hostinfo->mode = st.st_mode; if (VfsCreateInfo(output) == -1) { goto cleananddie; } (*output)->data = hostinfo; (*output)->parent = NULL; (*output)->dev = -1; (*output)->ino = HostfsHash(st.st_dev, (const char *)&st.st_ino, sizeof(st.st_ino)); (*output)->mode = st.st_mode; (*output)->refcount = 1; unassert(!VfsAcquireDevice(&g_anondevice, &(*output)->device)); return 0; cleananddie: if (*output != NULL) { unassert(!VfsFreeInfo(*output)); } else if (hostinfo != NULL) { unassert(!HostfsFreeInfo(hostinfo)); } else if (dodup && fd != -1) { unassert(!close(fd)); } return -1; } struct VfsSystem g_hostfs = {.name = "hostfs", .nodev = true, .ops = { .Init = HostfsInit, .Freeinfo = HostfsFreeInfo, .Freedevice = HostfsFreeDevice, .Readmountentry = HostfsReadmountentry, .Finddir = HostfsFinddir, .Traverse = HostfsTraverse, .Readlink = HostfsReadlink, .Mkdir = HostfsMkdir, .Mkfifo = HostfsMkfifo, .Open = HostfsOpen, .Access = HostfsAccess, .Stat = HostfsStat, .Fstat = HostfsFstat, .Chmod = HostfsChmod, .Fchmod = HostfsFchmod, .Chown = HostfsChown, .Fchown = HostfsFchown, .Ftruncate = HostfsFtruncate, .Close = HostfsClose, .Link = HostfsLink, .Unlink = HostfsUnlink, .Read = HostfsRead, .Write = HostfsWrite, .Pread = HostfsPread, .Pwrite = HostfsPwrite, .Readv = HostfsReadv, .Writev = HostfsWritev, .Preadv = HostfsPreadv, .Pwritev = HostfsPwritev, .Seek = HostfsSeek, .Fsync = HostfsFsync, .Fdatasync = HostfsFdatasync, .Flock = HostfsFlock, .Fcntl = HostfsFcntl, .Ioctl = HostfsIoctl, .Dup = HostfsDup, #ifdef HAVE_DUP3 .Dup3 = HostfsDup3, #endif .Poll = HostfsPoll, .Opendir = HostfsOpendir, #ifdef HAVE_SEEKDIR .Seekdir = HostfsSeekdir, .Telldir = HostfsTelldir, #endif .Readdir = HostfsReaddir, .Rewinddir = HostfsRewinddir, .Closedir = HostfsClosedir, .Bind = HostfsBind, .Connect = HostfsConnect, .Connectunix = HostfsConnectUnix, .Accept = HostfsAccept, .Listen = HostfsListen, .Shutdown = HostfsShutdown, .Recvmsg = HostfsRecvmsg, .Sendmsg = HostfsSendmsg, .Recvmsgunix = HostfsRecvmsgUnix, .Sendmsgunix = HostfsSendmsgUnix, .Getsockopt = HostfsGetsockopt, .Setsockopt = HostfsSetsockopt, .Getsockname = HostfsGetsockname, .Getpeername = HostfsGetpeername, .Rename = HostfsRename, .Utime = HostfsUtime, .Futime = HostfsFutime, .Symlink = HostfsSymlink, .Mmap = HostfsMmap, .Munmap = HostfsMunmap, .Mprotect = HostfsMprotect, .Msync = HostfsMsync, .Pipe = HostfsPipe, #ifdef HAVE_PIPE2 .Pipe2 = HostfsPipe2, #endif .Socket = HostfsSocket, .Socketpair = HostfsSocketpair, .Tcgetattr = HostfsTcgetattr, .Tcsetattr = HostfsTcsetattr, .Tcflush = HostfsTcflush, .Tcdrain = HostfsTcdrain, .Tcsendbreak = HostfsTcsendbreak, .Tcflow = HostfsTcflow, .Tcgetsid = HostfsTcgetsid, .Tcgetpgrp = HostfsTcgetpgrp, .Tcsetpgrp = HostfsTcsetpgrp, #ifdef HAVE_SOCKATMARK .Sockatmark = HostfsSockatmark, #endif .Fexecve = HostfsFexecve, }}; #endif /* DISABLE_VFS */ ================================================ FILE: blink/hostfs.h ================================================ #ifndef BLINK_HOSTFS_H_ #define BLINK_HOSTFS_H_ #include #include #include "blink/vfs.h" struct HostfsInfo { int mode; int filefd; int socketfamily; union { DIR *dirstream; struct sockaddr *socketaddr; }; socklen_t socketaddrlen; struct sockaddr *socketpeeraddr; socklen_t socketpeeraddrlen; }; int HostfsInit(const char *, u64, const void *, struct VfsDevice **, struct VfsMount **); int HostfsCreateInfo(struct HostfsInfo **); int HostfsFreeInfo(void *); int HostfsFreeDevice(void *); int HostfsFinddir(struct VfsInfo *, const char *, struct VfsInfo **); int HostfsTraverse(struct VfsInfo **dir, const char **path, struct VfsInfo *root); ssize_t HostfsReadlink(struct VfsInfo *, char **); int HostfsMkdir(struct VfsInfo *, const char *, mode_t); int HostfsMkfifo(struct VfsInfo *, const char *, mode_t); int HostfsOpen(struct VfsInfo *, const char *, int, int, struct VfsInfo **); int HostfsAccess(struct VfsInfo *, const char *, mode_t, int); int HostfsStat(struct VfsInfo *, const char *, struct stat *, int); int HostfsFstat(struct VfsInfo *, struct stat *); int HostfsChmod(struct VfsInfo *, const char *, mode_t, int); int HostfsFchmod(struct VfsInfo *, mode_t); int HostfsChown(struct VfsInfo *, const char *, uid_t, gid_t, int); int HostfsFchown(struct VfsInfo *, uid_t, gid_t); int HostfsFtruncate(struct VfsInfo *, off_t); int HostfsClose(struct VfsInfo *); int HostfsLink(struct VfsInfo *, const char *, struct VfsInfo *, const char *, int); int HostfsUnlink(struct VfsInfo *, const char *, int); ssize_t HostfsRead(struct VfsInfo *, void *, size_t); ssize_t HostfsWrite(struct VfsInfo *, const void *, size_t); ssize_t HostfsPread(struct VfsInfo *, void *, size_t, off_t); ssize_t HostfsPwrite(struct VfsInfo *, const void *, size_t, off_t); ssize_t HostfsReadv(struct VfsInfo *, const struct iovec *, int); ssize_t HostfsWritev(struct VfsInfo *, const struct iovec *, int); ssize_t HostfsPreadv(struct VfsInfo *, const struct iovec *, int, off_t); ssize_t HostfsPwritev(struct VfsInfo *, const struct iovec *, int, off_t); off_t HostfsSeek(struct VfsInfo *, off_t, int); int HostfsFsync(struct VfsInfo *); int HostfsFdatasync(struct VfsInfo *); int HostfsFlock(struct VfsInfo *, int); int HostfsFcntl(struct VfsInfo *, int, va_list); int HostfsIoctl(struct VfsInfo *, unsigned long, const void *); int HostfsDup(struct VfsInfo *, struct VfsInfo **); #ifdef HAVE_DUP3 int HostfsDup3(struct VfsInfo *, struct VfsInfo **, int); #endif int HostfsPoll(struct VfsInfo **, struct pollfd *, nfds_t, int); int HostfsOpendir(struct VfsInfo *, struct VfsInfo **); #ifdef HAVE_SEEKDIR void HostfsSeekdir(struct VfsInfo *, long); long HostfsTelldir(struct VfsInfo *); #endif struct dirent *HostfsReaddir(struct VfsInfo *); void HostfsRewinddir(struct VfsInfo *); int HostfsClosedir(struct VfsInfo *); int HostfsBind(struct VfsInfo *, const struct sockaddr *, socklen_t); int HostfsConnect(struct VfsInfo *, const struct sockaddr *, socklen_t); int HostfsConnectUnix(struct VfsInfo *, struct VfsInfo *, const struct sockaddr_un *, socklen_t); int HostfsAccept(struct VfsInfo *, struct sockaddr *, socklen_t *, struct VfsInfo **); int HostfsListen(struct VfsInfo *, int); int HostfsShutdown(struct VfsInfo *, int); ssize_t HostfsRecvmsg(struct VfsInfo *, struct msghdr *, int); ssize_t HostfsSendmsg(struct VfsInfo *, const struct msghdr *, int); ssize_t HostfsRecvmsgUnix(struct VfsInfo *, struct VfsInfo *, struct msghdr *, int); ssize_t HostfsSendmsgUnix(struct VfsInfo *, struct VfsInfo *, const struct msghdr *, int); int HostfsGetsockopt(struct VfsInfo *, int, int, void *, socklen_t *); int HostfsSetsockopt(struct VfsInfo *, int, int, const void *, socklen_t); int HostfsGetsockname(struct VfsInfo *, struct sockaddr *, socklen_t *); int HostfsGetpeername(struct VfsInfo *, struct sockaddr *, socklen_t *); int HostfsRename(struct VfsInfo *, const char *, struct VfsInfo *, const char *); int HostfsUtime(struct VfsInfo *, const char *, const struct timespec[2], int); int HostfsFutime(struct VfsInfo *, const struct timespec[2]); int HostfsSymlink(const char *, struct VfsInfo *, const char *); void *HostfsMmap(struct VfsInfo *, void *, size_t, int, int, off_t); int HostfsMunmap(struct VfsInfo *, void *, size_t); int HostfsMprotect(struct VfsInfo *, void *, size_t, int); int HostfsMsync(struct VfsInfo *, void *, size_t, int); int HostfsPipe(struct VfsInfo *[2]); int HostfsPipe2(struct VfsInfo *[2], int); int HostfsSocket(int, int, int, struct VfsInfo **); int HostfsSocketpair(int, int, int, struct VfsInfo *[2]); int HostfsTcgetattr(struct VfsInfo *, struct termios *); int HostfsTcsetattr(struct VfsInfo *, int, const struct termios *); int HostfsTcflush(struct VfsInfo *, int); int HostfsTcdrain(struct VfsInfo *); int HostfsTcsendbreak(struct VfsInfo *, int); int HostfsTcflow(struct VfsInfo *, int); pid_t HostfsTcgetsid(struct VfsInfo *); pid_t HostfsTcgetpgrp(struct VfsInfo *); int HostfsTcsetpgrp(struct VfsInfo *, pid_t); #ifdef HAVE_SOCKATMARK int HostfsSockatmark(struct VfsInfo *); #endif int HostfsFexecve(struct VfsInfo *, char *const *, char *const *); int HostfsWrapFd(int fd, bool dodup, struct VfsInfo **output); extern struct VfsSystem g_hostfs; #endif // BLINK_HOSTFS_H_ ================================================ FILE: blink/instruction.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/assert.h" #include "blink/bitscan.h" #include "blink/endian.h" #include "blink/linux.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/stats.h" #include "blink/x86.h" static bool IsOpcodeEqual(struct XedDecodedInst *xedd, u8 *a) { int n; u64 w; if ((n = xedd->length)) { unassert(n <= 15); if (n <= 7) { w = Read64(a) ^ Read64(xedd->bytes); return !w || (bsf(w) >> 3) >= n; } else { return !memcmp(a, xedd->bytes, n); } } else { return false; } } static int ReadInstruction(struct Machine *m, u8 *p, unsigned n) { struct XedDecodedInst xedd[1]; STATISTIC(++instructions_decoded); if (!DecodeInstruction(xedd, p, n, m->mode.omode)) { memcpy(m->xedd, xedd, kInstructionBytes); return 0; } else { return kMachineDecodeError; } } static int LoadInstructionSlow(struct Machine *m, u64 ip) { u8 *addr; unsigned i; u8 copy[15], *toil; i = 4096 - (ip & 4095); STATISTIC(++page_overlaps); if ((addr = LookupAddress2(m, ip, PAGE_XD, 0))) { if ((toil = LookupAddress2(m, ip + i, PAGE_XD, 0))) { memcpy(copy, addr, i); memcpy(copy + i, toil, 15 - i); return ReadInstruction(m, copy, 15); } else { return ReadInstruction(m, addr, i); } } else { return kMachineSegmentationFault; } } int LoadInstruction2(struct Machine *m, u64 pc) { unsigned key; u8 *addr, *page; if (atomic_load_explicit(&m->opcache->invalidated, memory_order_acquire)) { ResetInstructionCache(m); atomic_store_explicit(&m->opcache->invalidated, false, memory_order_relaxed); } key = pc & (ARRAYLEN(m->opcache->icache) - 1); m->xedd = (struct XedDecodedInst *)m->opcache->icache[key]; if ((pc & 4095) + 15 <= 4096) { if (pc - (pc & 4095) == m->opcache->codevirt && m->opcache->codehost) { addr = m->opcache->codehost + (pc & 4095); } else if ((page = LookupAddress2(m, pc - (pc & 4095), PAGE_XD, 0))) { m->opcache->codevirt = pc - (pc & 4095); m->opcache->codehost = page; addr = page + (pc & 4095); } else { return kMachineSegmentationFault; } if (IsOpcodeEqual(m->xedd, addr)) { STATISTIC(++instructions_cached); return 0; } else { return ReadInstruction(m, addr, 15); } } else { return LoadInstructionSlow(m, pc); } } void LoadInstruction(struct Machine *m, u64 pc) { int rc; switch ((rc = LoadInstruction2(m, pc))) { case 0: break; case kMachineSegmentationFault: m->faultaddr = pc; HaltMachine(m, rc); case kMachineDecodeError: HaltMachine(m, rc); default: HaltMachine(m, rc); } } ================================================ FILE: blink/intrin.h ================================================ #ifndef BLINK_INTRIN_H_ #define BLINK_INTRIN_H_ #if defined(__x86_64__) && defined(__GNUC__) && __GNUC__ >= 6 #define X86_INTRINSICS 1 typedef char char_xmmu_t __attribute__((__vector_size__(16), __may_alias__)); typedef char char_xmma_t __attribute__((__vector_size__(16), __aligned__(16), __may_alias__)); #else #define X86_INTRINSICS 0 #endif #if defined(__aarch64__) && defined(__GNUC__) #define ARM_INTRINSICS 1 #else #define ARM_INTRINSICS 0 #endif #endif /* BLINK_INTRIN_H_ */ ================================================ FILE: blink/ioctl.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/fds.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/ndelay.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/types.h" #include "blink/vfs.h" #include "blink/xlat.h" #ifdef __HAIKU__ #include #include #endif static int IoctlTiocgwinsz(struct Machine *m, int fd, i64 addr, int fn(int, struct winsize *)) { int rc; struct winsize ws; struct winsize_linux gws; if ((rc = fn(fd, &ws)) != -1) { XlatWinsizeToLinux(&gws, &ws); if (CopyToUserWrite(m, addr, &gws, sizeof(gws)) == -1) rc = -1; } return rc; } static int IoctlTiocswinsz(struct Machine *m, int fd, i64 addr, int fn(int, const struct winsize *)) { struct winsize ws; struct winsize_linux gws; if (CopyFromUserRead(m, &gws, addr, sizeof(gws)) == -1) return -1; XlatWinsizeToHost(&ws, &gws); return fn(fd, &ws); } static int IoctlTcgets(struct Machine *m, int fd, i64 addr, int fn(int, struct termios *)) { int rc; struct termios tio; struct termios_linux gtio; if ((rc = fn(fd, &tio)) != -1) { XlatTermiosToLinux(>io, &tio); if (CopyToUserWrite(m, addr, >io, sizeof(gtio)) == -1) rc = -1; } return rc; } static int IoctlTcsets(struct Machine *m, int fd, int request, i64 addr, int fn(int, int, const struct termios *)) { struct termios tio; struct termios_linux gtio; if (CopyFromUserRead(m, >io, addr, sizeof(gtio)) == -1) return -1; XlatLinuxToTermios(&tio, >io); return fn(fd, request, &tio); } static int IoctlTiocgpgrp(struct Machine *m, int fd, i64 addr) { int rc; u8 *pgrp; #ifdef __EMSCRIPTEN__ // Force shells to disable job control in emscripten errno = ENOTTY; return -1; #endif if (!(pgrp = (u8 *)SchlepW(m, addr, 4))) return -1; if ((rc = VfsTcgetpgrp(fd)) == -1) return -1; Write32(pgrp, rc); return 0; } static int IoctlTiocspgrp(struct Machine *m, int fd, i64 addr) { u8 *pgrp; if (!(pgrp = (u8 *)SchlepR(m, addr, 4))) return -1; return VfsTcsetpgrp(fd, Read32(pgrp)); } #ifdef HAVE_SIOCGIFCONF static int IoctlSiocgifconf(struct Machine *m, int systemfd, i64 ifconf_addr) { size_t i; char *buf; size_t len; size_t bufsize; char *buf_linux; size_t len_linux; struct ifreq *ifreq; struct ifconf ifconf; struct ifreq_linux ifreq_linux; struct ifconf_linux ifconf_linux; const struct ifconf_linux *ifconf_linuxp; memset(&ifreq_linux, 0, sizeof(ifreq_linux)); if (!(ifconf_linuxp = (const struct ifconf_linux *)SchlepRW( m, ifconf_addr, sizeof(*ifconf_linuxp))) || !IsValidMemory(m, Read64(ifconf_linuxp->buf), Read32(ifconf_linuxp->len), PROT_WRITE)) { return efault(); } bufsize = MIN(16384, Read32(ifconf_linuxp->len)); if (!(buf = (char *)AddToFreeList(m, malloc(bufsize)))) return -1; if (!(buf_linux = (char *)AddToFreeList(m, malloc(bufsize)))) return -1; ifconf.ifc_len = bufsize; ifconf.ifc_buf = buf; if (VfsIoctl(systemfd, SIOCGIFCONF, &ifconf)) return -1; len_linux = 0; ifreq = ifconf.ifc_req; for (i = 0; i < ifconf.ifc_len;) { if (len_linux + sizeof(ifreq_linux) > bufsize) break; #ifdef HAVE_SA_LEN len = IFNAMSIZ + ifreq->ifr_addr.sa_len; #else len = sizeof(*ifreq); #endif if (ifreq->ifr_addr.sa_family == AF_INET) { memset(ifreq_linux.name, 0, sizeof(ifreq_linux.name)); memcpy(ifreq_linux.name, ifreq->ifr_name, MIN(sizeof(ifreq_linux.name) - 1, sizeof(ifreq->ifr_name))); unassert(XlatSockaddrToLinux( (struct sockaddr_storage_linux *)&ifreq_linux.addr, (const struct sockaddr *)&ifreq->ifr_addr, sizeof(ifreq->ifr_addr)) == sizeof(struct sockaddr_in_linux)); memcpy(buf_linux + len_linux, &ifreq_linux, sizeof(ifreq_linux)); len_linux += sizeof(ifreq_linux); } ifreq = (struct ifreq *)((char *)ifreq + len); i += len; } Write32(ifconf_linux.len, len_linux); Write32(ifconf_linux.pad, 0); Write64(ifconf_linux.buf, Read64(ifconf_linuxp->buf)); CopyToUserWrite(m, Read64(ifconf_linux.buf), buf_linux, len_linux); CopyToUserWrite(m, ifconf_addr, &ifconf_linux, sizeof(ifconf_linux)); return 0; } static int IoctlSiocgifaddr(struct Machine *m, int systemfd, i64 ifreq_addr, unsigned long kind) { struct ifreq ifreq; struct ifreq_linux ifreq_linux; if (!IsValidMemory(m, ifreq_addr, sizeof(ifreq_linux), PROT_READ | PROT_WRITE)) { return efault(); } CopyFromUserRead(m, &ifreq_linux, ifreq_addr, sizeof(ifreq_linux)); memset(ifreq.ifr_name, 0, sizeof(ifreq.ifr_name)); memcpy(ifreq.ifr_name, ifreq_linux.name, MIN(sizeof(ifreq_linux.name) - 1, sizeof(ifreq.ifr_name))); if (Read16(ifreq_linux.addr.family) != AF_INET_LINUX) return einval(); unassert(XlatSockaddrToHost((struct sockaddr_storage *)&ifreq.ifr_addr, (const struct sockaddr_linux *)&ifreq_linux.addr, sizeof(struct sockaddr_in_linux)) == sizeof(struct sockaddr_in)); if (VfsIoctl(systemfd, kind, &ifreq)) return -1; memset(ifreq_linux.name, 0, sizeof(ifreq_linux.name)); memcpy(ifreq_linux.name, ifreq.ifr_name, MIN(sizeof(ifreq_linux.name) - 1, sizeof(ifreq.ifr_name))); unassert(XlatSockaddrToLinux( (struct sockaddr_storage_linux *)&ifreq_linux.addr, (struct sockaddr *)&ifreq.ifr_addr, sizeof(ifreq.ifr_addr)) == sizeof(struct sockaddr_in_linux)); CopyToUserWrite(m, ifreq_addr, &ifreq_linux, sizeof(ifreq_linux)); return 0; } #endif /* HAVE_SIOCGIFCONF */ static int IoctlFionbio(struct Machine *m, int fildes) { int oflags; if ((oflags = GetOflags(m, fildes)) == -1) return -1; return VfsFcntl(fildes, F_SETFL, (oflags & SETFL_FLAGS) | O_NDELAY); } static int IoctlFioclex(struct Machine *m, int fildes) { return VfsFcntl(fildes, F_SETFD, FD_CLOEXEC); } static int IoctlFionclex(struct Machine *m, int fildes) { return VfsFcntl(fildes, F_SETFD, 0); } static int IoctlTcsbrk(struct Machine *m, int fildes, int drain) { int rc; if (drain) { RESTARTABLE(rc = VfsTcdrain(fildes)); } else { rc = VfsTcsendbreak(fildes, 0); } return rc; } static int IoctlTcxonc(struct Machine *m, int fildes, int arg) { return VfsTcflow(fildes, arg); } static int IoctlTiocgsid(struct Machine *m, int fildes, i64 addr) { int rc; u8 *sid; if (!(sid = (u8 *)SchlepW(m, addr, 4))) return -1; if ((rc = VfsTcgetsid(fildes)) != -1) { Write32(sid, rc); rc = 0; } return rc; } static int XlatFlushQueue(int queue) { switch (queue) { case TCIFLUSH_LINUX: return TCIFLUSH; case TCOFLUSH_LINUX: return TCOFLUSH; case TCIOFLUSH_LINUX: return TCIOFLUSH; default: return einval(); } } static int IoctlTcflsh(struct Machine *m, int fildes, int queue) { if ((queue = XlatFlushQueue(queue)) == -1) return -1; return VfsTcflush(fildes, queue); } #ifdef HAVE_SOCKATMARK static int IoctlSiocatmark(struct Machine *m, int fildes, i64 addr) { u8 *p; int rc; if (!(p = (u8 *)SchlepW(m, addr, 4))) return -1; if ((rc = VfsSockatmark(fildes)) != -1) { Write32(p, rc); rc = 0; } return rc; } #endif static int IoctlGetInt32(struct Machine *m, int fildes, unsigned long cmd, i64 addr) { u8 *p; int rc, val; if (!(p = (u8 *)SchlepW(m, addr, 4))) return -1; if ((rc = VfsIoctl(fildes, cmd, &val)) != -1) { Write32(p, val); } return rc; } static int IoctlSetInt32(struct Machine *m, int fildes, unsigned long cmd, i64 addr) { int val; const u8 *p; if (!(p = (const u8 *)SchlepR(m, addr, 4))) return -1; val = Read32(p); return VfsIoctl(fildes, cmd, &val); } #ifdef TIOCSTI static int IoctlTiocsti(struct Machine *m, int fildes, i64 addr) { const u8 *bytep; if (!(bytep = LookupAddress(m, addr))) return efault(); return VfsIoctl(fildes, TIOCSTI, (void *)bytep); } #endif int SysIoctl(struct Machine *m, int fildes, u64 request, i64 addr) { struct Fd *fd; int (*tcgetattr_impl)(int, struct termios *); int (*tcsetattr_impl)(int, int, const struct termios *); int (*tcgetwinsize_impl)(int, struct winsize *); int (*tcsetwinsize_impl)(int, const struct winsize *); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { unassert(fd->cb); unassert(tcgetattr_impl = fd->cb->tcgetattr); unassert(tcsetattr_impl = fd->cb->tcsetattr); unassert(tcgetwinsize_impl = fd->cb->tcgetwinsize); unassert(tcsetwinsize_impl = fd->cb->tcsetwinsize); } else { tcsetattr_impl = 0; tcgetattr_impl = 0; tcgetwinsize_impl = 0; tcsetwinsize_impl = 0; } UNLOCK(&m->system->fds.lock); if (!fd) return -1; switch (request) { case TIOCGWINSZ_LINUX: return IoctlTiocgwinsz(m, fildes, addr, tcgetwinsize_impl); case TIOCSWINSZ_LINUX: return IoctlTiocswinsz(m, fildes, addr, tcsetwinsize_impl); case TCGETS_LINUX: return IoctlTcgets(m, fildes, addr, tcgetattr_impl); case TCSETS_LINUX: return IoctlTcsets(m, fildes, TCSANOW, addr, tcsetattr_impl); case TCSETSW_LINUX: return IoctlTcsets(m, fildes, TCSADRAIN, addr, tcsetattr_impl); case TCSETSF_LINUX: return IoctlTcsets(m, fildes, TCSAFLUSH, addr, tcsetattr_impl); case TIOCGPGRP_LINUX: return IoctlTiocgpgrp(m, fildes, addr); case TIOCSPGRP_LINUX: return IoctlTiocspgrp(m, fildes, addr); #ifndef DISABLE_NONPOSIX case FIONBIO_LINUX: return IoctlFionbio(m, fildes); case FIOCLEX_LINUX: return IoctlFioclex(m, fildes); case FIONCLEX_LINUX: return IoctlFionclex(m, fildes); #endif case TCSBRK_LINUX: return IoctlTcsbrk(m, fildes, addr); case TCXONC_LINUX: return IoctlTcxonc(m, fildes, addr); case TIOCGSID_LINUX: return IoctlTiocgsid(m, fildes, addr); case TCFLSH_LINUX: return IoctlTcflsh(m, fildes, addr); #ifdef HAVE_SOCKATMARK #ifndef DISABLE_SOCKETS case SIOCATMARK_LINUX: return IoctlSiocatmark(m, fildes, addr); #endif #endif #ifdef FIONREAD case FIONREAD_LINUX: return IoctlGetInt32(m, fildes, FIONREAD, addr); #endif #ifdef TIOCOUTQ case TIOCOUTQ_LINUX: return IoctlGetInt32(m, fildes, TIOCOUTQ, addr); #endif #ifdef TIOCSTI case TIOCSTI_LINUX: return IoctlTiocsti(m, fildes, addr); #endif #ifdef FIOGETOWN case FIOGETOWN_LINUX: return IoctlGetInt32(m, fildes, FIOGETOWN, addr); #endif #ifdef FIOSETOWN case FIOSETOWN_LINUX: return IoctlSetInt32(m, fildes, FIOSETOWN, addr); #endif #ifdef SIOCSPGRP case SIOCSPGRP_LINUX: return IoctlSetInt32(m, fildes, SIOCSPGRP, addr); #endif #ifdef SIOCGPGRP case SIOCGPGRP_LINUX: return IoctlGetInt32(m, fildes, SIOCGPGRP, addr); #endif #ifdef HAVE_SIOCGIFCONF #ifndef DISABLE_SOCKETS #ifndef DISABLE_NONPOSIX case SIOCGIFCONF_LINUX: return IoctlSiocgifconf(m, fildes, addr); case SIOCGIFADDR_LINUX: return IoctlSiocgifaddr(m, fildes, addr, SIOCGIFADDR); case SIOCGIFNETMASK_LINUX: return IoctlSiocgifaddr(m, fildes, addr, SIOCGIFNETMASK); case SIOCGIFBRDADDR_LINUX: return IoctlSiocgifaddr(m, fildes, addr, SIOCGIFBRDADDR); case SIOCGIFDSTADDR_LINUX: return IoctlSiocgifaddr(m, fildes, addr, SIOCGIFDSTADDR); #endif /* DISABLE_NONPOSIX */ #endif /* DISABLE_SOCKETS */ #endif /* HAVE_SIOCGIFCONF */ default: LOGF("missing ioctl %#" PRIx64, request); return einval(); } } ================================================ FILE: blink/ioports.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/debug.h" #include "blink/machine.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/uart.h" #ifndef DISABLE_METAL static int OpE9Read(struct Machine *m) { u8 b; struct Fd *fd; int fildes = 0; struct iovec t = {&b, 1}; ssize_t (*readv_impl)(int, const struct iovec *, int); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { readv_impl = fd->cb->readv; } else { readv_impl = 0; } UNLOCK(&m->system->fds.lock); if (readv_impl && readv_impl(fildes, &t, 1) == 1) { return b; } else { return -1; } } static int OpE9Write(struct Machine *m, u8 b) { struct Fd *fd; int fildes = 1; struct iovec t = {&b, 1}; ssize_t (*writev_impl)(int, const struct iovec *, int); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { writev_impl = fd->cb->writev; } else { writev_impl = 0; } UNLOCK(&m->system->fds.lock); if (!writev_impl) return -1; return writev_impl(fildes, &t, 1); } static int OpE9Poll(struct Machine *m) { int rc; struct Fd *fd; int fildes = 0; struct pollfd pf; int (*poll_impl)(struct pollfd *, nfds_t, int); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { poll_impl = fd->cb->poll; } else { poll_impl = 0; } UNLOCK(&m->system->fds.lock); if (!poll_impl) return -1; pf.fd = fildes; pf.events = POLLIN | POLLOUT; rc = poll_impl(&pf, 1, 20); if (rc > 0) rc = pf.revents; return rc; } static int OpSerialIn(struct Machine *m, int r) { int p, s; switch (r) { case UART_DLL: if (!m->system->dlab) { return OpE9Read(m); } else { return 1; } case UART_LSR: if ((p = OpE9Poll(m)) == -1) return -1; s = UART_TTYIDL; if (p & POLLIN) s |= UART_TTYDA; if (p & POLLOUT) s |= UART_TTYTXR; return s; case UART_DLM: return -1; default: return 0; } } static int OpSerialOut(struct Machine *m, int r, u32 x) { switch (r) { case UART_DLL: if (!m->system->dlab) { return OpE9Write(m, x); } return 0; case UART_LCR: m->system->dlab = !!(x & UART_DLAB); return 0; default: return -1; } } u64 OpIn(struct Machine *m, u16 p) { switch (p) { case 0xE9: return OpE9Read(m); case 0x3F8: case 0x3F9: case 0x3FA: case 0x3FB: case 0x3FC: case 0x3FD: case 0x3FE: case 0x3FF: return OpSerialIn(m, p - 0x3F8); default: return -1; } } int OpOut(struct Machine *m, u16 p, u32 x) { switch (p) { case 0xE9: return OpE9Write(m, x); case 0x3F8: case 0x3F9: case 0x3FA: case 0x3FB: case 0x3FC: case 0x3FD: case 0x3FE: case 0x3FF: return OpSerialOut(m, p - 0x3F8, x); default: return -1; } } #endif /* DISABLE_METAL */ ================================================ FILE: blink/iovs.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/iovs.h" #include #include #include #include #include "blink/endian.h" #include "blink/errno.h" #include "blink/limits.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/stats.h" #include "blink/types.h" #include "blink/util.h" void InitIovs(struct Iovs *ib) { ib->p = ib->init; ib->i = 0; ib->n = ARRAYLEN(ib->init); } void FreeIovs(struct Iovs *ib) { if (ib->p != ib->init) { free(ib->p); } } /** * Appends memory region to i/o vector builder. */ static int AppendIovs(struct Iovs *ib, void *base, size_t len) { unsigned i, n; struct iovec *p; if (len) { p = ib->p; i = ib->i; n = ib->n; if (i && (uintptr_t)base == (uintptr_t)p[i - 1].iov_base + p[i - 1].iov_len) { STATISTIC(++iov_stretches); if (p[i - 1].iov_len + len > NUMERIC_MAX(ssize_t)) return einval(); p[i - 1].iov_len += len; } else { if (i < n) { if (!i) { STATISTIC(++iov_created); } else { STATISTIC(++iov_fragments); } } else { STATISTIC(++iov_reallocs); n += n >> 1; if (p == ib->init) { if (!(p = (struct iovec *)malloc(sizeof(*p) * n))) return -1; memcpy(p, ib->init, sizeof(ib->init)); } else { if (!(p = (struct iovec *)realloc(p, sizeof(*p) * n))) return -1; } ib->p = p; ib->n = n; } p[i].iov_base = base; p[i].iov_len = len; ++ib->i; } } return 0; } int AppendIovsReal(struct Machine *m, struct Iovs *ib, i64 addr, u64 size, int prot) { void *real; unsigned got; u64 have, mask, need; if (size > NUMERIC_MAX(ssize_t)) return einval(); need = 0; mask = 0; if (prot & PROT_READ) { mask |= PAGE_U; need |= PAGE_U; } if (prot & PROT_WRITE) { mask |= PAGE_RW; need |= PAGE_RW; } while (size && ib->i < GetIovMax()) { if (!(real = LookupAddress2(m, addr, mask, need))) return efault(); have = 4096 - (addr & 4095); got = MIN(size, have); if (AppendIovs(ib, real, got) == -1) return -1; addr += got; size -= got; } return 0; } int AppendIovsGuest(struct Machine *m, struct Iovs *iv, i64 iovaddr, int iovlen, int prot) { int rc; size_t i, iovsize; const struct iovec_linux *guestiovs; if (iovlen > IOV_MAX_LINUX) return einval(); iovsize = iovlen * sizeof(struct iovec_linux); if ((guestiovs = (const struct iovec_linux *)SchlepR(m, iovaddr, iovsize))) { for (rc = i = 0; i < iovlen && iv->i < GetIovMax(); ++i) { if (AppendIovsReal(m, iv, Read64(guestiovs[i].base), Read64(guestiovs[i].len), prot) == -1) { rc = -1; break; } } return rc; } else { return -1; } } ================================================ FILE: blink/iovs.h ================================================ #ifndef BLINK_IOVS_H_ #define BLINK_IOVS_H_ #include #include #include #include "blink/machine.h" #include "blink/types.h" struct Iovs { unsigned i, n; struct iovec *p; struct iovec init[8]; }; void FreeIovs(struct Iovs *); void InitIovs(struct Iovs *); int AppendIovsReal(struct Machine *, struct Iovs *, i64, u64, int); int AppendIovsGuest(struct Machine *, struct Iovs *, i64, int, int); #endif /* BLINK_IOVS_H_ */ ================================================ FILE: blink/jit.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/jit.h" #include #include #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/bitscan.h" #include "blink/builtin.h" #include "blink/checked.h" #include "blink/debug.h" #include "blink/dll.h" #include "blink/end.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/flag.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/memcpy.h" #include "blink/stats.h" #include "blink/thread.h" #include "blink/tsan.h" #include "blink/util.h" /** * @fileoverview Just-In-Time Function Builder * * This file implements a low-level systems abstraction that enables * native functions to be written to memory and then executed. These * interfaces are used by Jitter() which is a higher-level interface * that's intended for generating implementations of x86 operations. * * This JIT only supports x86-64 and aarch64. That makes life easier * since both architectures have many registers and a register-based * calling convention. This JIT works around the restrictions placed * upon self-modifying code imposed by both OSes and microprocessors * such as: * * 1. ARM CPUs require a non-trivial flushing of instruction caches. * 2. OpenBSD always imposes strict W^X memory protection invariant. * 3. Apple requires we use JIT memory and toggle thread JIT states. * 4. ISAs limit the distance between JIT memory and our executable. * 5. Some platforms have a weird page size, e.g. Apple M1 is 16384. * * Meeting the requirements of all these platforms, means we have to * follow a very narrow path of possibilities, in terms of practices * plus design. These APIs make conformance easier. The way it works * here is multiple pages of memory are allocated in chunks, that we * call "blocks". Each time a thread wishes to create a function, it * must lease one of these blocks using StartJit(), FinishJit(), and * SpliceJit(). During that lease, functions may be generated, which * call arbitrary functions built by the compiler. Any function made * here needs to have a non-JIT implementation that can be called to * allow time for the JIT block to be flushed, at which time the JIT * updates a corresponding function hook. * * // setup a multi-threaded jit manager * struct Jit jit; * InitJit(&jit, 0); * * // workflow for composing two function calls * i64 key = 1234; * long Adder(long x, long y) { return x + y; } * struct JitBlock *jb; * jb = StartJit(jit, key); * AppendJit(jb, kPrologue, sizeof(kPrologue)); * AppendJitSetReg(jb, kJitArg0, 1); * AppendJitSetReg(jb, kJitArg1, 2); * AppendJitCall(jb, (void *)Adder); * AppendJitMovReg(jb, kJitRes0, kJitArg0); * AppendJitSetReg(jb, kJitArg1, 3); * AppendJitCall(jb, (void *)Adder); * AppendJit(jb, kEpilogue, sizeof(kEpilogue)); * FinishJit(jit, jb); * FlushJit(jit); * printf("1+2+3=%ld\n", ((long (*)(void))(GetJitHook(jit, key)))()); * * // destroy jit and all its functions * DestroyJit(&jit); * * Note that FlushJit() should only be a last resort. Functions will * become live immediately on operating systems which authorize self * modifying-code using RWX memory and have the appropriate compiler * builtin for flushing the CPU instruction cach. If weird platforms * aren't a concern, then the hairiness of hooking and/or FlushJit() * shouldn't be of any concern. Try using CanJitForImmediateEffect() * after having called StartJit() to check. */ #define kMaximumAnticipatedPageSize 65536 const u8 kJitRes[2] = {kJitRes0, kJitRes1}; const u8 kJitArg[4] = {kJitArg0, kJitArg1, kJitArg2, kJitArg3}; const u8 kJitSav[5] = {kJitSav0, kJitSav1, kJitSav2, kJitSav3, kJitSav4}; #ifdef HAVE_JIT #define ACTION_MOVE 0x010000 #define ACTION(a) ((0xff0000 & a)) #define MOVE(dst, src) ((dst) | (src) << 8 | ACTION_MOVE) #define MOVE_DST(a) ((0x0000ff & (a)) >> 0) #define MOVE_SRC(a) ((0x00ff00 & (a)) >> 8) #define HASH(virt) (virt) static u8 g_code[kJitMemorySize]; static struct JitGlobals { pthread_mutex_t_ lock; _Atomic(long) prot; int freecount; struct Dll *freeblocks; } g_jit = { PTHREAD_MUTEX_INITIALIZER_, PROT_READ | PROT_WRITE | PROT_EXEC, }; static inline u64 RoundupTwoPow(u64 x) { return x > 1 ? (u64)2 << bsr(x - 1) : x ? 1 : 0; } // begins write operation to memory that may be read locklessly // - generation is monotonic // - even numbers mean memory is ready // - odd numbers mean memory is actively being changed static inline unsigned BeginUpdate(_Atomic(unsigned) *genptr) { unsigned gen = atomic_load_explicit(genptr, memory_order_relaxed); unassert(~gen & 1); // prevents re-entering transaction atomic_store_explicit(genptr, gen + 1, memory_order_release); return gen; } // finishes write operation to memory that may be read locklessly static inline void EndUpdate(_Atomic(unsigned) *genptr, unsigned gen) { unassert(~gen & 1); atomic_store_explicit(genptr, gen + 2, memory_order_release); } // determines if lockless operation should be retried or abandoned static inline unsigned ShallNotPass(unsigned gen1, _Atomic(unsigned) *genptr) { unsigned gen2 = atomic_load_explicit(genptr, memory_order_acquire); unsigned is_being_actively_changed = gen1 & 1; unsigned we_lost_race_with_writers = gen1 ^ gen2; return is_being_actively_changed | we_lost_race_with_writers; } // apple forbids rwx memory on their new m1 macbooks and requires that // we use a non-posix api in order to have jit. the problem is the api // frequently flakes with "Trace/BPT trap: 5" errors. this fixes that. static void pthread_jit_write_protect_np_workaround(int enabled) { #if defined(__APPLE__) && defined(__aarch64__) int count_start = 8192; volatile int count = count_start; uint64_t *addr, val, val2, reread = -1; addr = (uint64_t *)(!enabled ? _COMM_PAGE_APRR_WRITE_ENABLE : _COMM_PAGE_APRR_WRITE_DISABLE); // other = (uint64_t *)(enabled ? _COMM_PAGE_APRR_WRITE_ENABLE // : _COMM_PAGE_APRR_WRITE_DISABLE); switch (*(volatile uint8_t *)_COMM_PAGE_APRR_SUPPORT) { case 1: do { val = *addr; reread = -1; asm volatile("msr S3_4_c15_c2_7, %0\n" "isb sy\n" : /* no outputs */ : "r"(val) : "memory"); val2 = *addr; asm volatile("mrs %0, S3_4_c15_c2_7\n" : "=r"(reread) : /* no inputs */ : "memory"); if (val2 == reread) { return; } usleep(10); } while (count-- > 0); break; case 3: do { val = *addr; reread = -1; asm volatile("msr S3_6_c15_c1_5, %0\n" "isb sy\n" : /* no outputs */ : "r"(val) : "memory"); val2 = *addr; asm volatile("mrs %0, S3_6_c15_c1_5\n" : "=r"(reread) : /* no inputs */ : "memory"); if (val2 == reread) { return; } usleep(10); } while (count-- > 0); break; default: pthread_jit_write_protect_np(enabled); return; } ERRF("failed to set jit write protection"); Abort(); #else pthread_jit_write_protect_np(enabled); #endif } static void *Calloc(size_t nmemb, size_t size) { STATISTIC(++jit_callocs); return calloc(nmemb, size); #define calloc please_use_Calloc } static void *Realloc(void *p, size_t n) { STATISTIC(++jit_reallocs); return realloc(p, n); #define realloc please_use_Realloc } static void Free(void *ptr) { if (!ptr) return; STATISTIC(++jit_frees); free(ptr); #define free please_use_Free } static struct JitJump *NewJitJump(struct Dll **freejumps) { struct Dll *e; struct JitJump *jj; if ((e = dll_first(*freejumps))) { STATISTIC(++jit_jump_alloc_freelist); dll_remove(freejumps, e); jj = JITJUMP_CONTAINER(e); } else if ((jj = (struct JitJump *)Calloc(1, sizeof(struct JitJump)))) { STATISTIC(++jit_jump_alloc_system); dll_init(&jj->elem); } return jj; } static struct JitPage *NewJitPage(void) { struct JitPage *jj; if ((jj = (struct JitPage *)Calloc(1, sizeof(struct JitPage)))) { dll_init(&jj->elem); } return jj; } static struct JitBlock *NewJitBlock(void) { struct JitBlock *jb; if ((jb = (struct JitBlock *)Calloc(1, sizeof(struct JitBlock)))) { dll_init(&jb->elem); dll_init(&jb->aged); JIT_LOGF("new jit block %p", jb); } return jb; } static struct JitStage *NewJitStage(void) { struct JitStage *js; if ((js = (struct JitStage *)Calloc(1, sizeof(struct JitStage)))) { dll_init(&js->elem); } return js; } static struct JitFreed *NewJitFreed(void) { struct JitFreed *jf; if ((jf = (struct JitFreed *)Calloc(1, sizeof(struct JitFreed)))) { dll_init(&jf->elem); } return jf; } static struct JitIntsSlab *NewJitIntsSlab(void) { struct JitIntsSlab *jis; if ((jis = (struct JitIntsSlab *)Calloc(1, sizeof(struct JitIntsSlab)))) { dll_init(&jis->elem); } return jis; } static void FreeJitJump(struct JitJump *jj) { Free(jj); } static void FreeJitPage(struct JitPage *jp) { Free(jp); } static void FreeJitFreed(struct JitFreed *jf) { Free(jf->data); Free(jf); } static void DestroyInts(struct JitInts *ji) { if (ji->p != ji->m) { Free(ji->p); } } static void FreeJitBlock(struct JitBlock *jb) { struct Dll *e; JIT_LOGF("freed jit block %p", jb); while ((e = dll_first(jb->freejumps))) { dll_remove(&jb->freejumps, e); FreeJitJump(JITJUMP_CONTAINER(e)); } Free(jb); } static void FreeJitStage(struct JitStage *js) { Free(js); } static void DestroyIntsAllocator(struct JitIntsAllocator *jia) { int i; struct Dll *e, *e2; struct JitIntsSlab *jis; Free(jia->p); for (e = dll_first(jia->slabs); e; e = e2) { e2 = dll_next(jia->slabs, e); jis = JIASLAB_CONTAINER(e); for (i = 0; i < ARRAYLEN(jis->p); ++i) { DestroyInts(jis->p + i); } Free(jis); } } static dontinline bool GrowIntsAllocator(struct JitIntsAllocator *jia) { int n2; struct JitInts **p2; p2 = jia->p; n2 = jia->n; if (n2 >= 2) { n2 += n2 >> 1; } else { n2 = 8; } if ((p2 = (struct JitInts **)Realloc(p2, n2 * sizeof(*p2)))) { jia->p = p2; jia->n = n2; return true; } else { return false; } } static struct JitInts *NewInts(struct JitIntsAllocator *jia) { struct Dll *e; struct JitInts *ji; struct JitIntsSlab *slab; if (jia->i) { STATISTIC(++jit_ints_alloc_freelist); return jia->p[--jia->i]; } if ((e = dll_first(jia->slabs))) { STATISTIC(++jit_ints_alloc_slab); slab = JIASLAB_CONTAINER(e); if (slab->i < ARRAYLEN(slab->p)) { ji = slab->p + slab->i++; ji->p = ji->m; ji->n = ARRAYLEN(ji->m); return ji; } } if ((slab = NewJitIntsSlab())) { STATISTIC(++jit_ints_alloc_system); dll_make_first(&jia->slabs, &slab->elem); return slab->p + slab->i++; } return 0; } static void FreeInts(struct JitIntsAllocator *jia, struct JitInts *ji) { if (ji) { ji->i = 0; if (jia->i == jia->n && !GrowIntsAllocator(jia)) return; jia->p[jia->i++] = ji; } } static bool GrowInts(struct JitInts *ji) { i64 *p2; size_t i, n2; p2 = ji->p; if (!ji->p) { unassert(!ji->n); ji->p = ji->m; ji->n = ARRAYLEN(ji->m); return true; } else if (ji->p == ji->m) { unassert(ji->n == ARRAYLEN(ji->m)); n2 = ARRAYLEN(ji->m) * 2; if ((p2 = Calloc(n2, sizeof(*p2)))) { for (i = 0; i < ARRAYLEN(ji->m); ++i) { p2[i] = ji->m[i]; } ji->p = p2; ji->n = n2; return true; } else { return false; } } else { n2 = ji->n; n2 += n2 >> 1; if ((p2 = (i64 *)Realloc(p2, n2 * sizeof(*p2)))) { ji->p = p2; ji->n = n2; return true; } else { return false; } } } static bool AddInt(struct JitInts *ji, i64 x) { if (ji->i == ji->n && !GrowInts(ji)) return false; ji->p[ji->i++] = x; return true; } static bool RemoveInt(struct JitInts *ji, i64 x) { int i, j; for (i = j = 0; i < ji->i; ++i) { if (ji->p[i] != x) { ji->p[j++] = ji->p[i]; } } ji->i -= i - j; return i > j; } static void InitEdges(struct JitEdges *e) { memset(e, 0, sizeof(*e)); e->n = RoundupTwoPow(kJitInitialEdges); unassert(e->src = (i64 *)Calloc(e->n, sizeof(*e->src))); unassert(e->dst = (struct JitInts **)Calloc(e->n, sizeof(*e->dst))); } static void DestroyEdges(struct JitEdges *edges) { DestroyIntsAllocator(&edges->jia); Free(edges->dst); Free(edges->src); } static nosideeffect int GetEdge(const struct JitEdges *edges, i64 src) { unsigned hash, spot, step; hash = HASH(src); for (spot = step = 0;; ++step) { spot = (hash + step * ((step + 1) >> 1)) & (edges->n - 1); if (!edges->src[spot] || edges->src[spot] == src) { return spot; } } } static unsigned GrowEdges(struct JitEdges *edges) { i64 *src, *src2; struct JitInts **dst, **dst2; unsigned i, i1, i2, n1, n2, used, hash, spot, step; i1 = edges->i; n1 = edges->n; src = edges->src; dst = edges->dst; unassert(n1 > 1 && IS2POW(n1)); for (used = i = 0; i < n1; ++i) used += !!dst[i]; n2 = n1 << (used > (n1 >> 2)); if (!(src2 = (i64 *)Calloc(n2, sizeof(*src2))) || !(dst2 = (struct JitInts **)Calloc(n2, sizeof(*dst2)))) { Free(src2); return 0; } for (i2 = i = 0; i < n1; ++i) { if (!src[i]) { unassert(!dst[i]); continue; } --i1; if (!dst[i]) { continue; } ++i2; spot = 0; step = 0; hash = HASH(src[i]); do { spot = (hash + step * ((step + 1) >> 1)) & (n2 - 1); unassert(src2[spot] != src[i]); ++step; } while (src2[spot]); src2[spot] = src[i]; dst2[spot] = dst[i]; } unassert(!i1); edges->i = i2; edges->n = n2; edges->src = src2; edges->dst = dst2; Free(src); Free(dst); return n2; } static bool AddEdge(struct JitEdges *edges, i64 src, i64 dst) { int s; if (edges->i == (edges->n >> 1)) { if (!GrowEdges(edges)) return false; } if (!edges->src[(s = GetEdge(edges, src))]) { edges->src[s] = src; ++edges->i; } if (!edges->dst[s]) { if (!(edges->dst[s] = NewInts(&edges->jia))) return false; } return AddInt(edges->dst[s], dst); } static void RemoveEdgesByIndex(struct JitEdges *edges, int s) { unassert(s >= 0 && s < edges->n); FreeInts(&edges->jia, edges->dst[s]); edges->dst[s] = 0; } static bool RemoveEdges(struct JitEdges *edges, i64 src) { int s; if (!edges->dst[(s = GetEdge(edges, src))]) return false; RemoveEdgesByIndex(edges, s); return true; } static bool RemoveEdge(struct JitEdges *edges, i64 src, i64 dst) { int s; if (!edges->dst[(s = GetEdge(edges, src))]) return false; if (!RemoveInt(edges->dst[s], dst)) return false; if (!edges->dst[s]->i) RemoveEdgesByIndex(edges, s); return true; } static void ClearEdges(struct JitEdges *edges) { int i; for (i = 0; i < edges->n; ++i) { edges->src[i] = 0; RemoveEdgesByIndex(edges, i); } edges->i = 0; } static bool IsCyclic(struct JitEdges *edges, i64 V[kJitDepth], int d, i64 dst) { int i, s; if (d == kJitDepth) { return true; } for (i = 0; i < d; ++i) { if (dst == V[i]) { return true; } } V[d++] = dst; if (edges->dst[(s = GetEdge(edges, dst))]) { for (i = 0; i < edges->dst[s]->i; ++i) { if (IsCyclic(edges, V, d, edges->dst[s]->p[i])) { return true; } } } return false; } static inline uintptr_t DecodeJitFunc(int func) { unassert(func); return (intptr_t)IMAGE_END + func; } static nosideeffect int EncodeJitFunc(intptr_t addr) { int func; intptr_t base, disp; if (addr) { base = (intptr_t)IMAGE_END; disp = addr - base; func = disp; unassert(func && func == disp); } else { func = 0; } return func; } bool CanJitForImmediateEffect(void) { return atomic_load_explicit(&g_jit.prot, memory_order_relaxed) & PROT_EXEC; } static u8 *AllocateJitMemory(long *state) { long i, brk; uintptr_t p; brk = *state; p = (uintptr_t)g_code; i = ROUNDUP(p + brk, FLAG_pagesize) - p; if (i + kJitBlockSize > kJitMemorySize) { return 0; } *state = i + kJitBlockSize; return g_code + i; } static int MakeJitJump(u8 buf[5], uintptr_t pc, uintptr_t addr) { int n; intptr_t disp; #if defined(__x86_64__) disp = addr - (pc + 5); unassert(kAmdDispMin <= disp && disp <= kAmdDispMax); buf[0] = kAmdJmp; Write32(buf + 1, disp & kAmdDispMask); n = 5; #elif defined(__aarch64__) disp = addr - pc; disp >>= 2; unassert(kArmDispMin <= disp && disp <= kArmDispMax); Write32(buf, kArmJmp | (disp & kArmDispMask)); n = 4; #endif return n; } // Obtains JitBlock from global pool or creates one if none exist. static struct JitBlock *AcquireJitBlock(struct Jit *jit) { struct Dll *e; struct JitBlock *jb; LOCK(&g_jit.lock); if ((e = dll_first(g_jit.freeblocks))) { dll_remove(&g_jit.freeblocks, e); jb = JITBLOCK_CONTAINER(e); unassert(g_jit.freecount > 0); --g_jit.freecount; } else { jb = 0; } UNLOCK(&g_jit.lock); if (jb) dll_make_last(&jit->agedblocks, &jb->aged); JIT_LOGF("acquired jit block %p (freecount=%d)", jb, g_jit.freecount); return jb; } // Frees JitBlock. The JIT block is added to a global free list, so it // can be reclaimed if a new Jit system is created. This is intended for // once all threads have shut down, due to exit_group() or execve(). // @assume jit->lock static void ReleaseJitBlock(struct JitBlock *jb) { struct Dll *e; JIT_LOGF("released jit block %p", jb); while ((e = dll_first(jb->staged))) { dll_remove(&jb->staged, e); FreeJitStage(JITSTAGE_CONTAINER(e)); } dll_make_first(&jb->freejumps, jb->jumps); jb->jumps = 0; jb->start = 0; jb->index = 0; jb->committed = 0; jb->wasretired = false; jb->isprotected = false; dll_init(&jb->aged); LOCK(&g_jit.lock); dll_make_first(&g_jit.freeblocks, &jb->elem); ++g_jit.freecount; UNLOCK(&g_jit.lock); } // Frees JitBlock and adds it to the global free list in such a way that // it'll take a long time before it's reused. This is intended for a JIT // under active use that's trying to reclaim jit memory. // @assume jit->lock static void RetireJitBlock(struct Jit *jit, struct JitBlock *jb) { JIT_LOGF("retiring jit block %p", jb); unassert(!jb->isprotected); unassert(dll_is_empty(jb->jumps)); unassert(dll_is_empty(jb->staged)); STATISTIC(++jit_blocks_retired); dll_remove(&jit->blocks, &jb->elem); dll_remove(&jit->agedblocks, &jb->aged); jb->start = 0; jb->index = 0; jb->committed = 0; jb->wasretired = true; LOCK(&g_jit.lock); dll_make_last(&g_jit.freeblocks, &jb->elem); ++g_jit.freecount; UNLOCK(&g_jit.lock); } // creates new jit block and sets up its jit memory static struct JitBlock *InitJitBlock(struct Jit *jit, long *state) { struct JitBlock *jb; if ((jb = NewJitBlock())) { if (!(jb->addr = AllocateJitMemory(state))) { FreeJitBlock(jb); jb = 0; } } return jb; } static void LockJit(struct Jit *jit) { if (jit->threaded) { LOCK(&jit->lock); } } static void UnlockJit(struct Jit *jit) { if (jit->threaded) { UNLOCK(&jit->lock); } } /** * Initializes memory object for Just-In-Time (JIT) threader. * * The `jit` struct itself is owned by the caller. Internal memory * associated with this object should be reclaimed later by calling * DestroyJit(). * * @return 0 on success */ int InitJit(struct Jit *jit, uintptr_t opt_staging_function) { long brk; unsigned n; struct JitBlock *jb; _Atomic(int) *funcs; _Atomic(uintptr_t) *virts; _Static_assert(kJitAlign >= 1, ""); _Static_assert(kJitBlockSize >= 4096, ""); _Static_assert(kJitInitialHooks >= 2, ""); unassert(FLAG_pagesize >= 4096); unassert(kJitBlockSize >= FLAG_pagesize); unassert(!(kJitBlockSize % FLAG_pagesize)); memset(jit, 0, sizeof(*jit)); InitEdges(&jit->edges); InitEdges(&jit->redges); jit->staging = EncodeJitFunc(opt_staging_function); unassert(!pthread_mutex_init(&jit->lock, 0)); jit->hooks.n = n = RoundupTwoPow(kJitInitialHooks); unassert(virts = (_Atomic(uintptr_t) *)Calloc(n, sizeof(*virts))); unassert(funcs = (_Atomic(int) *)Calloc(n, sizeof(*funcs))); atomic_store_explicit(&jit->hooks.virts, virts, memory_order_relaxed); atomic_store_explicit(&jit->hooks.funcs, funcs, memory_order_relaxed); for (brk = 0; (jb = InitJitBlock(jit, &brk));) { dll_make_last(&g_jit.freeblocks, &jb->elem); ++g_jit.freecount; } JIT_LOGF("initialized jit %p", jit); return 0; } /** * Destroys initialized JIT object. * * Passing a value not previously initialized by InitJit() is undefined. * * @return 0 on success */ int DestroyJit(struct Jit *jit) { struct Dll *e, *e2; LockJit(jit); JIT_LOGF("destroying jit %p", jit); for (e = dll_first(jit->freeds.p); e; e = e2) { e2 = dll_next(jit->freeds.p, e); FreeJitFreed(JITFREED_CONTAINER(e)); } while ((e = dll_first(jit->blocks))) { dll_remove(&jit->blocks, e); ReleaseJitBlock(JITBLOCK_CONTAINER(e)); } dll_make_first(&jit->freejumps, jit->jumps); for (e = dll_first(jit->freejumps); e; e = e2) { e2 = dll_next(jit->freejumps, e); FreeJitJump(JITJUMP_CONTAINER(e)); } for (e = dll_first(jit->pages); e; e = e2) { e2 = dll_next(jit->pages, e); FreeJitPage(JITPAGE_CONTAINER(e)); } UnlockJit(jit); unassert(!pthread_mutex_destroy(&jit->lock)); DestroyEdges(&jit->redges); DestroyEdges(&jit->edges); Free(jit->hooks.funcs); Free(jit->hooks.virts); return 0; } /** * Releases global JIT resources at shutdown. */ int ShutdownJit(void) { struct Dll *e; JIT_LOGF("shutting down jit"); while ((e = dll_first(g_jit.freeblocks))) { dll_remove(&g_jit.freeblocks, e); FreeJitBlock(JITBLOCK_CONTAINER(e)); --g_jit.freecount; } unassert(!g_jit.freecount); return 0; } /** * Disables Just-In-Time threader. */ int DisableJit(struct Jit *jit) { atomic_store_explicit(&jit->disabled, true, memory_order_release); return 0; } /** * Enables Just-In-Time threader. */ int EnableJit(struct Jit *jit) { atomic_store_explicit(&jit->disabled, false, memory_order_release); return 0; } /** * Fixes the memory protection for existing Just-In-Time code blocks. */ int FixJitProtection(struct Jit *jit) { int prot; struct Dll *e; LockJit(jit); prot = atomic_load_explicit(&g_jit.prot, memory_order_relaxed); for (e = dll_first(jit->blocks); e; e = dll_next(jit->blocks, e)) { unassert( !Mprotect(JITBLOCK_CONTAINER(e)->addr, kJitBlockSize, prot, "jit")); } UnlockJit(jit); return 0; } // @assume jit->lock static struct JitPage *GetJitPage(struct Jit *jit, i64 addr) { i64 page; bool lru; struct Dll *e; struct JitPage *jp; lru = false; page = addr & -4096; for (e = dll_first(jit->pages); e; e = dll_next(jit->pages, e)) { jp = JITPAGE_CONTAINER(e); if (jp->page == page) { if (!lru) { STATISTIC(++jit_pages_hits_1); } else { STATISTIC(++jit_pages_hits_2); dll_remove(&jit->pages, e); dll_make_first(&jit->pages, e); } return jp; } lru = true; } return 0; } // @assume jit->lock static struct JitPage *GetOrCreateJitPage(struct Jit *jit, i64 addr) { i64 page; struct JitPage *jp; page = addr & -4096; if (!(jp = GetJitPage(jit, page))) { if ((jp = NewJitPage())) { dll_make_first(&jit->pages, &jp->elem); jp->page = page; } } return jp; } // adds heap memory to freelist // this is intended for synchronization cooloff // @assume jit->lock static void RetireJitHeap(struct Jit *jit, void *data, size_t size) { struct Dll *e; struct JitFreed *jf = 0; if (!data) return; if (!jit->threaded) { Free(data); return; } if ((e = dll_first(jit->freeds.f))) { dll_remove(&jit->freeds.f, e); jf = JITFREED_CONTAINER(e); } else if (!(jf = NewJitFreed())) { return; // we can't free data so just leak it } jf->data = data; jf->size = size; dll_make_last(&jit->freeds.p, &jf->elem); ++jit->freeds.n; } // same as calloc, but pilfers old retired heap memory from freelist // @assume jit->lock static void *GetJitHeap(struct Jit *jit, size_t count, size_t elsize) { u64 size; void *res = 0; struct Dll *e; struct JitFreed *jf; if (ckd_mul(&size, count, elsize)) return 0; if (jit->freeds.n > kJitRetireQueue) { for (e = dll_first(jit->freeds.p); e; e = dll_next(jit->freeds.p, e)) { dll_remove(&jit->freeds.p, e); jf = JITFREED_CONTAINER(e); if (jf->size >= size) { res = jf->data; dll_make_first(&jit->freeds.f, e); break; } } } if (res) { memset(res, 0, size); } else { res = Calloc(1, size); } return res; } // @assume jit->lock static unsigned RehashJitHooks(struct Jit *jit) { int func; uintptr_t key, virt; unsigned i, i2, n1, n2, used, hash, spot, step, kgen; _Atomic(int) *funcs, *funcs2; _Atomic(uintptr_t) *virts, *virts2; virts = atomic_load_explicit(&jit->hooks.virts, memory_order_relaxed); funcs = atomic_load_explicit(&jit->hooks.funcs, memory_order_relaxed); // grow allocation unless this rehash is due to many deleted values n1 = atomic_load_explicit(&jit->hooks.n, memory_order_relaxed); unassert(n1 > 1 && IS2POW(n1)); for (used = i = 0; i < n1; ++i) { used += !!atomic_load_explicit(funcs + i, memory_order_relaxed); } n2 = n1 << (used > (n1 >> 2)); JIT_LOGF("rehashing jit hooks %u -> %u", n1, n2); // allocate an entirely new hash table if (!(virts2 = (_Atomic(uintptr_t) *)GetJitHeap(jit, n2, sizeof(*virts2))) || !(funcs2 = (_Atomic(int) *)GetJitHeap(jit, n2, sizeof(*funcs2)))) { RetireJitHeap(jit, virts2, n2 * sizeof(*virts2)); return 0; } // copy entries over to new hash table, removing deleted entries for (i2 = i = 0; i < n1; ++i) { virt = atomic_load_explicit(virts + i, memory_order_relaxed); func = atomic_load_explicit(funcs + i, memory_order_relaxed); if (virt && func) { spot = 0; step = 0; hash = HASH(virt); do { spot = (hash + step * ((step + 1) >> 1)) & (n2 - 1); key = atomic_load_explicit(virts2 + spot, memory_order_relaxed); unassert(key != virt); ++step; } while (key); atomic_store_explicit(virts2 + spot, virt, memory_order_relaxed); atomic_store_explicit(funcs2 + spot, func, memory_order_relaxed); ++i2; } } // update the hash table pointers for the lockless reader kgen = BeginUpdate(&jit->keygen); atomic_store_explicit(&jit->hooks.virts, virts2, memory_order_release); atomic_store_explicit(&jit->hooks.funcs, funcs2, memory_order_relaxed); atomic_store_explicit(&jit->hooks.n, n2, memory_order_release); EndUpdate(&jit->keygen, kgen); // leak old table so failed reads won't segfault from free munmap RetireJitHeap(jit, virts, n1 * sizeof(*virts)); RetireJitHeap(jit, funcs, n1 * sizeof(*funcs)); jit->hooks.i = i2; return n2; } // @assume jit->lock static bool SetJitHookUnlocked(struct Jit *jit, u64 virt, int cas, intptr_t funcaddr) { uintptr_t key; int func, oldfunc; struct JitPage *jp; _Atomic(int) *funcs; _Atomic(uintptr_t) *virts; unsigned n, kgen, hash, spot, step; unassert(virt); // ensure there's room to add this hook unassert(jit->hooks.i <= jit->hooks.n / 2); n = atomic_load_explicit(&jit->hooks.n, memory_order_relaxed); if (jit->hooks.i == n / 2 && !(n = RehashJitHooks(jit))) { DisableJit(jit); return false; } // probe for spot in hash table. this is guaranteed to halt since we // never place more than jit->hooks.n/2 items within this hash table spot = 0; step = 0; hash = HASH(virt); virts = atomic_load_explicit(&jit->hooks.virts, memory_order_relaxed); funcs = atomic_load_explicit(&jit->hooks.funcs, memory_order_relaxed); do { spot = (hash + step * ((step + 1) >> 1)) & (n - 1); key = atomic_load_explicit(virts + spot, memory_order_relaxed); ++step; } while (key && key != virt); func = EncodeJitFunc(funcaddr); oldfunc = atomic_load_explicit(funcs + spot, memory_order_relaxed); if (jit->staging) { if (func == jit->staging) { STATISTIC(++jit_hooks_staged); if (key && oldfunc != jit->staging) { STATISTIC(++jit_hooks_deleted); } } else { if (key && cas && oldfunc != cas) { // if staging is enabled and the hook isn't the staging address, // then some other thread must have won the race to install this return false; } STATISTIC(--jit_hooks_staged); if (func) { STATISTIC(++jit_hooks_installed); } } } else { if (key && oldfunc) { STATISTIC(++jit_hooks_deleted); } if (func) { STATISTIC(++jit_hooks_installed); } } if (!key) { ++jit->hooks.i; STATISTIC(jit_hash_elements = MAX(jit_hash_elements, jit->hooks.i)); } if (func && (jp = GetOrCreateJitPage(jit, virt))) { jp->bitset |= (u64)1 << ((virt & 4095) >> 6); } kgen = BeginUpdate(&jit->keygen); atomic_store_explicit(virts + spot, virt, memory_order_release); atomic_store_explicit(funcs + spot, func, memory_order_relaxed); EndUpdate(&jit->keygen, kgen); return true; } static bool SetJitHook(struct Jit *jit, u64 virt, int cas, intptr_t funcaddr) { bool res; LockJit(jit); res = SetJitHookUnlocked(jit, virt, cas, funcaddr); UnlockJit(jit); return res; } /** * Retrieves native function for executing virtual address. * * @param jit is the System's Jit object * @param virt is the hash table key, or virtual address of path start * @return native function address, or 0 if it doesn't exist */ uintptr_t GetJitHook(struct Jit *jit, u64 virt) { int off; uintptr_t key, res; _Atomic(int) *funcs; _Atomic(uintptr_t) *virts; unsigned n, kgen, hash, spot, step; COSTLY_STATISTIC(++jit_hash_lookups); hash = HASH(virt); do { kgen = atomic_load_explicit(&jit->keygen, memory_order_relaxed); n = atomic_load_explicit(&jit->hooks.n, memory_order_relaxed); virts = atomic_load_explicit(&jit->hooks.virts, memory_order_acquire); for (spot = step = 0;; ++step) { spot = (hash + step * ((step + 1) >> 1)) & (n - 1); key = atomic_load_explicit(virts + spot, memory_order_acquire); if (key == virt) { funcs = atomic_load_explicit(&jit->hooks.funcs, memory_order_relaxed); off = atomic_load_explicit(funcs + spot, memory_order_relaxed); res = off ? DecodeJitFunc(off) : 0; break; } if (!key) { return 0; } COSTLY_STATISTIC(++jit_hash_collisions); } } while (ShallNotPass(kgen, &jit->keygen)); return res; } // removes hook and edges for jit path and all paths that depend on it // @assume jit->lock static void DeleteJitPath(struct Jit *jit, i64 virt) { i64 dep; uintptr_t key; int i, s, old; _Atomic(int) *funcs; _Atomic(uintptr_t) *virts; unsigned n, hash, spot, step; // delete hook for this path from hash table hash = HASH(virt); for (spot = step = 0;; ++step) { n = atomic_load_explicit(&jit->hooks.n, memory_order_relaxed); spot = (hash + step * ((step + 1) >> 1)) & (n - 1); virts = atomic_load_explicit(&jit->hooks.virts, memory_order_relaxed); key = atomic_load_explicit(virts + spot, memory_order_relaxed); if (!key) return; if ((i64)key == virt) { JIT_LOGF("deleting jit hook for path starting at %#" PRIx64, virt); funcs = atomic_load_explicit(&jit->hooks.funcs, memory_order_relaxed); old = atomic_load_explicit(funcs + spot, memory_order_relaxed); if (old) { atomic_store_explicit(funcs + spot, 0, memory_order_release); if (old == jit->staging) { STATISTIC(--jit_hooks_staged); } else { STATISTIC(--jit_hooks_installed); STATISTIC(++jit_hooks_deleted); } } break; } } // delete paths that point to this path while (jit->redges.dst[(s = GetEdge(&jit->redges, virt))] && jit->redges.dst[s]->i) { dep = jit->redges.dst[s]->p[jit->redges.dst[s]->i - 1]; JIT_LOGF("jit path %#" PRIx64 " depends on %#" PRIx64, dep, virt); DeleteJitPath(jit, dep); } // delete edges associated with this path from bimap if (jit->edges.dst[(s = GetEdge(&jit->edges, virt))]) { for (i = jit->edges.dst[s]->i; i--;) { RemoveEdge(&jit->redges, jit->edges.dst[s]->p[i], virt); } RemoveEdgesByIndex(&jit->edges, s); } } // @assume jit->lock static void ResetJitPageHooks(struct Jit *jit, i64 page) { i64 virt; unsigned i, boff; struct JitPage *jp; if (!(jp = GetJitPage(jit, page))) return; STATISTIC(AVERAGE(jit_page_average_bits, popcount(jp->bitset))); while (jp->bitset) { boff = bsr(jp->bitset); virt = page + boff * (4096 / 64); jp->bitset &= ~((u64)1 << boff); for (i = 0; i < 64; ++i) { DeleteJitPath(jit, virt + i); } } dll_remove(&jit->pages, &jp->elem); FreeJitPage(jp); } // @assume jit->lock static int ResetJitPageUnlocked(struct Jit *jit, i64 virt) { i64 page; unsigned gen; page = virt & -4096; STATISTIC(++jit_page_resets); JIT_LOGF("resetting jit page %#" PRIx64, page); gen = BeginUpdate(&jit->pagegen); ResetJitPageHooks(jit, page); dll_make_first(&jit->freejumps, jit->jumps); jit->jumps = 0; EndUpdate(&jit->pagegen, gen); return 0; } /** * Clears JIT paths installed to memory page. * * This is intended to be called when functions like mmap(), munmap(), * and mprotect() cause a memory page to either disappear or lose exec * permissions. * * @param virt is virtual address of 4096-byte page (needn't be aligned) * @return 0 on success, or -1 w/ errno */ int ResetJitPage(struct Jit *jit, i64 virt) { int res; if (IsJitDisabled(jit)) return einval(); LockJit(jit); res = ResetJitPageUnlocked(jit, virt); UnlockJit(jit); return res; } // @assume jit->lock static void ForceJitBlocksToRetire(struct Jit *jit) { int i; struct Dll *e, *e2; struct JitBlock *jb; unsigned n, pgen, kgen; JIT_LOGF("retiring jit blocks to avoid oom"); dll_make_first(&jit->freejumps, jit->jumps); jit->jumps = 0; pgen = BeginUpdate(&jit->pagegen); for (e = dll_first(jit->agedblocks); e; e = e2) { e2 = dll_next(jit->agedblocks, e); jb = AGEDBLOCK_CONTAINER(e); if (!jb->isprotected) { JIT_LOGF("forcing jit block %p to retire", jb); RetireJitBlock(jit, jb); } } n = atomic_load_explicit(&jit->hooks.n, memory_order_relaxed); for (i = 0; i < n; ++i) { if (atomic_load_explicit(jit->hooks.virts + i, memory_order_relaxed)) { kgen = BeginUpdate(&jit->keygen); atomic_store_explicit(jit->hooks.virts + i, 0, memory_order_release); atomic_store_explicit(jit->hooks.funcs + i, 0, memory_order_relaxed); EndUpdate(&jit->keygen, kgen); } } jit->hooks.i = 0; ClearEdges(&jit->redges); ClearEdges(&jit->edges); EndUpdate(&jit->pagegen, pgen); } static bool CheckMmapResult(void *want, void *got) { if (got == MAP_FAILED) { LOGF("failed to mmap() jit block: %s", DescribeHostErrno(errno)); return false; } if (got != want) { LOGF("jit block mmap(%p) returned unexpected address %p: %s", want, got, DescribeHostErrno(errno)); return false; } return true; } static bool PrepareJitMemory(void *addr, size_t size) { #ifdef MAP_JIT // Apple M1 only permits RWX memory if we use MAP_JIT, which Apple has // chosen to make incompatible with MAP_FIXED. if (Munmap(addr, size)) { LOGF("failed to munmap() jit block: %s", DescribeHostErrno(errno)); return false; } return CheckMmapResult( addr, Mmap(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_JIT | MAP_PRIVATE | MAP_ANONYMOUS_, -1, 0, "jit")); #else int prot; prot = atomic_load_explicit(&g_jit.prot, memory_order_relaxed); if (!Mprotect(addr, size, prot, "jit")) { return true; } if (~prot & PROT_EXEC) { LOGF("failed to mprotect() jit block: %s", DescribeHostErrno(errno)); return false; } // OpenBSD imposes a R^X invariant and raises ENOTSUP if RWX // memory is requested. Since other OSes might exist, having // this same requirement, and possible a different errno, we // shall just clear the exec flag and try again. prot &= ~PROT_EXEC; atomic_store_explicit(&g_jit.prot, prot, memory_order_relaxed); return CheckMmapResult( addr, Mmap(addr, size, prot, MAP_PRIVATE | MAP_ANONYMOUS_ | MAP_FIXED, -1, 0, "jit")); #endif } /** * Begins writing function definition to JIT memory. * * This will acquire a block of JIT memory. Code may be added to the * function using methods like AppendJitPrologue() and AppendJitCall(). * When a chunk is completed, FinishJit() should be called. The calling * thread is granted exclusive ownership of the returned block of JIT * memory, until it's relinquished by FinishJit(). * * @param opt_virt is hash key for finished function, or 0 for manual * @return function builder object */ struct JitBlock *StartJit(struct Jit *jit, i64 opt_virt) { struct Dll *e; struct JitBlock *jb; if (!IsJitDisabled(jit)) { LockJit(jit); if ((e = dll_first(jit->blocks)) && // (jb = JITBLOCK_CONTAINER(e)) && // jb->index + kJitFit <= kJitBlockSize) { // we found a block with adequate free space owned by jit dll_remove(&jit->blocks, &jb->elem); } else { if (g_jit.freecount <= kJitRetireQueue) { ForceJitBlocksToRetire(jit); } if (!(jb = AcquireJitBlock(jit))) { LOG_ONCE(LOGF("ran out of jit memory")); } else if (!PrepareJitMemory(jb->addr, kJitBlockSize)) { // this system isn't allowing us to use jit memory dll_remove(&jit->agedblocks, &jb->aged); ReleaseJitBlock(jb); DisableJit(jit); jb = 0; } } if (jb) { dll_make_first(&jb->freejumps, jit->freejumps); jit->freejumps = 0; } UnlockJit(jit); } else { jb = 0; } if (jb) { jb->virt = opt_virt; unassert(!(jb->start & (kJitAlign - 1))); unassert(jb->start == jb->index); jb->pagegen = atomic_load_explicit(&jit->pagegen, memory_order_acquire); if (jb->virt && jit->staging) { unassert(SetJitHook(jit, jb->virt, 0, DecodeJitFunc(jit->staging))); } else { JIT_LOGF("marking jit block %p as protected due to manual mode", jb); jb->isprotected = true; } if (pthread_jit_write_protect_supported_np()) { pthread_jit_write_protect_np_workaround(false); } } return jb; } static bool OomJit(struct JitBlock *jb) { jb->index = kJitBlockSize + 1; return false; } /** * Appends bytes to JIT block. * * Errors here safely propagate to FinishJit(). * * @return true if room was available, otherwise false */ inline bool AppendJit(struct JitBlock *jb, const void *data, long size) { unassert(size > 0); jb->lastaction = 0; if (size <= GetJitRemaining(jb)) { memcpy(jb->addr + jb->index, data, size); jb->index += size; return true; } else { return OomJit(jb); } } static struct Dll *GetJitJumps(struct Jit *jit, struct JitBlock *jb, u64 virt) { struct JitJump *jj; struct Dll *res, *rem, *e, *e2; LockJit(jit); for (rem = res = 0, e = dll_first(jit->jumps); e; e = e2) { e2 = dll_next(jit->jumps, e); jj = JITJUMP_CONTAINER(e); if (jj->virt == virt) { dll_remove(&jit->jumps, e); dll_make_first(&res, e); } else if (++jj->tries == kJitJumpTries) { dll_remove(&jit->jumps, e); dll_make_first(&rem, e); } } UnlockJit(jit); dll_make_first(&jb->freejumps, rem); return res; } static void FixupJitJumps(struct JitBlock *jb, struct Dll *list, uintptr_t addr) { int n; union { u32 i; u64 q; u8 b[8]; } u; struct Dll *e; struct JitJump *jj; for (e = dll_first(list); e; e = dll_next(list, e)) { STATISTIC(++jumps_applied); STATISTIC(++path_connected_directly); jj = JITJUMP_CONTAINER(e); u.q = 0; n = MakeJitJump(u.b, (uintptr_t)jj->code, addr + jj->addend); unassert(!((uintptr_t)jj->code & 3)); #if defined(__aarch64__) atomic_store_explicit((_Atomic(u32) *)jj->code, u.i, memory_order_release); #elif defined(__x86_64__) u64 old, neu; old = atomic_load_explicit((_Atomic(u64) *)jj->code, memory_order_relaxed); do { neu = (old & 0xffffff0000000000) | u.q; } while (!atomic_compare_exchange_weak_explicit( (_Atomic(u64) *)jj->code, &old, neu, memory_order_release, memory_order_relaxed)); #else #error "not supported" #endif sys_icache_invalidate(jj->code, n); } dll_make_first(&jb->freejumps, list); } static bool UpdateJitHook(struct Jit *jit, struct JitBlock *jb, u64 virt, uintptr_t funcaddr) { struct Dll *jumps; unassert(funcaddr); jumps = GetJitJumps(jit, jb, virt); if (SetJitHook(jit, virt, jit->staging, funcaddr)) { FixupJitJumps(jb, jumps, funcaddr); return true; } else { dll_make_first(&jb->freejumps, jumps); return false; } } static void AbandonJitHook(struct Jit *jit, u64 virt) { if (virt && jit->staging) { SetJitHook(jit, virt, 0, 0); } } // mprotects jit memory if a system page worth of code was generated // @assume jit->lock int CommitJit_(struct Jit *jit, struct JitBlock *jb) { u8 *addr; size_t size; int count = 0; long blockoff; struct JitJump *jj; struct JitStage *js; struct Dll *e, *e2, *rem; unassert(jb->start == jb->index); unassert(!(jb->committed & (FLAG_pagesize - 1))); if (!CanJitForImmediateEffect() && (blockoff = ROUNDDOWN(jb->start, FLAG_pagesize)) > jb->committed) { addr = jb->addr + jb->committed; size = blockoff - jb->committed; JIT_LOGF("jit activating [%p,%p) w/ %zu kb", addr, addr + size, size / 1024); // abandon fixups pointing into the block being protected LockJit(jit); for (rem = 0, e = dll_first(jit->jumps); e; e = e2) { e2 = dll_next(jit->jumps, e); jj = JITJUMP_CONTAINER(e); if (MAX(jj->code, addr) < MIN(jj->code + 5, addr + size)) { dll_remove(&jit->jumps, e); dll_make_first(&rem, e); } } UnlockJit(jit); for (e = dll_first(rem); e; e = e2) { e2 = dll_next(rem, e); FreeJitJump(JITJUMP_CONTAINER(e)); } // ask system to change the page memory protections unassert(!Mprotect(addr, size, PROT_READ | PROT_EXEC, "jit")); // update interpreter hooks so our new jit code goes live while ((e = dll_first(jb->staged))) { js = JITSTAGE_CONTAINER(e); unassert(js->index >= jb->committed); if (js->index <= blockoff) { if (!ShallNotPass(js->pagegen, &jit->pagegen)) { UpdateJitHook(jit, jb, js->virt, (uintptr_t)jb->addr + js->start); } else { AbandonJitHook(jit, js->virt); } dll_remove(&jb->staged, e); FreeJitStage(js); ++count; } else { break; } } jb->committed = blockoff; } return count; } // puts user leased block back into jit->blocks pool for potential reuse // @assume jit->lock void ReinsertJitBlock_(struct Jit *jit, struct JitBlock *jb) { unassert(jb->start == jb->index); unassert(dll_is_empty(jb->jumps)); if (jb->index < kJitBlockSize) { // there's still memory remaining; reinsert for immediate reuse. dll_make_first(&jit->blocks, &jb->elem); } else { // block has been filled; relegate it to the end of the list. // guarantee that staged hooks shall be committed on openbsd. _Static_assert(kJitBlockSize % kMaximumAnticipatedPageSize == 0, "unassert(dll_is_empty(jb->staged)) can't pass " "unless kJitBlockSize is divisible by page size"); unassert(dll_is_empty(jb->staged)); dll_make_last(&jit->blocks, &jb->elem); } } // append our list of code fixups to jit system which may apply it later static void CommitJitJumps(struct Jit *jit, struct JitBlock *jb) { if (!dll_is_empty(jb->jumps)) { LockJit(jit); dll_make_first(&jit->jumps, jb->jumps); jb->jumps = 0; UnlockJit(jit); } } // discards fixups associated with function that couldn't be generated static void AbandonJitJumps(struct JitBlock *jb) { struct Dll *e, *e2; for (e = dll_first(jb->jumps); e; e = e2) { e2 = dll_next(jb->jumps, e); FreeJitJump(JITJUMP_CONTAINER(e)); } jb->jumps = 0; } /** * Records jump instruction fixup. * * When a JIT path ends because it's branching into an address for which * a JIT path doesn't exist yet, the caller may choose to generated code * that falls back into the main interpreter loop while recording a jump * fixup, so that if the destination virtual address is generated later, * the JIT will atomically self-modify this code to jump to the new one. * * @param virt is hash table key of destination (should be empty now) * @param addend is added to dest function pointer to compute jump */ bool RecordJitJump(struct JitBlock *jb, u64 virt, int addend) { struct JitJump *jj; if (jb->index > kJitBlockSize) return false; #if defined(__x86_64__) unassert(!(GetJitPc(jb) & 7)); #endif if (!CanJitForImmediateEffect()) return false; if (!(jj = NewJitJump(&jb->freejumps))) return false; jj->tries = 0; jj->virt = virt; jj->code = (u8 *)GetJitPc(jb); jj->addend = addend; dll_make_first(&jb->jumps, &jj->elem); STATISTIC(++jumps_recorded); return true; } // @assume jit->lock static bool RecordJitEdgeImpl(struct Jit *jit, i64 src, i64 dst) { i64 visits[kJitDepth]; if (src == dst) return false; visits[0] = src; if (IsCyclic(&jit->edges, visits, 1, dst)) { STATISTIC(++jit_cycles_avoided); return false; } if (!AddEdge(&jit->edges, src, dst)) { return false; } if (!AddEdge(&jit->redges, dst, src)) { RemoveEdge(&jit->edges, src, dst); return false; } return true; } /** * Records JIT edge or returns false if it'd create a cycle. */ bool RecordJitEdge(struct Jit *jit, i64 src, i64 dst) { bool res; LockJit(jit); res = RecordJitEdgeImpl(jit, src, dst); UnlockJit(jit); return res; } static void DiscardGeneratedJitCode(struct JitBlock *jb) { jb->index = jb->start; } /** * Finishes writing function definition to JIT memory. * * Errors that happened earlier in AppendJit*() methods will safely * propagate to this function. This function may disable the JIT on * errors that aren't recoverable. * * @param jb is function builder object that was returned by StartJit(); * this function always relinquishes the calling thread's ownership * of this object, even if this function returns an error * @return true if the function was generated, otherwise false if we ran * out of room in the block while building the function, in which * case the caller should simply try again */ bool FinishJit(struct Jit *jit, struct JitBlock *jb) { bool ok; u8 *addr; struct JitStage *js; unassert(jb->index > jb->start); unassert(jb->start >= jb->committed); // check if we lost race with page reset if (ShallNotPass(jb->pagegen, &jit->pagegen)) { return AbandonJit(jit, jb); } // align generated functions using breakpoint opcodes while (jb->index < kJitBlockSize && (jb->index & (kJitAlign - 1))) { unassert(AppendJitTrap(jb)); unassert(jb->index <= kJitBlockSize); } if (jb->index <= kJitBlockSize) { // function code was generated successfully if (jb->virt) { // since we have a hash table key we must install the hook JIP_LOGF("finishing jit path in block %p at %#" PRIx64, jb, jb->virt); if (CanJitForImmediateEffect()) { // operating system permits us to use rwx memory addr = jb->addr + jb->start; sys_icache_invalidate(addr, jb->index - jb->start); if (!UpdateJitHook(jit, jb, jb->virt, (uintptr_t)addr)) { // we lost race with another thread creating path at same addr return AbandonJit(jit, jb); } } else if ((js = NewJitStage())) { // updating hook must be deferred until we've filled system page // with code and then change its permission: mprotect(rwx -> rx) js->virt = jb->virt; js->start = jb->start; js->index = jb->index; js->pagegen = jb->pagegen; dll_make_last(&jb->staged, &js->elem); } } else { JIT_LOGF("finishing manual mode jit path in block %p", jb); } CommitJitJumps(jit, jb); // mark the generated jit memory as having been used // if there's only a tiny bit left we advance to end if (jb->index + kJitFit > kJitBlockSize) { JIT_LOGF("ending jit block %p due to pretty good fit", jb); STATISTIC(AVERAGE(jit_average_block, jb->index)); jb->index = kJitBlockSize; } jb->start = jb->index; ok = true; } else { // we ran out of jit memory in block while generating the function STATISTIC(++path_ooms); AbandonJitJumps(jb); if (jb->index - jb->start < (kJitBlockSize >> 1)) { // we ran out of block space when trying to create a path that's // shorter than half the maximum block size. in that case, abandon // the path. this will reset the hook on the initial path address. // hopefully the next time it's executed, there'll be enough room. JIT_LOGF("oom'd jit block %p at %#" PRIx64 " due to lack of room", jb, jb->virt); AbandonJitHook(jit, jb->virt); } else { // we ran out of block space trying to create a path that's very // long. it's possibly longer than the maximum block size. in that // case, just permanently leave the starting address in staging so // that we won't try to create this path again. JIT_LOGF("oom'd jit block %p at %#" PRIx64 " because long code is long", jb, jb->virt); } DiscardGeneratedJitCode(jb); ok = false; } unassert(jb->start == jb->index); CommitJit_(jit, jb); LockJit(jit); ReinsertJitBlock_(jit, jb); if (jb->index >= kJitBlockSize) { dll_make_first(&jit->freejumps, jb->freejumps); jb->freejumps = 0; } UnlockJit(jit); if (pthread_jit_write_protect_supported_np()) { pthread_jit_write_protect_np_workaround(true); } return ok; } /** * Abandons writing function definition to JIT memory. * * @param jb becomes owned by `jit` again after this call * @return always false */ bool AbandonJit(struct Jit *jit, struct JitBlock *jb) { JIT_LOGF("abandoning jit path in block %p at %#" PRIx64, jb, jb->virt); STATISTIC(++path_abandoned); AbandonJitJumps(jb); AbandonJitHook(jit, jb->virt); DiscardGeneratedJitCode(jb); LockJit(jit); ReinsertJitBlock_(jit, jb); UnlockJit(jit); if (pthread_jit_write_protect_supported_np()) { pthread_jit_write_protect_np_workaround(true); } return false; } /** * Appends NOPs until PC is aligned to `align`. * * @param align is byte alignment, which must be a two power */ bool AlignJit(struct JitBlock *jb, int align, int misalign) { unassert(align > 0 && IS2POW(align)); unassert(misalign >= 0 && misalign < align); while ((jb->index & (align - 1)) != misalign) { #ifdef __x86_64__ // Intel's Official Multibyte NOP Instructions // // 90 nop // 6690 xchg %ax,%ax // 0F1F00 nopl (%rax) // 0F1F4000 nopl 0x00(%rax) // 0f1f440000 nopl 0x00(%rax,%rax,1) // 660f1f440000 nopw 0x00(%rax,%rax,1) // 0F1F8000000000 nopl 0x00000000(%rax) // 0F1F840000000000 nopl 0x00000000(%rax,%rax,1) // 660F1F840000000000 nopw 0x00000000(%rax,%rax,1) // // See Intel's Six Thousand Page Manual, Volume 2, Table 4-12: // "Recommended Multi-Byte Sequence of NOP Instruction". static const u8 kNops[7][8] = { {1, 0x90}, {2, 0x66, 0x90}, {3, 0x0f, 0x1f, 0x00}, {4, 0x0f, 0x1f, 0x40, 0x00}, {5, 0x0f, 0x1f, 0x44, 0x00, 0x00}, {6, 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, {7, 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, }; int skew, need; skew = jb->index & (align - 1); if (skew > misalign) { need = align - skew + misalign; } else { need = misalign - skew; } if (!AppendJit(jb, kNops[MIN(7, need) - 1] + 1, kNops[MIN(7, need) - 1][0])) { return false; } #else if (!AppendJitNop(jb)) { return false; } #endif } unassert((jb->index & (align - 1)) == misalign); return true; } /** * Moves one register's value into another register. * * The `src` and `dst` register indices are architecture defined. * Predefined constants such as `kJitArg0` may be used to provide * register indices to this function in a portable way. * * @param dst is the index of the destination register * @param src is the index of the source register */ bool AppendJitMovReg(struct JitBlock *jb, int dst, int src) { long action; if (dst == src) return true; if (GetJitRemaining(jb) < 4) return OomJit(jb); if ((action = MOVE(dst, src)) == jb->lastaction) return true; #if defined(__x86_64__) unassert(!(dst & ~15)); unassert(!(src & ~15)); Write32(jb->addr + jb->index, ((kAmdRexw | (src & 8 ? kAmdRexr : 0) | (dst & 8 ? kAmdRexb : 0)) | 0x89 << 010 | (0300 | (src & 7) << 3 | (dst & 7)) << 020)); jb->index += 3; #elif defined(__aarch64__) // src target // ┌─┴─┐ ┌─┴─┐ // 0b10101010000000000000001111110011 mov x19, x0 // 0b10101010000000010000001111110100 mov x20, x1 // 0b10101010000101000000001111100001 mov x1, x20 // 0b10101010000100110000001111100000 mov x0, x19 unassert(!(dst & ~31)); unassert(!(src & ~31)); Put32(jb->addr + jb->index, 0xaa0003e0 | src << 16 | dst); jb->index += 4; #endif jb->lastaction = action; return true; } /** * Appends function call instruction to JIT memory. * * @param jb is function builder object returned by StartJit() * @param func points to another callee function in memory * @return true if room was available, otherwise false */ bool AppendJitCall(struct JitBlock *jb, void *func) { int n; intptr_t disp; uintptr_t addr; addr = (uintptr_t)func; #if defined(__x86_64__) u8 buf[5]; disp = addr - (GetJitPc(jb) + 5); if (kAmdDispMin <= disp && disp <= kAmdDispMax) { // AMD function calls are encoded using an 0xE8 byte, followed by a // 32-bit signed two's complement little-endian integer, containing // the relative location between the function being called, and the // instruction at the location that follows our 5 byte call opcode. buf[0] = kAmdCall; Write32(buf + 1, disp & kAmdDispMask); n = 5; } else { AppendJitSetReg(jb, kAmdAx, addr); buf[0] = kAmdCallAx[0]; buf[1] = kAmdCallAx[1]; n = 2; } #elif defined(__aarch64__) uint32_t buf[1]; // ARM function calls are encoded as: // // BL displacement // ┌─┴──┐┌────────────┴───────────┐ // 0b100101sddddddddddddddddddddddddd // // Where: // // - BL (0x94000000) is what ARM calls its CALL instruction // // - sddddddddddddddddddddddddd is a 26-bit two's complement integer // of how far away the function is that's being called. This is // measured in terms of instructions rather than bytes. Unlike AMD // the count here starts at the Program Counter (PC) address where // the BL INSN is stored, rather than the one that follows. // // Displacement is computed as such: // // INSN = BL | (((FUNC - PC) >> 2) & 0x03ffffffu) // // The inverse of the above operation is: // // FUNC = PC + ((i32)((u32)(INSN & 0x03ffffffu) << 6) >> 4) // disp = addr - GetJitPc(jb); disp >>= 2; unassert(kArmDispMin <= disp && disp <= kArmDispMax); buf[0] = kArmCall | (disp & kArmDispMask); n = 4; #endif return AppendJit(jb, buf, n); } /** * Appends unconditional branch instruction to JIT memory. * * @param jb is function builder object returned by StartJit() * @param code points to some other code address in memory * @return true if room was available, otherwise false */ bool AppendJitJump(struct JitBlock *jb, void *code) { u8 buf[5]; int n = MakeJitJump(buf, GetJitPc(jb), (uintptr_t)code); return AppendJit(jb, buf, n); } /** * Sets register to immediate value. * * @param jb is function builder object returned by StartJit() * @param param is the zero-based index into the register file * @param value is the constant value to use as the parameter * @return true if room was available, otherwise false */ bool AppendJitSetReg(struct JitBlock *jb, int reg, u64 value) { long lastaction; #if defined(__x86_64__) u8 rex = 0; if (GetJitRemaining(jb) < 10) return OomJit(jb); if (reg & 8) rex |= kAmdRexb; if (!value) { if (reg & 8) rex |= kAmdRexr; if (rex) jb->addr[jb->index++] = rex; jb->addr[jb->index++] = kAmdXor; jb->addr[jb->index++] = 0300 | (reg & 7) << 3 | (reg & 7); } else if ((i64)value < 0 && (i64)value >= INT32_MIN) { jb->addr[jb->index++] = rex | kAmdRexw; jb->addr[jb->index++] = 0xC7; jb->addr[jb->index++] = 0300 | (reg & 7); Write32(jb->addr + jb->index, value); jb->index += 4; } else { if (value > 0xffffffff) rex |= kAmdRexw; if (rex) jb->addr[jb->index++] = rex; jb->addr[jb->index++] = kAmdMovImm | (reg & 7); if ((rex & kAmdRexw) != kAmdRexw) { Write32(jb->addr + jb->index, value); jb->index += 4; } else { Write64(jb->addr + jb->index, value); jb->index += 8; } } #elif defined(__aarch64__) // ARM immediate moves are encoded as: // // ┌64-bit // │ // │┌{sign,???,zero,non}-extending // ││ // ││ ┌short[4] index // ││ │ // ││ MOV │ immediate register // │├┐┌─┴──┐├┐┌──────┴───────┐┌─┴─┐ // 0bmxx100101iivvvvvvvvvvvvvvvvrrrrr // // Which allows 16 bits to be loaded into a register at a time, with // tricks for clearing other parts of the register. For example, the // sign-extending mode will set the higher order shorts to all ones, // and it expects the immediate to be encoded using ones' complement u32 op; u32 *p; int i, n = 0; unassert(!(reg & ~kArmRegMask)); if (GetJitRemaining(jb) < 16) return OomJit(jb); p = (u32 *)(jb->addr + jb->index); // TODO: This could be improved some more. if ((i64)value < 0 && (i64)value >= -0x8000) { p[n++] = kArmMovSex | ~value << kArmImmOff | reg << kArmRegOff; } else { i = 0; op = kArmMovZex; while (value && !(value & 0xffff)) { value >>= 16; ++i; } do { op |= (value & 0xffff) << kArmImmOff; op |= reg << kArmRegOff; op |= i++ << kArmIdxOff; p[n++] = op; op = kArmMovNex; } while ((value >>= 16)); } jb->index += n * 4; #endif lastaction = jb->lastaction; if (ACTION(lastaction) == ACTION_MOVE && // MOVE_DST(lastaction) != reg && // MOVE_SRC(lastaction) != reg) { jb->lastaction = lastaction; } return true; } /** * Appends return instruction. */ bool AppendJitRet(struct JitBlock *jb) { #if defined(__x86_64__) u8 buf[1] = {0xc3}; #elif defined(__aarch64__) u32 buf[1] = {0xd65f03c0}; #endif return AppendJit(jb, buf, sizeof(buf)); } /** * Appends no-op instruction. */ bool AppendJitNop(struct JitBlock *jb) { #if defined(__x86_64__) u8 buf[1] = {0x90}; // nop #elif defined(__aarch64__) u32 buf[1] = {0xd503201f}; // nop #endif return AppendJit(jb, buf, sizeof(buf)); } /** * Appends pause instruction. */ bool AppendJitPause(struct JitBlock *jb) { #if defined(__x86_64__) u8 buf[2] = {0xf3, 0x90}; // pause #elif defined(__aarch64__) u32 buf[1] = {0xd503203f}; // yield #endif return AppendJit(jb, buf, sizeof(buf)); } /** * Appends debugger breakpoint. */ bool AppendJitTrap(struct JitBlock *jb) { #if defined(__x86_64__) u8 buf[1] = {0xcc}; // int3 #elif defined(__aarch64__) u32 buf[1] = {0xd4207d00}; // brk #0x3e8 #endif return AppendJit(jb, buf, sizeof(buf)); } #endif /* HAVE_JIT */ ================================================ FILE: blink/jit.h ================================================ #ifndef BLINK_JIT_H_ #define BLINK_JIT_H_ #include #include #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/dll.h" #include "blink/thread.h" #include "blink/tunables.h" #include "blink/types.h" #define kJitFit 1000 #define kJitDepth 16 #define kJitAlign 16 #define kJitJumpTries 16 #define kJitBlockSize 262144 #define kJitMemorySize 32505856 #define kJitRetireQueue (int)(kJitMemorySize / kJitBlockSize * .10) #define kJitSlabInts (65536 / sizeof(struct JitInts)) #define kJitInitialHooks 16384 #define kJitInitialEdges 4096 #ifdef __x86_64__ #define kJitRes0 kAmdAx #define kJitRes1 kAmdDx #ifdef __CYGWIN__ #define kJitArg0 kAmdCx #define kJitArg1 kAmdDx #define kJitArg2 8 #define kJitArg3 9 #else #define kJitArg0 kAmdDi #define kJitArg1 kAmdSi #define kJitArg2 kAmdDx #define kJitArg3 kAmdCx #endif #define kJitSav0 kAmdBx #define kJitSav1 12 #define kJitSav2 13 #define kJitSav3 14 #define kJitSav4 15 #else #define kJitRes0 0 #define kJitRes1 1 #define kJitArg0 0 #define kJitArg1 1 #define kJitArg2 2 #define kJitArg3 3 #define kJitSav0 19 #define kJitSav1 20 #define kJitSav2 21 #define kJitSav3 22 #define kJitSav4 23 #endif #ifdef __x86_64__ #define kAmdXor 0x31 #define kAmdRet 0xc3 #define kAmdJmp 0xe9 #define kAmdCall 0xe8 #define kAmdJmpAx "\377\340" #define kAmdCallAx "\377\320" #define kAmdDispMin INT32_MIN #define kAmdDispMax INT32_MAX #define kAmdDispMask 0xffffffffu #define kAmdRex 0x40 // turns ah/ch/dh/bh into spl/bpl/sil/dil #define kAmdRexb 0x41 // turns 0007 (r/m) of modrm into r8..r15 #define kAmdRexr 0x44 // turns 0070 (reg) of modrm into r8..r15 #define kAmdRexw 0x48 // makes register 64-bit #define kAmdAx 0 // first function result #define kAmdCx 1 // third function parameter #define kAmdDx 2 // fourth function parameter, second result #define kAmdBx 3 // generic saved register #define kAmdSp 4 // stack pointer #define kAmdBp 5 // backtrace pointer #define kAmdSi 6 // second function parameter #define kAmdDi 7 // first function parameter #define kAmdWord 1 // turns `op Eb,Gb` into `op Evqp,Gvqp` #define kAmdFlip 2 // turns `op r/m,r` into `op r,r/m` #define kAmdModrmRdiDisp8 0107 // ModR/M [-128,127](%rdi) #define kAmdMovImm 0xb8 // or'd with register, imm size is same as reg #define kAmdMov 0x88 // may be or'd with kAmdWord, kAmdFlip #endif #ifdef __aarch64__ #define kArmJmp 0x14000000u // B #define kArmCall 0x94000000u // BL #define kArmRet 0xd65f03c0u // RET #define kArmMovNex 0xf2800000u // sets sub-word of register to immediate #define kArmMovZex 0xd2800000u // load immediate into reg w/ zero-extend #define kArmMovSex 0x92800000u // load 1's complement imm w/ sign-extend #define kArmAdr 0x10000000u // form PC-relative byte address #define kArmAdrp 0x90000000u // form PC-relative page address #define kArmLdrPc \ 0x18000000u // load PC-relative memory into register // (general or SIMD) #define kArmLdrswPc 0x98000000u // load PC-relative short w/ sign-extend #define kArmPrfmPc 0xd8000000u // prefetch PC-relative memory #define kArmDispMin -33554432 // can jump -2**25 ints backward #define kArmDispMax +33554431 // can jump +2**25-1 ints forward #define kArmDispMask 0x03ffffffu // mask of branch displacement #define kArmRegOff 0 // bit offset of destination register #define kArmRegMask 0x0000001fu // mask of destination register #define kArmImmOff 5 // bit offset of mov immediate value #define kArmImmMask 0x001fffe0u // bit offset of mov immediate value #define kArmImmMax 0xffffu // maximum immediate value per instruction #define kArmIdxOff 21 // bit offset of u16[4] sub-word index #define kArmIdxMask 0x00600000u // mask of u16[4] sub-word index #define kArmAdrMask 0x9f000000u // mask of ADR opcode #define kArmAdrpMask 0x9f000000u // mask of ADRP opcode #define kArmLdrPcMask 0xbb000000u // mask of PC-relative LDR opcodes #define kArmLdrswPcMask 0xff000000u // mask of PC-relative LDRSW opcode #define kArmPrfmPcMask 0xff000000u // mask of PC-relative PRFM opcode #endif #define JITJUMP_CONTAINER(e) DLL_CONTAINER(struct JitJump, elem, e) #define JITPAGE_CONTAINER(e) DLL_CONTAINER(struct JitPage, elem, e) #define JITSTAGE_CONTAINER(e) DLL_CONTAINER(struct JitStage, elem, e) #define JITBLOCK_CONTAINER(e) DLL_CONTAINER(struct JitBlock, elem, e) #define JITFREED_CONTAINER(e) DLL_CONTAINER(struct JitFreed, elem, e) #define AGEDBLOCK_CONTAINER(e) DLL_CONTAINER(struct JitBlock, aged, e) #define JIASLAB_CONTAINER(e) DLL_CONTAINER(struct JitIntsSlab, elem, e) struct JitInts { int i, n; i64 *p, m[2]; }; struct JitIntsSlab { int i; struct Dll elem; struct JitInts p[kJitSlabInts]; }; struct JitIntsAllocator { int i, n; struct JitInts **p; struct Dll *slabs; }; struct JitEdges { int i, n; i64 *src; struct JitInts **dst; struct JitIntsAllocator jia; }; struct JitJump { u8 *code; u64 virt; int tries; int addend; struct Dll elem; }; struct JitStage { long start; long index; u64 virt; unsigned pagegen; struct Dll elem; }; struct JitFreed { void *data; size_t size; struct Dll elem; }; struct JitFreeds { int n; struct Dll *p; struct Dll *f; }; struct JitPage { i64 page; u64 bitset; struct Dll elem; }; struct JitBlock { u8 *addr; i64 virt; long start; long index; long committed; long lastaction; bool wasretired; bool isprotected; unsigned pagegen; struct Dll elem; struct Dll aged; struct Dll *jumps; struct Dll *staged; struct Dll *freejumps; }; struct JitHooks { unsigned i; _Atomic(unsigned) n; _Atomic(_Atomic(int) *) funcs; _Atomic(_Atomic(uintptr_t) *) virts; }; struct Jit { int staging; bool threaded; _Atomic(bool) disabled; struct JitHooks hooks; struct JitEdges edges; struct JitEdges redges; struct JitFreeds freeds; struct Dll *agedblocks; struct Dll *blocks; struct Dll *jumps; struct Dll *freejumps; struct Dll *pages; pthread_mutex_t_ lock; _Atomic(unsigned) keygen; _Atomic(unsigned) pagegen; }; extern const u8 kJitRes[2]; extern const u8 kJitSav[5]; extern const u8 kJitArg[4]; int ShutdownJit(void); int EnableJit(struct Jit *); int DisableJit(struct Jit *); int DestroyJit(struct Jit *); int FixJitProtection(struct Jit *); int InitJit(struct Jit *, uintptr_t); bool CanJitForImmediateEffect(void) nosideeffect; bool AppendJit(struct JitBlock *, const void *, long); bool AbandonJit(struct Jit *, struct JitBlock *); int FlushJit(struct Jit *); struct JitBlock *StartJit(struct Jit *, i64); bool AlignJit(struct JitBlock *, int, int); bool AppendJitRet(struct JitBlock *); bool AppendJitNop(struct JitBlock *); bool AppendJitPause(struct JitBlock *); bool AppendJitTrap(struct JitBlock *); bool AppendJitJump(struct JitBlock *, void *); bool AppendJitCall(struct JitBlock *, void *); bool AppendJitSetReg(struct JitBlock *, int, u64); bool AppendJitMovReg(struct JitBlock *, int, int); bool FinishJit(struct Jit *, struct JitBlock *); bool RecordJitJump(struct JitBlock *, u64, int); bool RecordJitEdge(struct Jit *, i64, i64); uintptr_t GetJitHook(struct Jit *, u64); int ResetJitPage(struct Jit *, i64); int CommitJit_(struct Jit *, struct JitBlock *); void ReinsertJitBlock_(struct Jit *, struct JitBlock *); /** * Returns number of bytes of space remaining in JIT memory block. * * @return number of bytes of space that can be appended into, or -1 if * if an append operation previously failed due to lack of space */ static inline long GetJitRemaining(const struct JitBlock *jb) { return kJitBlockSize - jb->index; } /** * Returns current program counter or instruction pointer of JIT block. * * @return absolute instruction pointer memory address in bytes */ static inline uintptr_t GetJitPc(const struct JitBlock *jb) { return (uintptr_t)jb->addr + jb->index; } /** * Returns true if DisableJit() was called or AcquireJit() had failed. */ static inline bool IsJitDisabled(const struct Jit *jit) { #ifdef HAVE_JIT return atomic_load_explicit(&jit->disabled, memory_order_acquire); #else return true; #endif } #endif /* BLINK_JIT_H_ */ ================================================ FILE: blink/jitflush.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/dll.h" #include "blink/flag.h" #include "blink/jit.h" #include "blink/macros.h" #include "blink/thread.h" /** * Forces activation of committed JIT chunks. * * Normally JIT chunks become active and have their function pointer * hook updated automatically once the system block fills up with jit * code. In some cases, such as unit tests, it's necessary to ensure * that JIT code goes live sooner. The tradeoff of flushing is it'll * lead to wasted memory and less performance, due to the additional * mprotect() system call overhead. */ int FlushJit(struct Jit *jit) { int count = 0; struct Dll *e; struct JitBlock *jb; struct JitStage *js; if (!CanJitForImmediateEffect()) { LOCK(&jit->lock); StartOver: for (e = dll_first(jit->blocks); e; e = dll_next(jit->blocks, e)) { jb = JITBLOCK_CONTAINER(e); if (jb->start >= kJitBlockSize) break; if (!dll_is_empty(jb->staged)) { dll_remove(&jit->blocks, e); UNLOCK(&jit->lock); js = JITSTAGE_CONTAINER(dll_last(jb->staged)); jb->start = ROUNDUP(js->index, FLAG_pagesize); jb->index = jb->start; count += CommitJit_(jit, jb); ReinsertJitBlock_(jit, jb); LOCK(&jit->lock); goto StartOver; } } UNLOCK(&jit->lock); } return count; } ================================================ FILE: blink/ldbl.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/ldbl.h" #include "blink/endian.h" #include "blink/macros.h" #include "blink/pun.h" u8 *SerializeLdbl(u8 b[10], double f) { int e; union DoublePun u = {f}; e = (u.i >> 52) & 0x7ff; if (!e) { e = 0; } else if (e == 0x7ff) { e = 0x7fff; } else { e -= 0x3ff; e += 0x3fff; } Write16(b + 8, e | u.i >> 63 << 15); Write64(b, (u.i & 0x000fffffffffffff) << 11 | (u64) !!u.f << 63); return b; } double DeserializeLdbl(const u8 b[10]) { union DoublePun u; u.i = (u64)(MAX(-1023, MIN(1024, ((Read16(b + 8) & 0x7fff) - 0x3fff))) + 1023) << 52 | ((Read64(b) & 0x7fffffffffffffff) + (1 << (11 - 1))) >> 11 | (u64)(b[9] >> 7) << 63; return u.f; } ================================================ FILE: blink/ldbl.h ================================================ #ifndef BLINK_LDBL_H_ #define BLINK_LDBL_H_ #include "blink/types.h" double DeserializeLdbl(const u8[10]); u8 *SerializeLdbl(u8[10], double); #endif /* BLINK_LDBL_H_ */ ================================================ FILE: blink/legacy.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/alu.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/x86.h" #ifndef DISABLE_METAL relegated void OpIncZv(P) { if (!Osz(rde)) { Put32(RegSrm(m, rde), Inc32(m, Get32(RegSrm(m, rde)), 0)); } else { Put16(RegSrm(m, rde), Inc16(m, Get16(RegSrm(m, rde)), 0)); } } relegated void OpDecZv(P) { if (!Osz(rde)) { Put32(RegSrm(m, rde), Dec32(m, Get32(RegSrm(m, rde)), 0)); } else { Put16(RegSrm(m, rde), Dec16(m, Get16(RegSrm(m, rde)), 0)); } } static relegated void PushaCommon(struct Machine *m, void *b, size_t n) { u32 v; switch (m->mode.omode) { case XED_MODE_REAL: Put16(m->sp, (v = (Get16(m->sp) - n) & 0xffff)); break; case XED_MODE_LEGACY: Put64(m->sp, (v = (Get32(m->sp) - n) & 0xffffffff)); break; default: __builtin_unreachable(); } CopyToUser(m, m->ss.base + v, b, n); } static relegated void Pushaw(P) { u8 b[8][2]; memcpy(b[0], m->di, 2); memcpy(b[1], m->si, 2); memcpy(b[2], m->bp, 2); memcpy(b[3], m->sp, 2); memcpy(b[4], m->bx, 2); memcpy(b[5], m->dx, 2); memcpy(b[6], m->cx, 2); memcpy(b[7], m->ax, 2); PushaCommon(m, b, sizeof(b)); } static relegated void Pushad(P) { u8 b[8][4]; memcpy(b[0], m->di, 4); memcpy(b[1], m->si, 4); memcpy(b[2], m->bp, 4); memcpy(b[3], m->sp, 4); memcpy(b[4], m->bx, 4); memcpy(b[5], m->dx, 4); memcpy(b[6], m->cx, 4); memcpy(b[7], m->ax, 4); PushaCommon(m, b, sizeof(b)); } static relegated void PopaCommon(struct Machine *m, void *b, size_t n) { u64 addr; switch (m->mode.omode) { case XED_MODE_REAL: addr = m->ss.base + Read16(m->sp); if (CopyFromUser(m, b, addr, n) == -1) { ThrowSegmentationFault(m, addr); } Put16(m->sp, (Get16(m->sp) + n) & 0xffff); break; case XED_MODE_LEGACY: addr = m->ss.base + Read32(m->sp); if (CopyFromUser(m, b, addr, n) == -1) { ThrowSegmentationFault(m, addr); } Put64(m->sp, (Get32(m->sp) + n) & 0xffffffff); break; default: __builtin_unreachable(); } } static relegated void Popaw(P) { u8 b[8][2]; PopaCommon(m, b, sizeof(b)); memcpy(m->di, b[0], 2); memcpy(m->si, b[1], 2); memcpy(m->bp, b[2], 2); memcpy(m->bx, b[4], 2); memcpy(m->dx, b[5], 2); memcpy(m->cx, b[6], 2); memcpy(m->ax, b[7], 2); } static relegated void Popad(P) { u8 b[8][4]; PopaCommon(m, b, sizeof(b)); memcpy(m->di, b[0], 4); memcpy(m->si, b[1], 4); memcpy(m->bp, b[2], 4); memcpy(m->bx, b[4], 4); memcpy(m->dx, b[5], 4); memcpy(m->cx, b[6], 4); memcpy(m->ax, b[7], 4); } relegated void OpPusha(P) { switch (m->mode.omode) { case XED_MODE_REAL: case XED_MODE_LEGACY: if (Osz(rde)) { Pushaw(A); } else { Pushad(A); } break; case XED_MODE_LONG: OpUdImpl(m); default: __builtin_unreachable(); } } relegated void OpPopa(P) { switch (m->mode.omode) { case XED_MODE_REAL: case XED_MODE_LEGACY: if (Osz(rde)) { Popaw(A); } else { Popad(A); } break; case XED_MODE_LONG: OpUdImpl(m); default: __builtin_unreachable(); } } relegated void OpCallf(P) { Push(A, m->cs.sel); Push(A, m->ip); LongBranch(A, uimm0, disp & (Osz(rde) ? 0xffff : 0xffffffff)); } relegated void OpRetf(P) { u64 ip = Pop(A, 0); u16 cs = Pop(A, uimm0); LongBranch(A, cs, ip); } #endif /* DISABLE_METAL */ ================================================ FILE: blink/likely.h ================================================ #ifndef BLINK_LIKELY_H_ #define BLINK_LIKELY_H_ #include "blink/builtin.h" #define LIKELY(x) __builtin_expect(!!(x), 1) #define UNLIKELY(x) __builtin_expect(!!(x), 0) #if __GNUC__ + 0 >= 9 && !defined(__chibicc__) #define VERY_LIKELY(x) __builtin_expect_with_probability(!!(x), 1, 0.999) #else #define VERY_LIKELY(x) LIKELY(x) #endif #if __GNUC__ + 0 >= 9 && !defined(__chibicc__) #define VERY_UNLIKELY(x) __builtin_expect_with_probability(!!(x), 0, 0.999) #else #define VERY_UNLIKELY(x) UNLIKELY(x) #endif #endif /* BLINK_LIKELY_H_ */ ================================================ FILE: blink/limits.h ================================================ #ifndef BLINK_LIMITS_H_ #define BLINK_LIMITS_H_ #include #include #include #define NUMERIC_MAX(t) \ (((t) ~(t)0) > 1 ? (t) ~(t)0 \ : (t)((((uintmax_t)1) << (sizeof(t) * CHAR_BIT - 1)) - 1)) static inline long GetIovMax(void) { #ifdef IOV_MAX return IOV_MAX; #elif defined(_SC_IOV_MAX) return sysconf(_SC_IOV_MAX); #elif defined(_XOPEN_IOV_MAX) return _XOPEN_IOV_MAX; #else return 16; #endif } static inline long GetSymloopMax(void) { #ifdef SYMLOOP_MAX return SYMLOOP_MAX; #elif defined(_SC_SYMLOOP_MAX) return sysconf(_SC_SYMLOOP_MAX); #elif defined(_POSIX_SYMLOOP_MAX) return _POSIX_SYMLOOP_MAX; #else return 8; #endif } #endif /* BLINK_LIMITS_H_ */ ================================================ FILE: blink/lines.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/lines.h" #include #include #include "blink/builtin.h" struct Lines *NewLines(void) { return (struct Lines *)calloc(1, sizeof(struct Lines)); } void FreeLines(struct Lines *lines) { size_t i; for (i = 0; i < lines->n; ++i) { free(lines->p[i]); } free(lines->p); free(lines); } void AppendLine(struct Lines *lines, const char *s, int n) { if (n < 0) n = strlen(s); lines->p = (char **)realloc(lines->p, ++lines->n * sizeof(*lines->p)); lines->p[lines->n - 1] = strndup(s, n); } void AppendLines(struct Lines *lines, const char *s) { const char *p; for (;;) { p = strchr(s, '\n'); if (p) { AppendLine(lines, s, p - s); s = p + 1; } else { if (*s) { AppendLine(lines, s, -1); } break; } } } ================================================ FILE: blink/lines.h ================================================ #ifndef BLINK_LINES_H_ #define BLINK_LINES_H_ #include struct Lines { size_t n; char **p; }; struct Lines *NewLines(void); void FreeLines(struct Lines *); void AppendLine(struct Lines *, const char *, int); void AppendLines(struct Lines *, const char *); #endif /* BLINK_LINES_H_ */ ================================================ FILE: blink/linux.h ================================================ #ifndef BLINK_LINUX_H_ #define BLINK_LINUX_H_ #include "blink/types.h" #define EPERM_LINUX 1 #define ENOENT_LINUX 2 #define ESRCH_LINUX 3 #define EINTR_LINUX 4 #define EIO_LINUX 5 #define ENXIO_LINUX 6 #define E2BIG_LINUX 7 #define ENOEXEC_LINUX 8 #define EBADF_LINUX 9 #define ECHILD_LINUX 10 #define EAGAIN_LINUX 11 #define ENOMEM_LINUX 12 #define EACCES_LINUX 13 #define EFAULT_LINUX 14 #define ENOTBLK_LINUX 15 #define EBUSY_LINUX 16 #define EEXIST_LINUX 17 #define EXDEV_LINUX 18 #define ENODEV_LINUX 19 #define ENOTDIR_LINUX 20 #define EISDIR_LINUX 21 #define EINVAL_LINUX 22 #define ENFILE_LINUX 23 #define EMFILE_LINUX 24 #define ENOTTY_LINUX 25 #define ETXTBSY_LINUX 26 #define EFBIG_LINUX 27 #define ENOSPC_LINUX 28 #define ESPIPE_LINUX 29 #define EROFS_LINUX 30 #define EMLINK_LINUX 31 #define EPIPE_LINUX 32 #define EDOM_LINUX 33 #define ERANGE_LINUX 34 #define EDEADLK_LINUX 35 #define ENAMETOOLONG_LINUX 36 #define ENOLCK_LINUX 37 #define ENOSYS_LINUX 38 #define ENOTEMPTY_LINUX 39 #define ELOOP_LINUX 40 #define ENOMSG_LINUX 42 #define EIDRM_LINUX 43 #define ENOSTR_LINUX 60 #define ENODATA_LINUX 61 #define ETIME_LINUX 62 #define ENOSR_LINUX 63 #define ENONET_LINUX 64 #define EREMOTE_LINUX 66 #define ENOLINK_LINUX 67 #define EPROTO_LINUX 71 #define EMULTIHOP_LINUX 72 #define EBADMSG_LINUX 74 #define EOVERFLOW_LINUX 75 #define EBADFD_LINUX 77 #define EILSEQ_LINUX 84 #define ERESTART_LINUX 85 #define EUSERS_LINUX 87 #define ENOTSOCK_LINUX 88 #define EDESTADDRREQ_LINUX 89 #define EMSGSIZE_LINUX 90 #define EPROTOTYPE_LINUX 91 #define ENOPROTOOPT_LINUX 92 #define EPROTONOSUPPORT_LINUX 93 #define ESOCKTNOSUPPORT_LINUX 94 #define ENOTSUP_LINUX 95 #define EOPNOTSUPP_LINUX 95 #define EPFNOSUPPORT_LINUX 96 #define EAFNOSUPPORT_LINUX 97 #define EADDRINUSE_LINUX 98 #define EADDRNOTAVAIL_LINUX 99 #define ENETDOWN_LINUX 100 #define ENETUNREACH_LINUX 101 #define ENETRESET_LINUX 102 #define ECONNABORTED_LINUX 103 #define ECONNRESET_LINUX 104 #define ENOBUFS_LINUX 105 #define EISCONN_LINUX 106 #define ENOTCONN_LINUX 107 #define ESHUTDOWN_LINUX 108 #define ETOOMANYREFS_LINUX 109 #define ETIMEDOUT_LINUX 110 #define ECONNREFUSED_LINUX 111 #define EHOSTDOWN_LINUX 112 #define EHOSTUNREACH_LINUX 113 #define EALREADY_LINUX 114 #define EINPROGRESS_LINUX 115 #define ESTALE_LINUX 116 #define EDQUOT_LINUX 122 #define ENOMEDIUM_LINUX 123 #define EMEDIUMTYPE_LINUX 124 #define ECANCELED_LINUX 125 #define EOWNERDEAD_LINUX 130 #define ENOTRECOVERABLE_LINUX 131 #define ERFKILL_LINUX 132 #define EHWPOISON_LINUX 133 #define AT_FDCWD_LINUX -100 #define AT_SYMLINK_NOFOLLOW_LINUX 0x0100 #define AT_REMOVEDIR_LINUX 0x0200 #define AT_EACCESS_LINUX 0x0200 #define AT_SYMLINK_FOLLOW_LINUX 0x0400 #define AT_NO_AUTOMOUNT_LINUX 0x0800 #define AT_EMPTY_PATH_LINUX 0x1000 #define O_RDONLY_LINUX 0 #define O_WRONLY_LINUX 1 #define O_RDWR_LINUX 2 #define O_ACCMODE_LINUX 3 #define O_APPEND_LINUX 0x000400 #define O_CREAT_LINUX 0x000040 #define O_EXCL_LINUX 0x000080 #define O_TRUNC_LINUX 0x000200 #define O_NDELAY_LINUX 0x000800 #define O_DIRECT_LINUX 0x004000 #define O_DIRECTORY_LINUX 0x010000 #define __O_TMPFILE_LINUX 0x400000 #define O_TMPFILE_LINUX (__O_TMPFILE_LINUX | O_DIRECTORY_LINUX) #define O_NOFOLLOW_LINUX 0x020000 #define O_CLOEXEC_LINUX 0x080000 #define O_NOCTTY_LINUX 0x000100 #define O_ASYNC_LINUX 0x002000 #define O_NOATIME_LINUX 0x040000 #define O_PATH_LINUX 0x200000 #define O_LARGEFILE_LINUX 0x008000 #define O_DSYNC_LINUX 0x001000 #define __O_SYNC_LINUX 0x100000 #define O_SYNC_LINUX (__O_SYNC_LINUX | O_DSYNC_LINUX) #define F_DUPFD_LINUX 0 #define F_DUPFD_CLOEXEC_LINUX 0x0406 #define F_GETFD_LINUX 1 #define F_SETFD_LINUX 2 #define FD_CLOEXEC_LINUX 1 #define F_GETFL_LINUX 3 #define F_SETFL_LINUX 4 #define F_GETLK_LINUX 5 #define F_SETLK_LINUX 6 #define F_SETLKW_LINUX 7 #define F_RDLCK_LINUX 0 #define F_WRLCK_LINUX 1 #define F_UNLCK_LINUX 2 #define F_SETSIG_LINUX 10 #define F_GETSIG_LINUX 11 #define F_SETOWN_LINUX 8 #define F_GETOWN_LINUX 9 #define F_SETOWN_EX_LINUX 15 #define F_GETOWN_EX_LINUX 16 #define F_GETOWNER_UIDS_LINUX 17 #define F_OWNER_TID_LINUX 0 #define F_OWNER_PID_LINUX 1 #define F_OWNER_PGRP_LINUX 2 #define SOCK_CLOEXEC_LINUX O_CLOEXEC_LINUX #define SOCK_NONBLOCK_LINUX O_NDELAY_LINUX #define TIOCGWINSZ_LINUX 0x5413 #define TIOCSWINSZ_LINUX 0x5414 #define TCGETS_LINUX 0x5401 #define TCSETS_LINUX 0x5402 #define TCSETSW_LINUX 0x5403 #define TCSETSF_LINUX 0x5404 #define TIOCGPGRP_LINUX 0x540f #define TIOCSPGRP_LINUX 0x5410 #define ARCH_SET_GS_LINUX 0x1001 #define ARCH_SET_FS_LINUX 0x1002 #define ARCH_GET_FS_LINUX 0x1003 #define ARCH_GET_GS_LINUX 0x1004 #define ARCH_GET_CPUID_LINUX 0x1011 #define ARCH_SET_CPUID_LINUX 0x1012 #define O_CLOEXEC_LINUX 0x080000 #define POLLIN_LINUX 0x01 #define POLLPRI_LINUX 0x02 #define POLLOUT_LINUX 0x04 #define POLLERR_LINUX 0x08 #define POLLHUP_LINUX 0x10 #define POLLNVAL_LINUX 0x20 #define TIMER_ABSTIME_LINUX 0x01 #define MAP_TYPE_LINUX 0x0000000f #define MAP_FILE_LINUX 0x00000000 #define MAP_SHARED_LINUX 0x00000001 #define MAP_PRIVATE_LINUX 0x00000002 #define MAP_FIXED_LINUX 0x00000010 #define MAP_ANONYMOUS_LINUX 0x00000020 #define MAP_GROWSDOWN_LINUX 0x00000100 #define MAP_NORESERVE_LINUX 0x00004000 #define MAP_POPULATE_LINUX 0x00008000 #define MAP_NONBLOCK_LINUX 0x00010000 #define MAP_STACK_LINUX 0x00020000 #define MAP_HUGETLB_LINUX 0x00040000 #define MAP_SYNC_LINUX 0x00080000 #define MAP_FIXED_NOREPLACE_LINUX 0x00100000 #define MAP_UNINITIALIZED_LINUX 0x04000000 #define PROT_NONE_LINUX 0 #define PROT_READ_LINUX 1 #define PROT_WRITE_LINUX 2 #define PROT_EXEC_LINUX 4 #define PROT_SEM_LINUX 8 #define PROT_GROWSDOWN_LINUX 0x01000000 #define PROT_GROWSUP_LINUX 0x02000000 #define CLONE_VM_LINUX 0x00000100 #define CLONE_THREAD_LINUX 0x00010000 #define CLONE_FS_LINUX 0x00000200 #define CLONE_FILES_LINUX 0x00000400 #define CLONE_SIGHAND_LINUX 0x00000800 #define CLONE_VFORK_LINUX 0x00004000 #define CLONE_SYSVSEM_LINUX 0x00040000 #define CLONE_SETTLS_LINUX 0x00080000 #define CLONE_PARENT_SETTID_LINUX 0x00100000 #define CLONE_CHILD_CLEARTID_LINUX 0x00200000 #define CLONE_DETACHED_LINUX 0x00400000 #define CLONE_CHILD_SETTID_LINUX 0x01000000 #define CLONE_NEWCGROUP_LINUX 0x02000000 #define CLONE_NEWUTS_LINUX 0x04000000 #define CLONE_NEWIPC_LINUX 0x08000000 #define CLONE_NEWUSER_LINUX 0x10000000 #define CLONE_NEWPID_LINUX 0x20000000 #define CLONE_NEWNET_LINUX 0x40000000 #define CLONE_IO_LINUX 0x80000000 #define FUTEX_WAIT_LINUX 0 #define FUTEX_WAKE_LINUX 1 #define FUTEX_WAIT_BITSET_LINUX 9 #define FUTEX_PRIVATE_FLAG_LINUX 128 #define FUTEX_CLOCK_REALTIME_LINUX 256 #define DT_UNKNOWN_LINUX 0 #define DT_FIFO_LINUX 1 #define DT_CHR_LINUX 2 #define DT_DIR_LINUX 4 #define DT_BLK_LINUX 6 #define DT_REG_LINUX 8 #define DT_LNK_LINUX 10 #define DT_SOCK_LINUX 12 #define SEEK_SET_LINUX 0 #define SEEK_CUR_LINUX 1 #define SEEK_END_LINUX 2 #define F_OK_LINUX 0 #define X_OK_LINUX 1 #define W_OK_LINUX 2 #define R_OK_LINUX 4 #define SHUT_RD_LINUX 0 #define SHUT_WR_LINUX 1 #define SHUT_RDWR_LINUX 2 #define SIG_DFL_LINUX 0 #define SIG_IGN_LINUX 1 #define SIG_BLOCK_LINUX 0 #define SIG_UNBLOCK_LINUX 1 #define SIG_SETMASK_LINUX 2 #define SIGHUP_LINUX 1 #define SIGINT_LINUX 2 #define SIGQUIT_LINUX 3 #define SIGILL_LINUX 4 #define SIGTRAP_LINUX 5 #define SIGABRT_LINUX 6 #define SIGBUS_LINUX 7 #define SIGFPE_LINUX 8 #define SIGKILL_LINUX 9 #define SIGUSR1_LINUX 10 #define SIGSEGV_LINUX 11 #define SIGUSR2_LINUX 12 #define SIGPIPE_LINUX 13 #define SIGALRM_LINUX 14 #define SIGTERM_LINUX 15 #define SIGSTKFLT_LINUX 16 #define SIGCHLD_LINUX 17 #define SIGCONT_LINUX 18 #define SIGSTOP_LINUX 19 #define SIGTSTP_LINUX 20 #define SIGTTIN_LINUX 21 #define SIGTTOU_LINUX 22 #define SIGURG_LINUX 23 #define SIGXCPU_LINUX 24 #define SIGXFSZ_LINUX 25 #define SIGVTALRM_LINUX 26 #define SIGPROF_LINUX 27 #define SIGWINCH_LINUX 28 #define SIGIO_LINUX 29 #define SIGSYS_LINUX 31 #define SIGINFO_LINUX 63 #define SIGEMT_LINUX 64 #define SIGPWR_LINUX 30 #define SIGTHR_LINUX 32 #define SIGRTMIN_LINUX 32 #define SIGRTMAX_LINUX 64 #define AT_NULL_LINUX 0 #define AT_IGNORE_LINUX 1 #define AT_EXECFD_LINUX 2 #define AT_PHDR_LINUX 3 #define AT_PHENT_LINUX 4 #define AT_PHNUM_LINUX 5 #define AT_PAGESZ_LINUX 6 #define AT_BASE_LINUX 7 #define AT_FLAGS_LINUX 8 #define AT_ENTRY_LINUX 9 #define AT_NOTELF_LINUX 10 #define AT_UID_LINUX 11 #define AT_EUID_LINUX 12 #define AT_GID_LINUX 13 #define AT_EGID_LINUX 14 #define AT_PLATFORM_LINUX 15 #define AT_HWCAP_LINUX 16 #define AT_CLKTCK_LINUX 17 #define AT_SECURE_LINUX 23 #define AT_BASE_PLATFORM_LINUX 24 #define AT_RANDOM_LINUX 25 #define AT_HWCAP2_LINUX 26 #define AT_EXECFN_LINUX 31 #define AT_MINSIGSTKSZ_LINUX 51 #define IFNAMSIZ_LINUX 16 #define SIOCGIFCONF_LINUX 0x8912 #define SIOCGIFADDR_LINUX 0x8915 #define SIOCGIFNETMASK_LINUX 0x891b #define SIOCGIFBRDADDR_LINUX 0x8919 #define SIOCGIFDSTADDR_LINUX 0x8917 #define FIOSETOWN_LINUX 0x8901 // int * #define SIOCSPGRP_LINUX 0x8902 // int * #define FIOGETOWN_LINUX 0x8903 // int * #define SIOCGPGRP_LINUX 0x8904 // int * #define SIOCATMARK_LINUX 0x8905 // int * #define SIOCGSTAMP_LINUX 0x8906 // struct timeval_linux * #define SIOCGSTAMPNS_LINUX 0x8907 // struct timespec_linux * #define AF_UNSPEC_LINUX 0 #define AF_UNIX_LINUX 1 #define AF_INET_LINUX 2 #define AF_INET6_LINUX 10 #define AF_NETLINK_LINUX 16 #define AF_PACKET_LINUX 17 #define AF_VSOCK_LINUX 40 #define SOL_IP_LINUX 0 #define SOL_SOCKET_LINUX 1 #define SOL_TCP_LINUX 6 #define SOL_UDP_LINUX 17 #define SOL_IPV6_LINUX 41 #define IPPROTO_IP_LINUX 0 #define IPPROTO_ICMP_LINUX 1 #define IPPROTO_TCP_LINUX 6 #define IPPROTO_UDP_LINUX 17 #define IPPROTO_ICMPV6_LINUX 58 #define IPPROTO_RAW_LINUX 255 #define SA_NOCLDSTOP_LINUX 1 #define SA_NOCLDWAIT_LINUX 2 #define SA_SIGINFO_LINUX 4 #define SA_UNSUPPORTED_LINUX 0x00000400 #define SA_EXPOSE_TAGBITS_LINUX 0x00000800 #define SA_RESTORER_LINUX 0x04000000 #define SA_ONSTACK_LINUX 0x08000000 #define SA_RESTART_LINUX 0x10000000 #define SA_NODEFER_LINUX 0x40000000 #define SA_RESETHAND_LINUX 0x80000000 #define SCHED_OTHER_LINUX 0 #define SCHED_FIFO_LINUX 1 #define SCHED_RR_LINUX 2 #define SCHED_BATCH_LINUX 3 #define SCHED_IDLE_LINUX 5 #define SCHED_DEADLINE_LINUX 6 #define MSG_OOB_LINUX 0x00000001 // send, recv [portable] #define MSG_PEEK_LINUX 0x00000002 // recv [portable] #define MSG_DONTROUTE_LINUX 0x00000004 // send [portable] #define MSG_TRUNC_LINUX 0x00000020 // recv [portable] #define MSG_DONTWAIT_LINUX 0x00000040 // send, recv [portable] #define MSG_EOR_LINUX 0x00000080 // send [portable] #define MSG_WAITALL_LINUX 0x00000100 // recv [portable] #define MSG_NOSIGNAL_LINUX 0x00004000 // send [portable] #define MSG_CMSG_CLOEXEC_LINUX 0x40000000 // recv #define MSG_CONFIRM_LINUX 0x00000800 // send #define MSG_ERRQUEUE_LINUX 0x00002000 // recv #define MSG_MORE_LINUX 0x00008000 // send #define MSG_FASTOPEN_LINUX 0x20000000 #define MSG_CTRUNC_LINUX 8 #define MSG_NOERROR_LINUX 0x1000 #define MSG_WAITFORONE_LINUX 0x010000 #define MSG_BATCH_LINUX 0x040000 #define MSG_EXCEPT_LINUX 0x2000 #define MSG_FIN_LINUX 0x0200 #define MSG_EOF_LINUX 0x0200 #define MSG_INFO_LINUX 12 #define MSG_PARITY_ERROR_LINUX 9 #define MSG_PROXY_LINUX 0x10 #define MSG_RST_LINUX 0x1000 #define MSG_STAT_LINUX 11 #define MSG_SYN_LINUX 0x0400 #define MSG_NOTIFICATION_LINUX 0x8000 #define GRND_NONBLOCK_LINUX 1 #define GRND_RANDOM_LINUX 2 #define NCCS_LINUX 19 #define VINTR_LINUX 0 #define VQUIT_LINUX 1 #define VERASE_LINUX 2 #define VKILL_LINUX 3 #define VEOF_LINUX 4 #define VTIME_LINUX 5 #define VMIN_LINUX 6 #define VSWTC_LINUX 7 #define VSTART_LINUX 8 #define VSTOP_LINUX 9 #define VSUSP_LINUX 10 #define VEOL_LINUX 11 #define VREPRINT_LINUX 12 #define VDISCARD_LINUX 13 #define VWERASE_LINUX 14 #define VLNEXT_LINUX 15 #define VEOL2_LINUX 16 #define RLIMIT_CPU_LINUX 0 #define RLIMIT_FSIZE_LINUX 1 #define RLIMIT_DATA_LINUX 2 #define RLIMIT_STACK_LINUX 3 #define RLIMIT_CORE_LINUX 4 #define RLIMIT_RSS_LINUX 5 #define RLIMIT_NPROC_LINUX 6 #define RLIMIT_NOFILE_LINUX 7 #define RLIMIT_MEMLOCK_LINUX 8 #define RLIMIT_AS_LINUX 9 #define RLIMIT_LOCKS_LINUX 10 #define RLIMIT_SIGPENDING_LINUX 11 #define RLIMIT_MSGQUEUE_LINUX 12 #define RLIMIT_NICE_LINUX 13 #define RLIMIT_RTPRIO_LINUX 14 #define RLIMIT_RTTIME_LINUX 15 #define RLIM_INFINITY_LINUX 0xffffffffffffffffull #define RLIM_NLIMITS_LINUX 16 #define MINSIGSTKSZ_LINUX 2048 #define SS_ONSTACK_LINUX 1 #define SS_DISABLE_LINUX 2 #define SS_AUTODISARM_LINUX 0x80000000u // termios::c_iflag #define IGNBRK_LINUX 0000001 #define BRKINT_LINUX 0000002 #define IGNPAR_LINUX 0000004 #define PARMRK_LINUX 0000010 #define INPCK_LINUX 0000020 #define ISTRIP_LINUX 0000040 #define INLCR_LINUX 0000100 #define IGNCR_LINUX 0000200 #define ICRNL_LINUX 0000400 #define IUCLC_LINUX 0001000 #define IXON_LINUX 0002000 #define IXANY_LINUX 0004000 #define IXOFF_LINUX 0010000 #define IMAXBEL_LINUX 0020000 #define IUTF8_LINUX 0040000 // termios::c_oflag #define OPOST_LINUX 0000001 #define OLCUC_LINUX 0000002 #define ONLCR_LINUX 0000004 #define OCRNL_LINUX 0000010 #define ONOCR_LINUX 0000020 #define ONLRET_LINUX 0000040 #define OFILL_LINUX 0000100 #define OFDEL_LINUX 0000200 #define NLDLY_LINUX 0000400 #define NL0_LINUX 0000000 #define NL1_LINUX 0000400 #define CRDLY_LINUX 0003000 #define CR0_LINUX 0000000 #define CR1_LINUX 0001000 #define CR2_LINUX 0002000 #define CR3_LINUX 0003000 #define TABDLY_LINUX 0014000 #define TAB0_LINUX 0000000 #define TAB1_LINUX 0004000 #define TAB2_LINUX 0010000 #define TAB3_LINUX 0014000 #define XTABS_LINUX 0014000 #define BSDLY_LINUX 0020000 #define BS0_LINUX 0000000 #define BS1_LINUX 0020000 #define VTDLY_LINUX 0040000 #define VT0_LINUX 0000000 #define VT1_LINUX 0040000 #define FFDLY_LINUX 0100000 #define FF0_LINUX 0000000 #define FF1_LINUX 0100000 // termios::c_cflag #define EXTA_LINUX B19200 #define EXTB_LINUX B38400 #define CSIZE_LINUX 0000060 #define CS5_LINUX 0000000 #define CS6_LINUX 0000020 #define CS7_LINUX 0000040 #define CS8_LINUX 0000060 #define CSTOPB_LINUX 0000100 #define CREAD_LINUX 0000200 #define PARENB_LINUX 0000400 #define PARODD_LINUX 0001000 #define HUPCL_LINUX 0002000 #define CLOCAL_LINUX 0004000 #define CBAUD_LINUX 0010017 #define CBAUDEX_LINUX 0010000 #define B0_LINUX 0000000 // shut it down #define B50_LINUX 0000001 #define B75_LINUX 0000002 #define B110_LINUX 0000003 #define B134_LINUX 0000004 #define B150_LINUX 0000005 #define B200_LINUX 0000006 #define B300_LINUX 0000007 #define B600_LINUX 0000010 #define B1200_LINUX 0000011 #define B1800_LINUX 0000012 #define B2400_LINUX 0000013 #define B4800_LINUX 0000014 #define B9600_LINUX 0000015 #define B19200_LINUX 0000016 #define B38400_LINUX 0000017 #define B57600_LINUX 0010001 #define B115200_LINUX 0010002 #define B230400_LINUX 0010003 #define B460800_LINUX 0010004 #define B500000_LINUX 0010005 #define B576000_LINUX 0010006 #define B921600_LINUX 0010007 #define B1000000_LINUX 0010010 #define B1152000_LINUX 0010011 #define B1500000_LINUX 0010012 #define B2000000_LINUX 0010013 #define B2500000_LINUX 0010014 #define B3000000_LINUX 0010015 #define B3500000_LINUX 0010016 #define B4000000_LINUX 0010017 #define CIBAUD_LINUX 002003600000 // input baud rate (isn't used) #define CMSPAR_LINUX 010000000000 // sticky parity #define CRTSCTS_LINUX 020000000000 // flow control // termios::c_lflag #define ISIG_LINUX 0000001 #define ICANON_LINUX 0000002 #define XCASE_LINUX 0000004 #define ECHO_LINUX 0000010 #define ECHOE_LINUX 0000020 #define ECHOK_LINUX 0000040 #define ECHONL_LINUX 0000100 #define NOFLSH_LINUX 0000200 #define TOSTOP_LINUX 0000400 #define ECHOCTL_LINUX 0001000 #define ECHOPRT_LINUX 0002000 #define ECHOKE_LINUX 0004000 #define FLUSHO_LINUX 0010000 #define PENDIN_LINUX 0040000 #define IEXTEN_LINUX 0100000 #define FD_SETSIZE_LINUX 1024 #define FUTEX_WAITERS_LINUX 0x80000000 #define FUTEX_OWNER_DIED_LINUX 0x40000000 #define FUTEX_TID_MASK_LINUX 0x3fffffff #define UTIME_NOW_LINUX ((1l << 30) - 1l) #define UTIME_OMIT_LINUX ((1l << 30) - 2l) #define ITIMER_REAL_LINUX 0 #define ITIMER_VIRTUAL_LINUX 1 #define ITIMER_PROF_LINUX 2 #define FIOASYNC_LINUX 0x5452 #define FIOCLEX_LINUX 0x5451 #define FIONBIO_LINUX 0x5421 #define FIONCLEX_LINUX 0x5450 #define FIONREAD_LINUX 0x541b #define FIOQSIZE_LINUX 0x5460 #define TCFLSH_LINUX 0x540b #define TCGETA_LINUX 0x5405 #define TCGETS_LINUX 0x5401 #define TCGETX_LINUX 0x5432 #define TCSBRK_LINUX 0x5409 #define TCSBRKP_LINUX 0x5425 #define TCSETA_LINUX 0x5406 #define TCSETAF_LINUX 0x5408 #define TCSETAW_LINUX 0x5407 #define TCSETS_LINUX 0x5402 #define TCSETSF_LINUX 0x5404 #define TCSETSW_LINUX 0x5403 #define TCSETX_LINUX 0x5433 #define TCSETXF_LINUX 0x5434 #define TCSETXW_LINUX 0x5435 #define TCXONC_LINUX 0x540a #define TIOCCBRK_LINUX 0x5428 #define TIOCCONS_LINUX 0x541d #define TIOCEXCL_LINUX 0x540c #define TIOCGDEV_LINUX 0x80045432 #define TIOCGETD_LINUX 0x5424 #define TIOCGEXCL_LINUX 0x80045440 #define TIOCGICOUNT_LINUX 0x545d #define TIOCGISO7816_LINUX 0x80285442 #define TIOCGLCKTRMIOS_LINUX 0x5456 #define TIOCGPGRP_LINUX 0x540f #define TIOCGPKT_LINUX 0x80045438 #define TIOCGPTLCK_LINUX 0x80045439 #define TIOCGPTN_LINUX 0x80045430 #define TIOCGPTPEER_LINUX 0x5441 #define TIOCGRS485_LINUX 0x542e #define TIOCGSERIAL_LINUX 0x541e #define TIOCGSID_LINUX 0x5429 #define TIOCGSOFTCAR_LINUX 0x5419 #define TIOCGWINSZ_LINUX 0x5413 #define TIOCINQ_LINUX 0x541b #define TIOCLINUX_LINUX 0x541c #define TIOCMBIC_LINUX 0x5417 #define TIOCMBIS_LINUX 0x5416 #define TIOCMGET_LINUX 0x5415 #define TIOCMIWAIT_LINUX 0x545c #define TIOCMSET_LINUX 0x5418 #define TIOCNOTTY_LINUX 0x5422 #define TIOCNXCL_LINUX 0x540d #define TIOCOUTQ_LINUX 0x5411 #define TIOCPKT_LINUX 0x5420 #define TIOCPKT_DATA_LINUX 0 #define TIOCPKT_DOSTOP_LINUX 0x20 #define TIOCPKT_FLUSHREAD_LINUX 0x1 #define TIOCPKT_FLUSHWRITE_LINUX 0x2 #define TIOCPKT_IOCTL_LINUX 0x40 #define TIOCPKT_NOSTOP_LINUX 0x10 #define TIOCPKT_START_LINUX 0x8 #define TIOCPKT_STOP_LINUX 0x4 #define TIOCSBRK_LINUX 0x5427 #define TIOCSCTTY_LINUX 0x540e #define TIOCSERCONFIG_LINUX 0x5453 #define TIOCSERGETLSR_LINUX 0x5459 #define TIOCSERGETMULTI_LINUX 0x545a #define TIOCSERGSTRUCT_LINUX 0x5458 #define TIOCSERGWILD_LINUX 0x5454 #define TIOCSERSETMULTI_LINUX 0x545b #define TIOCSERSWILD_LINUX 0x5455 #define TIOCSER_TEMT_LINUX 0x1 #define TIOCSETD_LINUX 0x5423 #define TIOCSIG_LINUX 0x40045436 #define TIOCSISO7816_LINUX 0xc0285443 #define TIOCSLCKTRMIOS_LINUX 0x5457 #define TIOCSPGRP_LINUX 0x5410 #define TIOCSPTLCK_LINUX 0x40045431 #define TIOCSRS485_LINUX 0x542f #define TIOCSSERIAL_LINUX 0x541f #define TIOCSSOFTCAR_LINUX 0x541a #define TIOCSTI_LINUX 0x5412 #define TIOCSWINSZ_LINUX 0x5414 #define TIOCVHANGUP_LINUX 0x5437 #define TCIFLUSH_LINUX 0 #define TCOFLUSH_LINUX 1 #define TCIOFLUSH_LINUX 2 #define SO_DEBUG_LINUX 1 #define SO_REUSEADDR_LINUX 2 #define SO_TYPE_LINUX 3 #define SO_ERROR_LINUX 4 #define SO_DONTROUTE_LINUX 5 #define SO_SNDBUF_LINUX 7 #define SO_RCVBUF_LINUX 8 #define SO_KEEPALIVE_LINUX 9 #define SO_LINGER_LINUX 13 #define SO_REUSEPORT_LINUX 15 #define SO_RCVTIMEO_LINUX 20 #define SO_SNDTIMEO_LINUX 21 #define SO_RCVLOWAT_LINUX 18 #define SO_SNDLOWAT_LINUX 19 #define SO_BROADCAST_LINUX 6 #define IP_TOS_LINUX 1 #define IP_TTL_LINUX 2 #define IP_HDRINCL_LINUX 3 #define IP_OPTIONS_LINUX 4 #define IP_RETOPTS_LINUX 7 #define IP_RECVERR_LINUX 11 #define IP_RECVTTL_LINUX 12 #define IP_MTU_LINUX 14 #define IPV6_RECVERR_LINUX 25 #define TCP_NODELAY_LINUX 1 #define TCP_MAXSEG_LINUX 2 #define TCP_CORK_LINUX 3 #define TCP_NOPUSH_LINUX 3 #define TCP_KEEPIDLE_LINUX 4 #define TCP_KEEPINTVL_LINUX 5 #define TCP_KEEPCNT_LINUX 6 #define TCP_SYNCNT_LINUX 7 #define TCP_DEFER_ACCEPT_LINUX 9 #define TCP_WINDOW_CLAMP_LINUX 10 #define TCP_FASTOPEN_LINUX 23 #define TCP_NOTSENT_LOWAT_LINUX 25 #define TCP_FASTOPEN_CONNECT_LINUX 30 #define TCP_QUICKACK_LINUX 12 #define TCP_SAVE_SYN_LINUX 27 #define CLOSE_RANGE_UNSHARE_LINUX 2 #define CLOSE_RANGE_CLOEXEC_LINUX 4 #define SOCK_STREAM_LINUX 1 #define SOCK_DGRAM_LINUX 2 #define SOCK_RAW_LINUX 3 #define IOV_MAX_LINUX 1024 #define WNOHANG_LINUX 0x00000001 #define WUNTRACED_LINUX 0x00000002 #define WEXITED_LINUX 0x00000004 #define WCONTINUED_LINUX 0x00000008 #define WNOWAIT_LINUX 0x01000000 #define __WNOTHREAD_LINUX 0x20000000 #define __WALL_LINUX 0x40000000 #define __WCLONE_LINUX 0x80000000 #define MS_SYNC_LINUX 4 #define MS_ASYNC_LINUX 1 #define MS_INVALIDATE_LINUX 2 #define LOCK_SH_LINUX 1 #define LOCK_EX_LINUX 2 #define LOCK_NB_LINUX 4 #define LOCK_UN_LINUX 8 #define SCM_RIGHTS_LINUX 1 #define SCM_CREDENTIALS_LINUX 2 #define ST_RDONLY_LINUX 1 #define ST_NOSUID_LINUX 2 #define ST_NODEV_LINUX 4 #define ST_NOEXEC_LINUX 8 #define ST_SYNCHRONOUS_LINUX 16 #define ST_NOATIME_LINUX 0x0040 #define ST_RELATIME_LINUX 0x1000 #define ST_APPEND_LINUX 0x0100 #define ST_IMMUTABLE_LINUX 0x0200 #define ST_MANDLOCK_LINUX 0x0040 #define ST_NODIRATIME_LINUX 0x0800 #define ST_WRITE_LINUX 0x0080 #define ST_NOSYMFOLLOW_LINUX 0x2000 #define SCM_MAX_FD_LINUX 253 #define SI_USER_LINUX 0 #define SI_QUEUE_LINUX -1 #define SI_TIMER_LINUX -2 #define SI_TKILL_LINUX -6 #define SI_MESGQ_LINUX -3 #define SI_ASYNCIO_LINUX -4 #define SI_ASYNCNL_LINUX -60 #define SI_KERNEL_LINUX 128 #define SI_NOINFO_LINUX 32767 #define CLD_EXITED_LINUX 1 #define CLD_KILLED_LINUX 2 #define CLD_DUMPED_LINUX 3 #define CLD_TRAPPED_LINUX 4 #define CLD_STOPPED_LINUX 5 #define CLD_CONTINUED_LINUX 6 #define TRAP_BRKPT_LINUX 1 #define TRAP_TRACE_LINUX 2 #define SEGV_MAPERR_LINUX 1 #define SEGV_ACCERR_LINUX 2 #define SEGV_PKUERR_LINUX -1 #define FPE_INTDIV_LINUX 1 #define FPE_INTOVF_LINUX 2 #define FPE_FLTDIV_LINUX 3 #define FPE_FLTOVF_LINUX 4 #define FPE_FLTUND_LINUX 5 #define FPE_FLTRES_LINUX 6 #define FPE_FLTINV_LINUX 7 #define FPE_FLTSUB_LINUX 8 #define ILL_ILLOPC_LINUX 1 #define ILL_ILLOPN_LINUX 2 #define ILL_ILLADR_LINUX 3 #define ILL_ILLTRP_LINUX 4 #define ILL_PRVOPC_LINUX 5 #define ILL_PRVREG_LINUX 6 #define ILL_COPROC_LINUX 7 #define ILL_BADSTK_LINUX 8 #define BUS_ADRALN_LINUX 1 #define BUS_ADRERR_LINUX 2 #define BUS_OBJERR_LINUX 3 #define BUS_OOMERR_LINUX -1 #define BUS_MCEERR_AR_LINUX 4 #define BUS_MCEERR_AO_LINUX 5 #define POLL_IN_LINUX 1 #define POLL_OUT_LINUX 2 #define POLL_MSG_LINUX 3 #define POLL_ERR_LINUX 4 #define POLL_PRI_LINUX 5 #define POLL_HUP_LINUX 6 #define RENAME_NOREPLACE_LINUX 1 #define RENAME_EXCHANGE_LINUX 2 #define RENAME_WHITEOUT_LINUX 4 #define CLOCK_REALTIME_LINUX 0 #define CLOCK_MONOTONIC_LINUX 1 #define CLOCK_PROCESS_CPUTIME_ID_LINUX 2 #define CLOCK_THREAD_CPUTIME_ID_LINUX 3 #define CLOCK_MONOTONIC_RAW_LINUX 4 #define CLOCK_REALTIME_COARSE_LINUX 5 #define CLOCK_MONOTONIC_COARSE_LINUX 6 #define CLOCK_BOOTTIME_LINUX 7 #define CLOCK_REALTIME_ALARM_LINUX 8 #define CLOCK_BOOTTIME_ALARM_LINUX 9 #define CLOCK_TAI_LINUX 11 #define PR_GET_SECCOMP_LINUX 21 #define PR_SET_SECCOMP_LINUX 22 #define PR_CAPBSET_READ_LINUX 23 #define PR_CAPBSET_DROP_LINUX 24 #define PR_GET_TSC_LINUX 25 #define PR_SET_TSC_LINUX 26 #define PR_TSC_ENABLE_LINUX 1 #define PR_TSC_SIGSEGV_LINUX 2 #define PR_SET_NO_NEW_PRIVS_LINUX 38 #define PR_GET_TID_ADDRESS_LINUX 40 #define EPOLL_CLOEXEC_LINUX O_CLOEXEC_LINUX #define EPOLL_CTL_ADD_LINUX 1 #define EPOLL_CTL_DEL_LINUX 2 #define EPOLL_CTL_MOD_LINUX 3 #define EPOLLIN_LINUX 0x00000001u #define EPOLLPRI_LINUX 0x00000002u #define EPOLLOUT_LINUX 0x00000004u #define EPOLLERR_LINUX 0x00000008u #define EPOLLHUP_LINUX 0x00000010u #define EPOLLNVAL_LINUX 0x00000020u #define EPOLLRDNORM_LINUX 0x00000040u #define EPOLLRDBAND_LINUX 0x00000080u #define EPOLLWRNORM_LINUX 0x00000100u #define EPOLLWRBAND_LINUX 0x00000200u #define EPOLLMSG_LINUX 0x00000400u #define EPOLLRDHUP_LINUX 0x00002000u #define EPOLLEXCLUSIVE_LINUX 0x10000000u #define EPOLLWAKEUP_LINUX 0x20000000u #define EPOLLONESHOT_LINUX 0x40000000u #define EPOLLET_LINUX 0x80000000u #define MS_RDONLY_LINUX 1 #define MS_NOSUID_LINUX 2 #define MS_NODEV_LINUX 4 #define MS_NOEXEC_LINUX 8 #define MS_SYNCHRONOUS_LINUX 16 #define MS_REMOUNT_LINUX 32 #define MS_MANDLOCK_LINUX 64 #define MS_DIRSYNC_LINUX 128 #define MS_NOSYMFOLLOW_LINUX 256 #define MS_NOATIME_LINUX 1024 #define MS_NODIRATIME_LINUX 2048 #define MS_BIND_LINUX 4096 #define MS_MOVE_LINUX 8192 #define MS_REC_LINUX 16384 #define MS_SILENT_LINUX 32768 #define MS_POSIXACL_LINUX (1 << 16) #define MS_UNBINDABLE_LINUX (1 << 17) #define MS_PRIVATE_LINUX (1 << 18) #define MS_SLAVE_LINUX (1 << 19) #define MS_SHARED_LINUX (1 << 20) #define MS_RELATIME_LINUX (1 << 21) #define MS_KERNMOUNT_LINUX (1 << 22) #define MS_I_VERSION_LINUX (1 << 23) #define MS_STRICTATIME_LINUX (1 << 24) #define MS_LAZYTIME_LINUX (1 << 25) #define MS_NOREMOTELOCK_LINUX (1 << 27) #define MS_NOSEC_LINUX (1 << 28) #define MS_BORN_LINUX (1 << 29) #define MS_ACTIVE_LINUX (1 << 30) #define MS_NOUSER_LINUX (1U << 31) struct iovec_linux { u8 base[8]; u8 len[8]; }; struct pollfd_linux { u8 fd[4]; u8 events[2]; u8 revents[2]; }; struct timeval_linux { u8 sec[8]; u8 usec[8]; }; struct timespec_linux { u8 sec[8]; u8 nsec[8]; }; struct timezone_linux { u8 minuteswest[4]; u8 dsttime[4]; }; struct sigaction_linux { u8 handler[8]; u8 flags[8]; u8 restorer[8]; u8 mask[8]; }; struct winsize_linux { u8 row[2]; u8 col[2]; u8 xpixel[2]; u8 ypixel[2]; }; struct termios_linux { u8 iflag[4]; u8 oflag[4]; u8 cflag[4]; u8 lflag[4]; u8 line; u8 cc[NCCS_LINUX]; }; struct sockaddr_linux { u8 family[2]; }; struct sockaddr_un_linux { u8 family[2]; char path[108]; }; struct sockaddr_in_linux { u8 family[2]; u16 port; u32 addr; u8 zero[8]; }; struct sockaddr_in6_linux { u8 family[2]; u16 port; u8 flowinfo[4]; u8 addr[16]; u8 scope_id[4]; }; struct sockaddr_storage_linux { union { u8 family[2]; char storage[128]; }; }; struct stat_linux { u8 dev[8]; u8 ino[8]; u8 nlink[8]; u8 mode[4]; u8 uid[4]; u8 gid[4]; u8 pad_[4]; u8 rdev[8]; u8 size[8]; u8 blksize[8]; u8 blocks[8]; struct timespec_linux atim; struct timespec_linux mtim; struct timespec_linux ctim; }; struct itimerval_linux { struct timeval_linux interval; struct timeval_linux value; }; struct rusage_linux { struct timeval_linux utime; struct timeval_linux stime; u8 maxrss[8]; u8 ixrss[8]; u8 idrss[8]; u8 isrss[8]; u8 minflt[8]; u8 majflt[8]; u8 nswap[8]; u8 inblock[8]; u8 oublock[8]; u8 msgsnd[8]; u8 msgrcv[8]; u8 nsignals[8]; u8 nvcsw[8]; u8 nivcsw[8]; }; struct siginfo_linux { u8 signo[4]; u8 errno_[4]; u8 code[4]; u8 pad1_[4]; union { struct { union { struct { // signals sent by kill() and sigqueue() set these u8 pid[4]; u8 uid[4]; }; struct { // SIGALRM sets these u8 timerid[4]; u8 overrun[4]; }; }; union { u8 value[8]; // provided by third arg of sigqueue(2) struct { u8 status[4]; u8 pad2_[4]; u8 utime[8]; u8 stime[8]; }; }; }; struct { // SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP u8 addr[8]; u8 addr_lsb[2]; u8 pad3_[6]; union { struct { u8 lower[8]; u8 upper[8]; }; u8 pkey[4]; }; }; struct { u8 band[8]; // SIGPOLL u8 fd[4]; }; struct { u8 call_addr[8]; u8 syscall[4]; u8 arch[4]; }; u8 payload[112]; }; }; struct fpstate_linux { u8 cwd[2]; u8 swd[2]; u8 ftw[2]; u8 fop[2]; u8 rip[8]; u8 rdp[8]; u8 mxcsr[4]; u8 mxcr_mask[4]; u8 st[8][16]; u8 xmm[16][16]; u8 padding_[96]; }; struct ucontext_linux { u8 uc__flags[8]; u8 uc__link[8]; u8 ss__sp[8]; u8 ss__flags[4]; u8 pad0_[4]; u8 ss_size[8]; u8 r8[8]; u8 r9[8]; u8 r10[8]; u8 r11[8]; u8 r12[8]; u8 r13[8]; u8 r14[8]; u8 r15[8]; u8 rdi[8]; u8 rsi[8]; u8 rbp[8]; u8 rbx[8]; u8 rdx[8]; u8 rax[8]; u8 rcx[8]; u8 rsp[8]; u8 rip[8]; u8 eflags[8]; u8 cs[2]; u8 gs[2]; u8 fs[2]; u8 ss[2]; u8 err[8]; u8 trapno[8]; u8 oldmask[8]; u8 cr2[8]; u8 fpstate[8]; u8 pad1_[64]; u8 sigmask[8]; }; struct utsname_linux { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; char domainname[65]; }; struct rlimit_linux { u8 cur[8]; u8 max[8]; }; struct dirent_linux { u8 ino[8]; // inode number u8 off[8]; // implementation-dependent location number u8 reclen[2]; // byte length of this whole struct and string u8 type[1]; // DT_REG, DT_DIR, DT_UNKNOWN, DT_BLK, etc. char name[256]; // NUL-terminated basename }; struct ifconf_linux { u8 len[4]; u8 pad[4]; u8 buf[8]; }; struct ifreq_linux { u8 name[IFNAMSIZ_LINUX]; union { struct sockaddr_in_linux addr; struct sockaddr_in_linux dstaddr; struct sockaddr_in_linux netmask; struct sockaddr_in_linux broadaddr; u8 flags[2]; u8 pad[24]; }; }; struct flock_linux { u8 type[2]; u8 whence[2]; u8 pad1_[4]; u8 start[8]; u8 len[8]; u8 pid[4]; u8 pad2_[4]; }; struct sysinfo_linux { u8 uptime[8]; // seconds since boot u8 loads[3][8]; // 1-5-15 min active process averages u8 totalram[8]; // system physical memory u8 freeram[8]; // amount of ram currently going to waste u8 sharedram[8]; // bytes w/ pages mapped into multiple progs u8 bufferram[8]; // lingering disk pages; see fadvise u8 totalswap[8]; // size of emergency memory u8 freeswap[8]; // hopefully equal to totalswap u8 procs[2]; // number of processes u8 ignore_[6]; // padding u8 totalhigh[8]; // wut u8 freehigh[8]; // wut u8 mem_unit[4]; // ram stuff above is multiples of this }; struct tms_linux { u8 utime[8]; // user time u8 stime[8]; // system time u8 cutime[8]; // user time of children u8 cstime[8]; // system time of children }; struct sigaltstack_linux { u8 sp[8]; // base address of stack u8 flags[4]; // SS_???_LINUX flags u8 pad1_[4]; // u8 size[8]; // size of stack }; struct pselect6_linux { u8 sigmaskaddr[8]; u8 sigmasksize[8]; }; struct sigset_linux { u8 sigmask[8]; }; struct robust_list_linux { u8 next[8]; u8 offset[8]; u8 pending[8]; }; struct utimbuf_linux { u8 actime[8]; u8 modtime[8]; }; struct f_owner_ex_linux { u8 type[4]; u8 pid[4]; }; struct statfs_linux { u8 type[8]; // type of filesystem u8 bsize[8]; // optimal transfer block size u8 blocks[8]; // total data blocks in filesystem u8 bfree[8]; // free blocks in filesystem u8 bavail[8]; // free blocks available to unprivileged user u8 files[8]; // total file nodes in filesystem u8 ffree[8]; // free file nodes in filesystem u8 fsid[2][4]; // filesystem id u8 namelen[8]; // maximum length of filenames u8 frsize[8]; // fragment size u8 flags[8]; // mount flags of filesystem 2.6.36 u8 spare[4][8]; }; struct linger_linux { u8 onoff[4]; // on/off u8 linger[4]; // seconds }; struct msghdr_linux { u8 name[8]; // optional pointer to address u8 namelen[4]; // socklen_t size of name u8 pad1_[4]; // u8 iov[8]; // points to scatter/gather array u8 iovlen[8]; // u64 # elements in iov u8 control[8]; // points to ancillary data c. cmsghdr u8 controllen[8]; // u64 ancillary data buffer len u8 flags[4]; // u32 MSG_XXX (only applies to recvmsg) u8 pad2_[4]; // }; struct mmsghdr_linux { struct msghdr_linux hdr; u8 len[4]; u8 pad_[4]; }; struct cmsghdr_linux { u8 len[8]; // u64 bytes in message (including this) u8 level[4]; // i32 e.g. SOL_SOCKET u8 type[4]; // i32 e.g. SCM_RIGHTS }; struct ucred_linux { // 8-byte aligned u8 pid[4]; // process id of sending process u8 uid[4]; // user id of sending process u8 gid[4]; // group id of sending process }; struct epoll_event_linux { u8 events[4]; u8 data[8]; }; int sysinfo_linux(struct sysinfo_linux *); #endif /* BLINK_LINUX_H_ */ ================================================ FILE: blink/loader.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/loader.h" #include #include #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/biosrom.h" #include "blink/builtin.h" #include "blink/end.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/overlays.h" #include "blink/procfs.h" #include "blink/random.h" #include "blink/tunables.h" #include "blink/util.h" #include "blink/vfs.h" #include "blink/x86.h" #define READ64(p) Read64((const u8 *)(p)) #define READ32(p) Read32((const u8 *)(p)) #ifndef __COSMOPOLITAN__ #define IsWindows() 0 #endif static bool CanEmulateImpl(struct Machine *, char **, char ***, bool); static void LoaderCopy(struct Machine *m, i64 vaddr, size_t amt, void *image, i64 offset, int prot) { i64 base; bool memory_might_be_write_protected; if (!amt) return; ELF_LOGF("copy %" PRIx64 "-%" PRIx64 " from %" PRIx64 "-%" PRIx64, vaddr, vaddr + amt, offset, offset + amt); base = ROUNDDOWN(vaddr, 4096); if ((memory_might_be_write_protected = (prot & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE) || (!IsJitDisabled(&m->system->jit) && prot == (PROT_READ | PROT_WRITE | PROT_EXEC)))) { unassert(!ProtectVirtual(m->system, base, vaddr + amt - base, PROT_READ | PROT_WRITE, false)); } unassert(!CopyToUser(m, vaddr, (u8 *)image + offset, amt)); if (memory_might_be_write_protected) { unassert(!ProtectVirtual(m->system, base, vaddr + amt - base, prot, false)); } } static i64 LoadElfLoadSegment(struct Machine *m, const char *path, void *image, size_t imagesize, const Elf64_Phdr_ *phdr, i64 last_end, int *last_prot, u64 aslr, int fd) { i64 bulk; size_t amt; void *blank; int overprot; struct System *s = m->system; u32 flags = Read32(phdr->flags); i64 vaddr = Read64(phdr->vaddr) + aslr; i64 memsz = Read64(phdr->memsz); i64 offset = Read64(phdr->offset); i64 filesz = Read64(phdr->filesz); long pagesize = HasLinearMapping() ? FLAG_pagesize : 4096; i64 start = ROUNDDOWN(vaddr, pagesize); i64 end = ROUNDUP(vaddr + memsz, pagesize); long skew = vaddr & (pagesize - 1); u64 key = (flags & PF_R_ ? PAGE_U : 0) | // (flags & PF_W_ ? PAGE_RW : 0) | // (flags & PF_X_ ? 0 : PAGE_XD); int prot = (flags & PF_R_ ? PROT_READ : 0) | // (flags & PF_W_ ? PROT_WRITE : 0) | // (flags & PF_X_ ? PROT_EXEC : 0); SYS_LOGF("PT_LOAD %c%c%c [%" PRIx64 ",%" PRIx64 ") %s", // (flags & PF_R_ ? 'R' : '.'), // (flags & PF_W_ ? 'W' : '.'), // (flags & PF_X_ ? 'X' : '.'), // vaddr, vaddr + memsz, path); ELF_LOGF("PROGRAM HEADER"); ELF_LOGF(" path = %s", path); ELF_LOGF(" aslr = %" PRIx64, aslr); ELF_LOGF(" flags = %s%s%s", // (flags & PF_R_ ? "R" : ""), // (flags & PF_W_ ? "W" : ""), // (flags & PF_X_ ? "X" : "")); ELF_LOGF(" vaddr = %" PRIx64, vaddr); ELF_LOGF(" memsz = %" PRIx64, memsz); ELF_LOGF(" offset = %" PRIx64, offset); ELF_LOGF(" filesz = %" PRIx64, filesz); ELF_LOGF(" pagesize = %ld", pagesize); ELF_LOGF(" start = %" PRIx64, start); ELF_LOGF(" end = %" PRIx64, end); ELF_LOGF(" skew = %lx", skew); if (!memsz) { return last_end; } if (offset > imagesize) { ERRF("bad phdr offset"); exit(EXIT_FAILURE_EXEC_FAILED); } if (filesz > imagesize) { ERRF("bad phdr filesz"); exit(EXIT_FAILURE_EXEC_FAILED); } if (filesz && offset + filesz > imagesize) { ERRF("corrupt elf program header"); exit(EXIT_FAILURE_EXEC_FAILED); } if (end < last_end) { ERRF("program headers aren't ordered, expected %" PRIx64 " >= %" PRIx64, end, last_end); exit(EXIT_FAILURE_EXEC_FAILED); } if (skew != (offset & (pagesize - 1))) { WriteErrorString( "p_vaddr p_offset skew unequal w.r.t. page size; try either " "(1) rebuilding your program using the linker flags: -static " "-Wl,-z,common-page-size=65536,-z,max-page-size=65536 or (2) " "using `blink -m` to disable the linear memory optimization\n"); exit(EXIT_FAILURE_EXEC_FAILED); } // on systems with a page size greater than the elf executable (e.g. // apple m1) it's possible for the second program header load to end // up overlapping the previous one. if (HasLinearMapping() && start < last_end) { unassert(pagesize > 4096); unassert(vaddr < last_end); unassert(start == last_end - pagesize); unassert(skew + (last_end - vaddr) == pagesize); overprot = prot | *last_prot; unassert(!ProtectVirtual(m->system, start, pagesize, overprot, false)); amt = MIN(filesz, last_end - vaddr); LoaderCopy(m, vaddr, amt, image, offset, overprot); filesz -= amt; offset += last_end - vaddr; vaddr += last_end - vaddr; start = last_end; skew = 0; } // if there's still a skew then the elf program header is documenting // the precise byte offset within the file where this program starts. // in that case, it's harmless to just round down the mmap request to // ingest the previous bytes which shouldn't even need to be cleared. if (skew) { unassert(skew < pagesize); vaddr -= skew; offset -= skew; if (filesz) { filesz += skew; } } // associate the file name with the memory mapping // this makes it possible for debug symbols to be loaded if (filesz) { key |= PAGE_FILE; unassert(AddFileMap(m->system, start, filesz, path, offset)); } // load the aligned program header unassert(start <= end); unassert(vaddr == start); unassert(vaddr + filesz <= end); unassert(!(vaddr & (pagesize - 1))); unassert(!(start & (pagesize - 1))); unassert(!(offset & (pagesize - 1))); if (start < end) { // it's also harmless to extend the size to the next host page // boundary when mapping a file. if some extra bytes go beyond // the end of the file then they'll be zero'd and sigbus won't // be raised if they're used. if extra file content does exist // beyond filesz, then we shall manually bzero() it afterwards if ((bulk = ROUNDUP(filesz, pagesize))) { // map the bulk of .text directly into memory without copying. ELF_LOGF("load %" PRIx64 "-%" PRIx64 " from %" PRIx64 "-%" PRIx64, start, start + bulk, offset, offset + bulk); if (ReserveVirtual(s, start, bulk, key, fd, offset, 0, 0) == -1) { ERRF("failed to map elf program header file data"); exit(EXIT_FAILURE_EXEC_FAILED); } if ((amt = bulk - filesz)) { ELF_LOGF("note: next copy is actually bzero() kludge"); unassert(blank = calloc(1, amt)); LoaderCopy(m, start + filesz, amt, blank, 0, prot); free(blank); } } start += bulk; // allocate any remaining zero-initialized memory if (start < end) { ELF_LOGF("alloc %" PRIx64 "-%" PRIx64, start, end); if (ReserveVirtual(s, start, end - start, key, -1, 0, 0, 0) == -1) { ERRF("failed to allocate program header bss"); exit(EXIT_FAILURE_EXEC_FAILED); } } } *last_prot = prot; s->brk = MAX(s->brk, end); if (flags & PF_X_) { if (!s->codesize) { s->codestart = vaddr; s->codesize = memsz; } else if (vaddr == s->codestart + s->codesize) { s->codesize += memsz; } } return end; } static bool IsFreebsdExecutable(Elf64_Ehdr_ *ehdr, size_t size) { // APE uses the FreeBSD OS ABI too, but never with ET_DYN return Read16(ehdr->type) == ET_DYN_ && ehdr->ident[EI_OSABI_] == ELFOSABI_FREEBSD_ && ehdr->ident[EI_VERSION_] == 1; } static bool IsOpenbsdExecutable(struct Elf64_Ehdr_ *ehdr, size_t size) { size_t off; unsigned i; Elf64_Phdr_ *phdr; if (Read64(ehdr->phoff) < size) { for (i = 0; i < Read16(ehdr->phnum); ++i) { off = Read64(ehdr->phoff) + Read16(ehdr->phentsize) * i; if (off + Read16(ehdr->phentsize) > size) { return false; } phdr = (Elf64_Phdr_ *)((u8 *)ehdr + off); if (Read32(phdr->type) == PT_OPENBSD_RANDOMIZE_) { return true; } } } return false; } static bool IsHaikuExecutable(Elf64_Ehdr_ *ehdr, size_t size) { #ifdef __HAIKU__ int i, n; bool res = false; const char *stab; const Elf64_Sym_ *st; if ((stab = GetElfStringTable(ehdr, size)) && (st = GetElfSymbolTable(ehdr, size, &n))) { for (i = 0; i < n; ++i) { if (ELF64_ST_TYPE_(st[i].info) == STT_OBJECT_ && !strcmp(stab + Read32(st[i].name), "_gSharedObjectHaikuVersion")) { res = true; break; } } } return res; #else return false; #endif } static bool IsShebangExecutable(void *image, size_t size) { return size >= 2 && ((char *)image)[0] == '#' && ((char *)image)[1] == '!'; } static void ExplainWhyItCantBeEmulated(const char *path, const char *reason) { LOGF("%s: can't emulate: %s", path, reason); } static bool IsBinFile(const char *prog) { return EndsWith(prog, ".bin") || // EndsWith(prog, ".BIN") || // EndsWith(prog, ".img") || // EndsWith(prog, ".IMG") || // EndsWith(prog, ".raw") || // EndsWith(prog, ".RAW"); } bool IsSupportedExecutable(const char *path, void *image, size_t size) { Elf64_Ehdr_ *ehdr; if (IsBinFile(path)) { return true; } if (size >= sizeof(Elf64_Ehdr_) && READ32(image) == READ32("\177ELF")) { ehdr = (Elf64_Ehdr_ *)image; if (Read16(ehdr->type) != ET_EXEC_ && // Read16(ehdr->type) != ET_DYN_) { ExplainWhyItCantBeEmulated(path, "ELF is neither ET_EXEC or ET_DYN"); return false; } if (ehdr->ident[EI_CLASS_] == ELFCLASS32_) { ExplainWhyItCantBeEmulated(path, "32-bit ELF not supported"); return false; } if (Read16(ehdr->machine) != EM_NEXGEN32E_) { ExplainWhyItCantBeEmulated(path, "ELF is not AMD64"); return false; } if (IsFreebsdExecutable(ehdr, size)) { ExplainWhyItCantBeEmulated(path, "ELF is FreeBSD executable"); return false; } if (IsOpenbsdExecutable(ehdr, size)) { ExplainWhyItCantBeEmulated(path, "ELF is OpenBSD executable"); return false; } if (IsHaikuExecutable(ehdr, size)) { ExplainWhyItCantBeEmulated(path, "ELF is Haiku executable"); return false; } #if defined(__ELF__) && !defined(__linux) LOGF("blink believes %s is an x86_64-linux executable", path); #endif return true; } if (size >= 4096 && (READ64(image) == READ64("MZqFpD='") || READ64(image) == READ64("jartsr='"))) { return true; } if (!IsShebangExecutable(image, size)) { ExplainWhyItCantBeEmulated(path, "not ELF, not APE, and not a .bin file"); } return false; } static void LoadFlatExecutable(struct Machine *m, uintptr_t base, const char *prog, void *image, size_t imagesize, int fd) { int prot = 0; Elf64_Phdr_ phdr; i64 end = INT64_MIN; Write32(phdr.type, PT_LOAD_); Write32(phdr.flags, PF_X_ | PF_R_ | PF_W_); Write64(phdr.offset, 0); Write64(phdr.vaddr, base); Write64(phdr.filesz, imagesize); Write64(phdr.memsz, ROUNDUP(imagesize + kRealSize, 4096)); LoadElfLoadSegment(m, prog, image, imagesize, &phdr, end, &prot, 0, fd); m->ip = base; } static i64 ChooseAslr(const Elf64_Ehdr_ *ehdr, size_t size, i64 dflt, i64 *base) { i64 aslr; if (GetElfMemorySize(ehdr, size, base) <= 0) { ERRF("couldn't determine boundaries of loaded executable"); exit(EXIT_FAILURE_EXEC_FAILED); } if (Read16(ehdr->type) == ET_DYN_ && !*base) { aslr = dflt; ELF_LOGF("choosing base skew %" PRIx64 " because dynamic", aslr); } else { aslr = 0; ELF_LOGF("won't skew base since not dynamic"); } *base += aslr; if (!(*base & ~(FLAG_pagesize - 1))) { ERRF("won't load program to null base address"); exit(EXIT_FAILURE_EXEC_FAILED); } return aslr; } static bool LoadElf(struct Machine *m, // struct Elf *elf, // Elf64_Ehdr_ *ehdr, // size_t esize, // int fd) { int i, prot; Elf64_Phdr_ *phdr; i64 end = INT64_MIN; bool execstack = true; elf->aslr = ChooseAslr(ehdr, esize, m->system->brk, &elf->base); m->ip = elf->at_entry = elf->aslr + Read64(ehdr->entry); m->cs.sel = USER_CS_LINUX; m->ss.sel = USER_DS_LINUX; elf->at_phdr = elf->base + Read64(ehdr->phoff); elf->at_phent = Read16(ehdr->phentsize); elf->at_phnum = 0; for (prot = i = 0; i < Read16(ehdr->phnum); ++i) { ++elf->at_phnum; phdr = (Elf64_Phdr_ *)((u8 *)ehdr + Read64(ehdr->phoff) + Read16(ehdr->phentsize) * i); switch (Read32(phdr->type)) { case PT_GNU_STACK_: execstack = Read32(phdr->flags) & PF_X_; break; case PT_LOAD_: end = LoadElfLoadSegment(m, elf->execfn, ehdr, esize, phdr, end, &prot, elf->aslr, fd); break; case PT_INTERP_: elf->interpreter = (char *)ehdr + Read64(phdr->offset); if (elf->interpreter[Read64(phdr->filesz) - 1]) { ELF_LOGF("elf interpreter not nul terminated"); exit(EXIT_FAILURE_EXEC_FAILED); } break; default: break; } } if (elf->interpreter) { int fd; i64 aslr; char ibuf[21]; struct stat st; Elf64_Ehdr_ *ehdri; end = INT64_MIN; ELF_LOGF("loading elf interpreter %s", elf->interpreter); errno = 0; SYS_LOGF("LoadInterpreter %s", elf->interpreter); if ((fd = VfsOpen(AT_FDCWD, elf->interpreter, O_RDONLY, 0)) == -1 || (VfsFstat(fd, &st) == -1 || !st.st_size) || (ehdri = (Elf64_Ehdr_ *)Mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0, "loader")) == MAP_FAILED || !IsSupportedExecutable(elf->interpreter, ehdri, st.st_size)) { WriteErrorString(elf->interpreter); WriteErrorString(": failed to load interpreter (errno "); FormatInt64(ibuf, errno); WriteErrorString(ibuf); WriteErrorString(")\n"); exit(EXIT_FAILURE_EXEC_FAILED); } aslr = ChooseAslr( ehdri, st.st_size, elf->aslr ? elf->aslr - (16 * 1024 * 1024) : FLAG_dyninterpaddr, &elf->at_base); m->ip = elf->at_base + Read64(ehdri->entry); for (prot = i = 0; i < Read16(ehdri->phnum); ++i) { phdr = GetElfProgramHeaderAddress(ehdri, st.st_size, i); switch (Read32(phdr->type)) { case PT_LOAD_: end = LoadElfLoadSegment(m, elf->interpreter, ehdri, st.st_size, phdr, end, &prot, aslr, fd); break; default: break; } } unassert(!Munmap(ehdri, st.st_size)); unassert(!VfsClose(fd)); } return execstack; } void BootProgram(struct Machine *m, // struct Elf *elf, // u8 bootdrive) { int fd; SetDefaultBiosIntVectors(m); memset(m->beg, 0, sizeof(m->beg)); // reinitialize registers memset(m->seg, 0, sizeof(m->seg)); m->flags = SetFlag(m->flags, FLAGS_IF, 1); m->ip = 0x7c00; elf->base = 0x7c00; Write64(m->sp, 0x6f00); // following QEMU m->dl = bootdrive; SetDefaultBiosDataArea(m); memset(m->system->real + 0x500, 0, kBiosOptBase - 0x500); memset(m->system->real + 0x00100000, 0, kRealSize - 0x00100000); if ((fd = VfsOpen(AT_FDCWD, m->system->elf.prog, O_RDONLY, 0)) == -1 || VfsRead(fd, m->system->real + 0x7c00, 512) <= 0) { // if we failed to load the boot sector for whatever reason, then... // ...arrange to invoke int 0x18 (diskless boot hook) // TODO: maybe error out more quickly? Write16(m->system->real + 0x7c00, 0x18CD); } VfsClose(fd); SetWriteAddr(m, 0x7c00, 512); } static int GetElfHeader(char ehdr[64], const char *prog, const char *image) { int c, i; const char *p; for (p = image; p < image + 4096; ++p) { if (READ64(p) != READ64("printf '")) { continue; } for (i = 0, p += 8; p + 3 < image + 4096 && (c = *p++) != '\'';) { if (c == '\\') { if ('0' <= *p && *p <= '7') { c = *p++ - '0'; if ('0' <= *p && *p <= '7') { c *= 8; c += *p++ - '0'; if ('0' <= *p && *p <= '7') { c *= 8; c += *p++ - '0'; } } } } if (i < 64) { ehdr[i++] = c; } else { ERRF("%s: ape printf elf header too long\n", prog); return -1; } } if (i != 64) { ERRF("%s: ape printf elf header too short\n", prog); return -1; } if (READ32(ehdr) != READ32("\177ELF")) { ERRF("%s: ape printf elf header didn't have elf magic\n", prog); return -1; } return 0; } ERRF("%s: printf statement not found in first 4096 bytes\n", prog); return -1; } static void FreeProgName(void) { free(g_progname); } static int CheckExecutableFile(const char *prog, const struct stat *st) { if (!S_ISREG(st->st_mode)) { LOGF("execve needs regular file"); errno = EACCES; return -1; } if (!IsWindows() && !(st->st_mode & 0111) && !IsBinFile(prog)) { LOGF("execve needs chmod +x"); errno = EACCES; return -1; } if (!st->st_size) { LOGF("executable file empty"); errno = ENOEXEC; return -1; } return 0; } // SHELL RUNS // ./script.sh foo bar // SCRIPT HAS // #!/bin/interp one arg // BLINK DOES // AT_EXECFN = ./script.sh // argv[0] = /bin/interp // argv[1] = one arg // argv[2] = ./script.sh // argv[3] = foo // argv[4] = bar static bool HasShebang(struct Machine *m, const char *p, size_t n, char **prog, char **args) { char *b; size_t i, j, t; n = MIN(n, kMaxShebang); if (n < 4) return false; if (p[0] != '#') return false; if (p[1] != '!') return false; if (!(b = (char *)AddToFreeList(m, calloc(1, n + 1)))) return false; for (t = 0, j = 0, i = 2; i < n; ++i) { if (!(32 <= p[i] && p[i] < 0177) && p[i] != '\n') return false; if (!t) { // STATE 0: COPY INTERPRETER FILENAME if (p[i] == ' ') { *prog = b; b = 0; j = 0; t = 1; } else if (p[i] == '\n') { *prog = b; *args = 0; return true; } else { b[j++] = p[i]; b[j] = 0; } } else if (t == 1) { // STATE 1: HANDLE SPACES BETWEEN INTERPRETER AND ITS ARGS if (p[i] == ' ') { // do nothing } else if (p[i] == '\n') { *args = 0; return true; } else { if (!(b = (char *)AddToFreeList(m, calloc(1, n + 1)))) return false; b[j++] = p[i]; b[j] = 0; t = 2; } } else if (t == 2) { // STATE 2: COPY INTERPRETER ARGS AS A SINGLE ARGUMENT if (p[i] == '\n') { *args = b; return true; } else { b[j++] = p[i]; b[j] = 0; } } else { __builtin_unreachable(); } } return false; } static size_t CountStrList(char **a) { size_t n = 0; while (*a++) ++n; return n; } static char **ConcatStrLists(struct Machine *m, char **a, char **b) { size_t i, n; char **c, *e; if ((c = (char **)AddToFreeList( m, malloc(((n = CountStrList(a) + CountStrList(b)) + 2) * sizeof(*c))))) { i = 0; while ((e = *a++)) c[i++] = e; while ((e = *b++)) c[i++] = e; unassert(i == n); c[i++] = 0; c[i] = 0; } return c; } static int CanEmulateData(struct Machine *m, char **prog, char ***argv, bool isfirst, char *img, size_t imglen) { char **newargv; char *interp[3] = {0}; if (IsSupportedExecutable(*prog, img, imglen)) { return 1; } else if (isfirst && HasShebang(m, img, imglen, interp, interp + 1) && CanEmulateImpl(m, interp, 0, false) && (newargv = ConcatStrLists(m, interp, *argv))) { newargv[1 + !!interp[1]] = *prog; *prog = interp[0]; *argv = newargv; return 2; } else { return 0; } } static bool IsApeBinary(const char *path) { int fd; ssize_t rc; char buf[8]; fd = open(path, O_RDONLY | O_CLOEXEC | O_NOCTTY); if (fd == -1) return false; rc = pread(fd, buf, 8, 0); close(fd); if (rc != 8) return false; return !memcmp(buf, "MZqFpD='", 8) || // !memcmp(buf, "jartsr='", 8); } void LoadProgram(struct Machine *m, char *execfn, char *prog, char **args, char **vars, const char *biosprog) { int fd; i64 stack; void *map; int status; char tmp[64]; bool isfirst; long pagesize; size_t mapsize; bool execstack; struct stat st; struct Elf *elf; static bool once; if (!once) { atexit(FreeProgName); once = true; } elf = &m->system->elf; m->system->loaded = false; unassert(GetRandom(elf->rng, sizeof(elf->rng), 0) == sizeof(elf->rng)); for (isfirst = true;;) { unassert(prog); elf->execfn = execfn; elf->prog = prog; elf->interpreter = 0; elf->at_phdr = 0; elf->at_base = -1; elf->at_phent = 56; free(g_progname); g_progname = strdup(prog); SYS_LOGF("LoadProgram %s", prog); if ((fd = VfsOpen(AT_FDCWD, prog, O_RDONLY, 0)) == -1 || VfsFstat(fd, &st) == -1 || CheckExecutableFile(prog, &st) == -1 || (map = Mmap(0, (mapsize = st.st_size), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0, "loader")) == MAP_FAILED) { WriteErrorString(prog); WriteErrorString(": failed to load executable (errno "); FormatInt64(tmp, errno); WriteErrorString(tmp); WriteErrorString(")\n"); exit(EXIT_FAILURE_EXEC_FAILED); } status = CanEmulateData(m, &prog, &args, isfirst, (char *)map, mapsize); if (!status) { WriteErrorString("\ error: unsupported executable; we need:\n\ - x86_64-linux elf executables\n\ - flat executables (.bin files)\n\ - actually portable executables (MZqFpD/jartsr)\n\ - scripts with #!shebang meeting above criteria\n"); exit(EXIT_FAILURE_EXEC_FAILED); } else if (status == 1) { break; // file is a real executable } else if (status == 2) { // turns out it's a shell script if (isfirst) { // start over using the shebang interpreter instead unassert(!VfsMunmap(map, mapsize)); unassert(!VfsClose(fd)); isfirst = false; } else { LOGF("shell scripts can't interpret shell scripts"); exit(EXIT_FAILURE_EXEC_FAILED); } } else { __builtin_unreachable(); } } ResetCpu(m); m->system->codesize = 0; m->system->codestart = 0; m->system->brk = FLAG_imagestart; m->system->automap = FLAG_automapstart; if (HasLinearMapping()) { m->system->brk ^= Read64(elf->rng) & FLAG_aslrmask; m->system->automap ^= (Read64(elf->rng) & FLAG_aslrmask); } if (m->mode.genmode == XED_GEN_MODE_REAL) { LoadBios(m, biosprog); if (IsApeBinary(prog)) { // cosmo convention (see also binbase) AddFileMap(m->system, 4 * 1024 * 1024, 512, prog, 0); } else { // sectorlisp convention AddFileMap(m->system, 0, 512, prog, 0); } } else { m->flags = SetFlag(m->flags, FLAGS_IF, 1); m->system->cr0 = CR0_PE | CR0_MP | CR0_ET | CR0_PG; m->system->cr3 = AllocatePageTable(m->system); if (IsBinFile(prog)) { elf->base = 0x400000; LoadFlatExecutable(m, elf->base, prog, map, mapsize, fd); execstack = true; } else if (READ32(map) == READ32("\177ELF")) { execstack = LoadElf(m, elf, (Elf64_Ehdr_ *)map, mapsize, fd); } else if (READ64(map) == READ64("MZqFpD='") || READ64(map) == READ64("jartsr='")) { m->system->iscosmo = true; // Cosmopolitan programs pretty much require at least 47-bit virtual // addresses; if the host lacks these, then emulate them w/ software if (FLAG_vabits < 47) FLAG_nolinear = true; if (GetElfHeader(tmp, prog, (const char *)map) == -1) exit(EXIT_FAILURE_EXEC_FAILED); memcpy(map, tmp, 64); execstack = LoadElf(m, elf, (Elf64_Ehdr_ *)map, mapsize, fd); } else { unassert(!"impossible condition"); } stack = HasLinearMapping() && FLAG_vabits <= 47 && !kSkew ? 0 : kStackTop - kStackSize; if ((stack = ReserveVirtual( m->system, stack, kStackSize, PAGE_FILE | PAGE_U | PAGE_RW | (execstack ? 0 : PAGE_XD), -1, 0, 0, 0)) != -1) { unassert(AddFileMap(m->system, stack, kStackSize, "[stack]", -1)); Put64(m->sp, stack + kStackSize); } else { LOGF("failed to reserve stack memory"); exit(EXIT_FAILURE_EXEC_FAILED); } m->system->loaded = true; // in case rwx stack is smc write-protected :'( LoadArgv(m, execfn, prog, args, vars, elf->rng); } pagesize = FLAG_pagesize; pagesize = MAX(4096, pagesize); if (elf->interpreter) { elf->interpreter = strdup(elf->interpreter); } unassert(CheckMemoryInvariants(m->system)); elf->execfn = strdup(elf->execfn); elf->prog = strdup(elf->prog); unassert(!VfsMunmap(map, mapsize)); unassert(!VfsClose(fd)); m->system->loaded = true; #ifndef DISABLE_VFS unassert(!ProcfsRegisterExe(getpid(), elf->prog)); #endif } static bool CanEmulateImpl(struct Machine *m, char **prog, char ***argv, bool isfirst) { int fd; bool res; void *img; struct stat st; if ((fd = VfsOpen(AT_FDCWD, *prog, O_RDONLY | O_CLOEXEC, 0)) == -1) { CantEmulate: LOGF("%s: can't emulate: %s", *prog, strerror(errno)); return false; } unassert(!VfsFstat(fd, &st)); if (CheckExecutableFile(*prog, &st) == -1) { VfsClose(fd); return false; } img = VfsMmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); VfsClose(fd); if (img == MAP_FAILED) goto CantEmulate; res = !!CanEmulateData(m, prog, argv, isfirst, (char *)img, st.st_size); unassert(!VfsMunmap(img, st.st_size)); return res; } bool CanEmulateExecutable(struct Machine *m, char **prog, char ***argv) { int err; bool res; err = errno; res = CanEmulateImpl(m, prog, argv, true); errno = err; return res; } ================================================ FILE: blink/loader.h ================================================ #ifndef BLINK_LOADER_H_ #define BLINK_LOADER_H_ #include "blink/elf.h" #include "blink/machine.h" bool CanEmulateExecutable(struct Machine *, char **, char ***); void BootProgram(struct Machine *, struct Elf *, u8); void LoadProgram(struct Machine *, char *, char *, char **, char **, const char *); void LoadDebugSymbols(struct System *); void LoadFileSymbols(struct System *, const char *, i64); bool IsSupportedExecutable(const char *, void *, size_t); #endif /* BLINK_LOADER_H_ */ ================================================ FILE: blink/log.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/log.h" #include #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/fspath.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/thread.h" #include "blink/tsan.h" #include "blink/types.h" #include "blink/util.h" #define LOG_ERR 0 #define LOG_INFO 1 #define DEFAULT_LOG_PATH "blink.log" #define APPEND(F, ...) \ n += F(b + n, n > PIPE_BUF ? 0 : PIPE_BUF - n, __VA_ARGS__) static struct Log { pthread_once_t_ once; int level; int fd; char *path; } g_log = { PTHREAD_ONCE_INIT_, LOG_ERR, }; static char *GetTimestamp(void) { int x; struct timespec ts; _Thread_local static i64 last; _Thread_local static char s[27]; _Thread_local static struct tm tm; IGNORE_RACES_START(); clock_gettime(CLOCK_REALTIME, &ts); if (ts.tv_sec != last) { localtime_r(&ts.tv_sec, &tm); x = tm.tm_year + 1900; s[0] = '0' + x / 1000; s[1] = '0' + x / 100 % 10; s[2] = '0' + x / 10 % 10; s[3] = '0' + x % 10; s[4] = '-'; x = tm.tm_mon + 1; s[5] = '0' + x / 10; s[6] = '0' + x % 10; s[7] = '-'; x = tm.tm_mday; s[8] = '0' + x / 10; s[9] = '0' + x % 10; s[10] = 'T'; x = tm.tm_hour; s[11] = '0' + x / 10; s[12] = '0' + x % 10; s[13] = ':'; x = tm.tm_min; s[14] = '0' + x / 10; s[15] = '0' + x % 10; s[16] = ':'; x = tm.tm_sec; s[17] = '0' + x / 10; s[18] = '0' + x % 10; s[19] = '.'; s[26] = 0; last = ts.tv_sec; } IGNORE_RACES_END(); x = ts.tv_nsec; s[20] = '0' + x / 100000000; s[21] = '0' + x / 10000000 % 10; s[22] = '0' + x / 1000000 % 10; s[23] = '0' + x / 100000 % 10; s[24] = '0' + x / 10000 % 10; s[25] = '0' + x / 1000 % 10; return s; } static void OpenLog(void) { int fd; if (!g_log.path) return; if (!strcmp(g_log.path, "-") || // !strcmp(g_log.path, "/dev/stderr")) { fd = 2; } else if (!strcmp(g_log.path, "/dev/stdout")) { fd = 1; } else { fd = open(g_log.path, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0644); if (fd == -1) { perror(g_log.path); g_log.fd = -1; return; } } unassert((g_log.fd = fcntl(fd, F_DUPFD_CLOEXEC, kMinBlinkFd)) != -1); unassert(!close(fd)); } static void Log(const char *file, int line, const char *fmt, va_list va, int level) { char b[4096]; int err, n = 0; err = errno; unassert(!pthread_once_(&g_log.once, OpenLog)); APPEND(snprintf, "%c%s:%s:%d:%d ", "EI"[level], GetTimestamp(), file, line, g_machine ? g_machine->tid : 0); APPEND(vsnprintf, fmt, va); APPEND(snprintf, "\n"); if (n > PIPE_BUF - 1) { n = PIPE_BUF - 1; b[n - 1] = '\n'; b[n - 2] = '.'; b[n - 3] = '.'; b[n - 4] = '.'; } if (g_log.fd != -1) { WriteError(g_log.fd, b, n); } if (FLAG_alsologtostderr || (!FLAG_nologstderr && level <= g_log.level)) { WriteError(2, b, n); } errno = err; } void LogErr(const char *file, int line, const char *fmt, ...) { va_list va; va_start(va, fmt); Log(file, line, fmt, va, LOG_ERR); va_end(va); } void LogInfo(const char *file, int line, const char *fmt, ...) { va_list va; va_start(va, fmt); Log(file, line, fmt, va, LOG_INFO); va_end(va); } void LogSys(const char *file, int line, const char *fmt, ...) { va_list va; va_start(va, fmt); Log(file, line, fmt, va, LOG_INFO); va_end(va); } static void FreeLogPath(void) { free(g_log.path); g_log.path = 0; } static void SetLogPath(const char *path) { if (path) { g_log.path = ExpandUser(path); } else { g_log.path = JoinPath(GetStartDir(), DEFAULT_LOG_PATH); } atexit(FreeLogPath); } void LogInit(const char *path) { WriteErrorInit(); SetLogPath(path); } ================================================ FILE: blink/log.h ================================================ #ifndef BLINK_LOG_H_ #define BLINK_LOG_H_ #include #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/flag.h" #ifndef NDEBUG #define LOG_ENABLED 1 #else #define LOG_ENABLED 0 #endif #define LOG_SIG 0 // log signal handling behaviors #define LOG_ASM 0 // log executed assembly opcodes #define LOG_JIT 0 // just-in-time compilation logs #define LOG_JIP 0 // jit path construction logging #define LOG_JIX 0 // verbose jit execution logging #define LOG_MEM 0 // system memory mapping logging #define LOG_THR 0 // multi-threaded operation logs #define LOG_ELF 0 // elf executable loader logging #define LOG_SPX 0 // speculative execution logging #define LOG_CPU 0 // produce txt file of registers #define LOG_COD 0 // produce asm file of jit codes #define LOG_VFS 0 // log from emulated filesystems #if LOG_ENABLED #define ERRF(...) LogErr(__FILE__, __LINE__, __VA_ARGS__) #define LOGF(...) LogInfo(__FILE__, __LINE__, __VA_ARGS__) #else #define ERRF(...) (void)0 #define LOGF(...) (void)0 #endif #if LOG_ENABLED #define SYS_LOGF(...) \ do { \ if (__builtin_expect(FLAG_strace, 0)) { \ LogSys(__FILE__, __LINE__, "(sys) " __VA_ARGS__); \ } \ } while (0) #else #define SYS_LOGF(...) (void)0 #endif #if LOG_SIG #define SIG_LOGF(...) LogInfo(__FILE__, __LINE__, "(sig) " __VA_ARGS__) #else #define SIG_LOGF(...) (void)0 #endif #if LOG_ASM #define ASM_LOGF(...) LogInfo(__FILE__, __LINE__, "(asm) " __VA_ARGS__) #else #define ASM_LOGF(...) (void)0 #endif #if LOG_JIT #define JIT_LOGF(...) LogInfo(__FILE__, __LINE__, "(jit) " __VA_ARGS__) #else #define JIT_LOGF(...) (void)0 #endif #if LOG_JIP #define JIP_LOGF(...) LogInfo(__FILE__, __LINE__, "(pat) " __VA_ARGS__) #else #define JIP_LOGF(...) (void)0 #endif #if LOG_JIX #define JIX_LOGF(...) LogInfo(__FILE__, __LINE__, "(jix) " __VA_ARGS__) #else #define JIX_LOGF(...) (void)0 #endif #if LOG_MEM #define MEM_LOGF(...) LogInfo(__FILE__, __LINE__, "(mem) " __VA_ARGS__) #else #define MEM_LOGF(...) (void)0 #endif #if LOG_THR #define THR_LOGF(...) LogInfo(__FILE__, __LINE__, "(thr) " __VA_ARGS__) #else #define THR_LOGF(...) (void)0 #endif #if LOG_ELF #define ELF_LOGF(...) LogInfo(__FILE__, __LINE__, "(elf) " __VA_ARGS__) #else #define ELF_LOGF(...) (void)0 #endif #if LOG_SPX #define SPX_LOGF(...) LogInfo(__FILE__, __LINE__, "(spx) " __VA_ARGS__) #else #define SPX_LOGF(...) (void)0 #endif #if LOG_VFS #define VFS_LOGF(...) LogInfo(__FILE__, __LINE__, "(vfs) " __VA_ARGS__) #else #define VFS_LOGF(...) (void)0 #endif #if LOG_ENABLED #define LOG_ONCE(x) \ do { \ static _Atomic(int) once_; \ if (!atomic_exchange_explicit(&once_, 1, memory_order_relaxed)) { \ x; \ } \ } while (0) #else #define LOG_ONCE(x) (void)0 #endif extern char *g_progname; void LogInit(const char *); void LogSys(const char *, int, const char *, ...) printf_attr(3); void LogErr(const char *, int, const char *, ...) printf_attr(3); void LogInfo(const char *, int, const char *, ...) printf_attr(3); int WriteError(int, const char *, int); void WriteErrorInit(void); int WriteErrorString(const char *); #endif /* BLINK_LOG_H_ */ ================================================ FILE: blink/logcpu.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/debug.h" #include "blink/endian.h" #include "blink/machine.h" // use cosmopolitan/tool/build/fastdiff.c void LogCpu(struct Machine *m) { static FILE *f; if (!f) f = fopen("/tmp/cpu.log", "w"); fprintf(f, "\n" "IP %" PRIx64 "\n" "AX %#" PRIx64 "\n" "CX %#" PRIx64 "\n" "DX %#" PRIx64 "\n" "BX %#" PRIx64 "\n" "SP %#" PRIx64 "\n" "BP %#" PRIx64 "\n" "SI %#" PRIx64 "\n" "DI %#" PRIx64 "\n" "R8 %#" PRIx64 "\n" "R9 %#" PRIx64 "\n" "R10 %#" PRIx64 "\n" "R11 %#" PRIx64 "\n" "R12 %#" PRIx64 "\n" "R13 %#" PRIx64 "\n" "R14 %#" PRIx64 "\n" "R15 %#" PRIx64 "\n" "FLAGS %s\n" "%s\n", m->ip, Read64(m->ax), Read64(m->cx), Read64(m->dx), Read64(m->bx), Read64(m->sp), Read64(m->bp), Read64(m->si), Read64(m->di), Read64(m->r8), Read64(m->r9), Read64(m->r10), Read64(m->r11), Read64(m->r12), Read64(m->r13), Read64(m->r14), Read64(m->r15), DescribeCpuFlags(m->flags), DescribeOp(m, GetPc(m))); } ================================================ FILE: blink/machine.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/machine.h" #include #include #include #include #include #include "blink/alu.h" #include "blink/assert.h" #include "blink/atomic.h" #include "blink/biosrom.h" #include "blink/bitscan.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/case.h" #include "blink/debug.h" #include "blink/endian.h" #include "blink/flag.h" #include "blink/flags.h" #include "blink/fpu.h" #include "blink/jit.h" #include "blink/likely.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/modrm.h" #include "blink/random.h" #include "blink/signal.h" #include "blink/sse.h" #include "blink/stats.h" #include "blink/string.h" #include "blink/swap.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/time.h" #include "blink/util.h" #include "blink/x86.h" #include "blink/xlat.h" _Thread_local siginfo_t g_siginfo; _Thread_local struct Machine *g_machine; static void OpHintNopEv(P) { } static void OpCmc(P) { m->flags ^= CF; } static void OpClc(P) { m->flags = SetFlag(m->flags, FLAGS_CF, false); } static void OpStc(P) { m->flags = SetFlag(m->flags, FLAGS_CF, true); } static void OpCli(P) { m->flags = SetFlag(m->flags, FLAGS_IF, false); } static void OpSti(P) { m->flags = SetFlag(m->flags, FLAGS_IF, true); } static void OpCld(P) { m->flags = SetFlag(m->flags, FLAGS_DF, false); } static void OpStd(P) { m->flags = SetFlag(m->flags, FLAGS_DF, true); } static void OpPushf(P) { Push(A, ExportFlags(m->flags) & 0xFCFFFF); } static void OpPopf(P) { if (!Osz(rde)) { ImportFlags(m, Pop(A, 0)); } else { ImportFlags(m, (m->flags & ~0xffff) | Pop(A, 0)); } } static void OpLahf(P) { m->ah = ExportFlags(m->flags); } static void OpSahf(P) { ImportFlags(m, (m->flags & ~0xff) | m->ah); } static void OpLeaGvqpM(P) { WriteRegister(rde, RegRexrReg(m, rde), LoadEffectiveAddress(A).addr); if (IsMakingPath(m)) { Jitter(A, "L" // res0 = LoadEffectiveAddress() "r0C"); // PutReg(RexrReg, res0) } } static void OpMovEvqpGvqp(P) { WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(A), ReadRegister(rde, RegRexrReg(m, rde))); if (IsMakingPath(m)) { Jitter(A, "A" // res0 = GetReg(RexrReg) "r0D"); // PutRegOrMem(RexbRm, res0) } } static void OpMovGvqpEvqp(P) { WriteRegister(rde, RegRexrReg(m, rde), ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(A))); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0C"); // PutReg(RexrReg, res0) } } static void OpMovzbGvqpEb(P) { WriteRegister(rde, RegRexrReg(m, rde), Load8(GetModrmRegisterBytePointerRead1(A))); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0wC"); // PutReg[force16/32/64bit](RexrReg, res0) } } static void OpMovzwGvqpEw(P) { WriteRegister(rde, RegRexrReg(m, rde), Load16(GetModrmRegisterWordPointerRead2(A))); if (IsMakingPath(m)) { Jitter(A, "z1B" // res0 = GetRegOrMem[force16bit](RexbRm) "r0C"); // PutReg(RexrReg, res0) } } static void OpMovsbGvqpEb(P) { WriteRegister(rde, RegRexrReg(m, rde), (i8)Load8(GetModrmRegisterBytePointerRead1(A))); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0x" // res0 = SignExtend(res0) "r0wC"); // PutReg[force16/32/64bit](RexrReg, res0) } } static void OpMovswGvqpEw(P) { WriteRegister(rde, RegRexrReg(m, rde), (i16)Load16(GetModrmRegisterWordPointerRead2(A))); if (IsMakingPath(m)) { Jitter(A, "z1B" // res0 = GetRegOrMem[force16bit](RexbRm) "r0z1x" // res0 = SignExtend[force16bit](res0) "r0C"); // PutReg(RexrReg, res0) } } static void OpMovslGdqpEd(P) { WriteRegister(rde, RegRexrReg(m, rde), (i32)Load32(GetModrmRegisterWordPointerRead4(A))); if (IsMakingPath(m)) { Jitter(A, "z2B" // res0 = GetRegOrMem[force32bit](RexbRm) "r0z2x" // res0 = SignExtend[force32bit](res0) "r0C"); // PutReg(RexrReg, res0) } } static relegated u64 GetDescriptorLimit(u64 d) { u64 lim = (d & 0x000f000000000000) >> 32 | (d & 0xffff); if ((d & 0x0080000000000000) != 0) lim = (lim << 12) | 0xfff; return lim; } relegated int GetDescriptor(struct Machine *m, int selector, u64 *out_descriptor) { u64 base = m->system->gdt_base, daddr; selector &= -8; if (8 <= selector && selector + 7 <= m->system->gdt_limit) { daddr = base + selector; if (daddr >= kRealSize || daddr + 8 > kRealSize) return -1; SetReadAddr(m, daddr, 8); *out_descriptor = Load64(m->system->real + daddr); return 0; } else { return -1; } } static relegated void OpLsl(P) { u64 descriptor; if (GetDescriptor(m, Load16(GetModrmRegisterWordPointerRead2(A)), &descriptor) != -1) { WriteRegister(rde, RegRexrReg(m, rde), GetDescriptorLimit(descriptor)); m->flags = SetFlag(m->flags, FLAGS_ZF, true); } else { m->flags = SetFlag(m->flags, FLAGS_ZF, false); } } void SetMachineMode(struct Machine *m, struct XedMachineMode mode) { m->mode = mode; m->system->mode = mode; } static relegated void OpXlatAlBbb(P) { i64 v; v = MaskAddress(Eamode(rde), Get64(m->bx) + Get8(m->ax)); v = DataSegment(A, v); SetReadAddr(m, v, 1); m->al = Load8(ResolveAddress(m, v)); } static void OpXchgZvqp(P) { u64 x, y; x = Get64(m->ax); y = Get64(RegRexbSrm(m, rde)); WriteRegister(rde, m->ax, y); WriteRegister(rde, RegRexbSrm(m, rde), x); } static void OpCmpxchg8b(P) { uint8_t *p; uint32_t d, a; p = GetModrmRegisterXmmPointerRead8(A); if (Lock(rde)) LockBus(p); a = Read32(p + 0); d = Read32(p + 4); if (a == Read32(m->ax) && d == Read32(m->dx)) { m->flags = SetFlag(m->flags, FLAGS_ZF, true); memcpy(p + 0, m->bx, 4); memcpy(p + 4, m->cx, 4); } else { m->flags = SetFlag(m->flags, FLAGS_ZF, false); Write32(m->ax, a); Write32(m->dx, d); } if (Lock(rde)) UnlockBus(p); } static void OpCmpxchg16b(P) { uint8_t *p; uint64_t d, a; p = GetModrmRegisterXmmPointerRead16(A); if (Lock(rde)) LockBus(p); a = Read64(p + 0); d = Read64(p + 8); if (a == Read64(m->ax) && d == Read64(m->dx)) { m->flags = SetFlag(m->flags, FLAGS_ZF, true); memcpy(p + 0, m->bx, 8); memcpy(p + 8, m->cx, 8); } else { m->flags = SetFlag(m->flags, FLAGS_ZF, false); Write64(m->ax, a); Write64(m->dx, d); } if (Lock(rde)) UnlockBus(p); } static void Op1c7(P) { bool ismem; ismem = !IsModrmRegister(rde); switch (ModrmReg(rde)) { case 1: if (ismem) { if (Rexw(rde)) { OpCmpxchg16b(A); } else { OpCmpxchg8b(A); } } else { OpUdImpl(m); } break; case 6: if (!ismem) { OpRdrand(A); } else { OpUdImpl(m); } break; case 7: if (!ismem) { if (Rep(rde) == 3) { OpRdpid(A); } else { OpRdseed(A); } } else { OpUdImpl(m); } break; default: OpUdImpl(m); } } static void TripleOp(P, const nexgen32e_f ops[3]) { nexgen32e_f op; op = ops[WordLog2(rde) - 1]; op(A); if (IsMakingPath(m)) { Jitter(A, "m", op); // call micro-op } } static void OpSax(P) { TripleOp(A, kSax); } static void OpConvert(P) { TripleOp(A, kConvert); } static void OpBswapZvqp(P) { u64 x = Get64(RegRexbSrm(m, rde)); if (Rexw(rde)) { Put64(RegRexbSrm(m, rde), SWAP64(x)); } else if (!Osz(rde)) { Put64(RegRexbSrm(m, rde), SWAP32(x)); } else { Put16(RegRexbSrm(m, rde), SWAP16(x)); } } static void OpMovAlOb(P) { i64 addr = AddressOb(A); SetWriteAddr(m, addr, 1); Put8(m->ax, Load8(ResolveAddress(m, addr))); } static void OpMovObAl(P) { i64 addr = AddressOb(A); SetReadAddr(m, addr, 1); Store8(ResolveAddress(m, addr), Get8(m->ax)); } static void OpMovRaxOvqp(P) { i64 v = DataSegment(A, disp); SetReadAddr(m, v, 1 << RegLog2(rde)); WriteRegister(rde, m->ax, ReadMemory(rde, ResolveAddress(m, v))); } static void OpMovOvqpRax(P) { i64 v = DataSegment(A, disp); SetWriteAddr(m, v, 1 << RegLog2(rde)); WriteMemory(rde, ResolveAddress(m, v), Get64(m->ax)); } static void OpMovEbGb(P) { Store8(GetModrmRegisterBytePointerWrite1(A), Get8(ByteRexrReg(m, rde))); if (IsMakingPath(m)) { Jitter(A, "A" // res0 = GetReg(RexrReg) "r0D"); // PutRegOrMem(RexbRm, res0) } } static void OpMovGbEb(P) { Put8(ByteRexrReg(m, rde), Load8(GetModrmRegisterBytePointerRead1(A))); unassert(!RegLog2(rde)); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0C"); // PutReg(RexrReg, res0) } } static void OpMovZbIb(P) { Put8(ByteRexbSrm(m, rde), uimm0); if (IsMakingPath(m)) { Jitter(A, "a2" // push arg2 "i" // = uimm0 "u" // unpop "z0F", // PutReg[force8bit](RexbSrm, arg2) uimm0); } } static void OpMovZvqpIvqp(P) { WriteRegister(rde, RegRexbSrm(m, rde), uimm0); if (IsMakingPath(m)) { if (!Rexw(rde) && !Osz(rde)) { unassert(uimm0 == (u32)uimm0); Jitter(A, "a0" // push arg2 "i" // = uimm0 "u" // unpop "z3F", // PutReg[kludge64bit](RexbSrm, arg2) uimm0); } else { Jitter(A, "a0" // push arg2 "i" // = uimm0 "u" // unpop "wF", // PutReg[force16+bit](RexbSrm, arg2) uimm0); } } } static void OpMovImm(P) { WriteRegisterOrMemoryBW(rde, GetModrmWriteBW(A), uimm0); if (IsMakingPath(m)) { Jitter(A, "a3" // push arg3 "i" // = uimm0 "u" // unpop "D", // PutRegOrMem(RexbRm, arg3) uimm0); } } // we want to have independent jit paths jump directly into one another // to avoid having control flow drop back to the main interpreter loop. void Connect(P, u64 pc, bool avoid_cycles) { #ifdef HAVE_JIT void *jump; uintptr_t f; STATISTIC(++path_connected_total); // 1. cyclic paths can block asynchronous sigs & deadlock exit // 2. we don't want to stitch together paths on separate pages if ((!avoid_cycles && m->path.start == pc) || RecordJitEdge(&m->system->jit, m->path.start, pc)) { // is a preexisting jit path installed at destination? if ((f = GetJitHook(&m->system->jit, pc)) && f != (uintptr_t)JitlessDispatch) { // tail call into the other generated jit path function jump = (u8 *)f + GetPrologueSize(); STATISTIC(++path_connected_directly); } else { STATISTIC(++path_connected_lazily); // generate assembly to drop back into main interpreter // then apply an smc fixup later on, if dest is created if (!FLAG_noconnect) { RecordJitJump(m->path.jb, pc, GetPrologueSize()); } jump = (void *)m->system->ender; } } else { // generate assembly to drop back into main interpreter STATISTIC(++path_connected_interpreter); jump = (void *)m->system->ender; } AppendJitJump(m->path.jb, jump); #endif } static void AluRo(P, const aluop_f ops[4], const aluop_f fops[4]) { ops[RegLog2(rde)](m, ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A)), ReadRegisterBW(rde, RegLog2(rde) ? RegRexrReg(m, rde) : ByteRexrReg(m, rde))); if (IsMakingPath(m)) { STATISTIC(++alu_ops); LoadAluArgs(A); switch (GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { case 0: CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "q" // arg0 = sav0 (machine) "m", // call micro-op fops[RegLog2(rde)]); break; default: Jitter(A, "q" // arg0 = sav0 (machine) "c", // call function ops[RegLog2(rde)]); break; } } } static void OpAluTest(P) { if (IsMakingPath(m) && FuseBranchTest(A)) { kAlu[ALU_AND][RegLog2(rde)]( m, ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A)), ReadRegisterBW( rde, RegLog2(rde) ? RegRexrReg(m, rde) : ByteRexrReg(m, rde))); return; } AluRo(A, kAlu[ALU_AND], kAluFast[ALU_AND]); } static void OpAluCmp(P) { if (IsMakingPath(m) && FuseBranchCmp(A, false)) { kAlu[ALU_SUB][RegLog2(rde)]( m, ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A)), ReadRegisterBW( rde, RegLog2(rde) ? RegRexrReg(m, rde) : ByteRexrReg(m, rde))); return; } AluRo(A, kAlu[ALU_SUB], kAluFast[ALU_SUB]); } static void OpAluFlip(P) { aluop_f op = kAlu[(Opcode(rde) & 070) >> 3][RegLog2(rde)]; u8 *q = RegLog2(rde) ? RegRexrReg(m, rde) : ByteRexrReg(m, rde); WriteRegisterBW(rde, q, op(m, ReadRegisterBW(rde, q), ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A)))); if (IsMakingPath(m)) { STATISTIC(++alu_ops); LoadAluFlipArgs(A); switch (GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { case 0: STATISTIC(++alu_unflagged); if (GetFlagDeps(rde)) Jitter(A, "q"); // arg0 = sav0 (machine) Jitter(A, "m" // call micro-op "r0C", // PutReg(RexrReg, res0) kJustAlu[(Opcode(rde) & 070) >> 3]); break; CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "q" // arg0 = sav0 (machine) "m" // call micro-op "r0C", // PutReg(RexrReg, res0) kAluFast[(Opcode(rde) & 070) >> 3][RegLog2(rde)]); break; default: Jitter(A, "q" // arg0 = sav0 (machine) "c" // call function "r0C", // PutReg(RexrReg, res0) op); break; } } } static void OpAluFlipCmp(P) { aluop_f op = kAlu[ALU_SUB][RegLog2(rde)]; u8 *q = RegLog2(rde) ? RegRexrReg(m, rde) : ByteRexrReg(m, rde); op(m, ReadRegisterBW(rde, q), ReadRegisterOrMemoryBW(rde, GetModrmReadBW(A))); if (IsMakingPath(m)) { STATISTIC(++alu_ops); LoadAluFlipArgs(A); switch (GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { case 0: CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "q" // arg0 = sav0 (machine) "m", // call micro-op kAluFast[ALU_SUB][RegLog2(rde)]); break; default: Jitter(A, "q" // arg0 = sav0 (machine) "c", // call function op); break; } } } static void OpAluAxImm(P) { aluop_f op; op = kAlu[(Opcode(rde) & 070) >> 3][RegLog2(rde)]; WriteRegisterBW(rde, m->ax, op(m, ReadRegisterBW(rde, m->ax), uimm0)); if (IsMakingPath(m)) { switch (GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { case 0: CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "G" // res0 = %ax "r0a1=" // arg1 = res0 "a2i" // "q" // arg0 = machine "m" // call op "r0H", // %ax = res0 uimm0, kAluFast[(Opcode(rde) & 070) >> 3][RegLog2(rde)]); break; default: Jitter(A, "G" // res0 = %ax "r0a1=" // arg1 = res0 "a2i" // "q" // arg0 = machine "c" // call op "r0H", // %ax = res0 uimm0, op); break; } } } static void OpRoAxImm(P, const aluop_f ops[4], const aluop_f fops[4]) { ops[RegLog2(rde)](m, ReadRegisterBW(rde, m->ax), uimm0); if (IsMakingPath(m)) { STATISTIC(++alu_ops); switch (GetNeededFlags(m, m->ip, CF | ZF | SF | OF | AF | PF)) { case 0: CASE_ALU_FAST: STATISTIC(++alu_simplified); Jitter(A, "G" // r0 = GetReg(AX) "a2i" // arg2 = uimm0 "r0a1=" // arg1 = res0 "q" // arg0 = sav0 (machine) "m", // call micro-op uimm0, fops[RegLog2(rde)]); break; default: Jitter(A, "G" // r0 = GetReg(AX) "a2i" // arg2 = uimm0 "r0a1=" // arg1 = res0 "q" // arg0 = sav0 (machine) "c", // call function uimm0, ops[RegLog2(rde)]); break; } } } static void OpCmpAxImm(P) { OpRoAxImm(A, kAlu[ALU_SUB], kAluFast[ALU_SUB]); } static void OpTestAxImm(P) { OpRoAxImm(A, kAlu[ALU_AND], kAluFast[ALU_AND]); } static void OpBsuwiCl(P) { aluop_f op = kBsu[ModrmReg(rde)][RegLog2(rde)]; u8 *p = GetModrmRegisterWordPointerWriteOszRexw(A); WriteRegisterOrMemory(rde, p, op(m, ReadMemory(rde, p), m->cl)); if (IsMakingPath(m)) { switch (ModrmReg(rde)) { case BSU_ROL: case BSU_ROR: case BSU_SHL: case BSU_SHR: case BSU_SAL: case BSU_SAR: if (!GetNeededFlags(m, m->ip, GetFlagClobbers(rde))) { if (Rexw(rde)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m" // call function "r0D", // PutRegOrMem(RexbRm, res0) kJustBsuCl64[ModrmReg(rde)]); } else if (!Osz(rde)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m" // call function "r0D", // PutRegOrMem(RexbRm, res0) kJustBsuCl32[ModrmReg(rde)]); } } break; default: break; } } } static void BsuwiConstant(P, u64 y) { aluop_f op = kBsu[ModrmReg(rde)][RegLog2(rde)]; u8 *p = GetModrmRegisterWordPointerWriteOszRexw(A); WriteRegisterOrMemory(rde, p, op(m, ReadMemory(rde, p), y)); if (IsMakingPath(m)) { switch (ModrmReg(rde)) { case BSU_ROL: case BSU_ROR: case BSU_SHL: case BSU_SHR: case BSU_SAL: case BSU_SAR: STATISTIC(++alu_ops); if (!GetNeededFlags(m, m->ip, GetFlagClobbers(rde))) { if (Rexw(rde) && (y &= 63)) { STATISTIC(++alu_unflagged); Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "a3i" // arg3 = shift amount "" // arg2 = undefined "" // arg1 = undefined "t" // arg0 = res0 "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) y, kJustBsu[ModrmReg(rde)]); return; } else if (!Osz(rde) && (y &= 31)) { STATISTIC(++alu_unflagged); Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "a3i" // arg3 = shift amount "" // arg2 = undefined "" // arg1 = undefined "t" // arg0 = res0 "m" // call micro-op "r0D", // PutRegOrMem(RexbRm, res0) y, kJustBsu32[ModrmReg(rde)]); return; } } break; default: break; } Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "a2i" // arg2 = shift amount "r0a1=" // arg1 = res0 "q" // arg0 = sav0 (machine) "c" // call function "r0D", // PutRegOrMem(RexbRm, res0) y, op); } } static void OpBsuwi1(P) { BsuwiConstant(A, 1); } static void OpBsuwiImm(P) { BsuwiConstant(A, uimm0); } static aluop_f Bsubi(P, u64 y) { aluop_f op = kBsu[ModrmReg(rde)][RegLog2(rde)]; u8 *a = GetModrmRegisterBytePointerWrite1(A); Store8(a, op(m, Load8(a), y)); return op; } static void OpBsubiCl(P) { aluop_f op; op = Bsubi(A, m->cl); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0s1=" // sav1 = res0 "%cl" // "r0a2=" // arg2 = res0 "s1a1=" // arg1 = sav1 "q" // arg0 = sav0 (machine) "c" // call function "r0D", op); } } static void BsubiConstant(P, u64 y) { aluop_f op; op = Bsubi(A, y); if (IsMakingPath(m)) { Jitter(A, "B" // res0 = GetRegOrMem(RexbRm) "r0a1=" // arg1 = res0 "q" // arg0 = sav0 (machine) "a2i" // "c" // call function "r0D", // y, op); } } static void OpBsubi1(P) { BsubiConstant(A, 1); } static void OpBsubiImm(P) { BsubiConstant(A, uimm0); } static void OpPushImm(P) { Push(A, uimm0); } static void GenInterrupt(P, u8 trapno) { #ifdef DISABLE_METAL HaltMachine(m, trapno); #else u16 offset; struct System *s; switch (m->mode.genmode) { default: HaltMachine(m, trapno); break; case XED_GEN_MODE_REAL: offset = (u16)trapno * 4; s = m->system; if (offset + 3 > s->idt_limit) { ThrowProtectionFault(m); } else if (!Osz(rde) || Asz(rde)) { OpUdImpl(m); } else { u8 *pfp = ReserveAddress(m, s->idt_base + offset, 4, false), *pisr; u32 fp, isrinsn; u16 isrseg, isroff; bool optim = false; fp = Load32(pfp); isrseg = (u16)(fp >> 16); isroff = (u16)fp; Push(A, ExportFlags(m->flags)); Push(A, m->cs.sel); Push(A, m->ip); // optimize for cases where ISR is simply a `hvtailcall` & a few // other conditions are met; this bypasses the usual instruction // decoding so it should be done with care to preserve semantics if (trapno < 0x80 && isrseg == kBiosSeg) { pisr = s->real + kBiosBase + isroff; if (Read8(pisr) == 0x0F) { isrinsn = Load32(pisr); if (isrinsn == ((u32)0x0F | (u32)0xFF << 8 | (u32)0167 << 16 | (u32)trapno << 24)) { optim = true; } } } if (optim) { u64 sp = Get16(m->sp); Put16(m->sp, sp + 6); HaltMachine(m, trapno); } else { m->flags = SetFlag(m->flags, FLAGS_IF, false); m->flags = SetFlag(m->flags, FLAGS_TF, false); m->flags = SetFlag(m->flags, FLAGS_AC, false); LongBranch(A, isrseg, isroff); } } } #endif } static void OpInterruptImm(P) { GenInterrupt(A, uimm0); } static void OpInterrupt1(P) { GenInterrupt(A, 1); } static void OpInterrupt3(P) { GenInterrupt(A, 3); } #ifndef DISABLE_METAL static void OpInto(P) { if (Mode(rde) != XED_MODE_LONG) { if (GetFlag(m->flags, FLAGS_OF)) HaltMachine(m, 4); } else { OpUdImpl(m); } } static void OpIret(P) { if (m->mode.genmode == XED_GEN_MODE_REAL) { OpRetf(A); if (!Osz(rde)) { // Intel V2A § 3.2 says that iretl should only update some parts of // eflags, not all; more precisely: // "tempEFLAGS ← Pop(); // EFLAGS ← (tempEFLAGS AND 257FD5H) OR (EFLAGS AND 1A0000H);" // it should be OK though to update all the bits in eflags's lower half u32 mask = ID | AC | RF | 0xffff; ImportFlags(m, (m->flags & ~mask) | (Pop(A, 0) & mask)); } else { ImportFlags(m, (m->flags & ~0xffff) | Pop(A, 0)); } } else { OpUdImpl(m); } } #endif void Terminate(P, void uop(struct Machine *, u64)) { if (IsMakingPath(m)) { Jitter(A, "a1i" // arg1 = disp "m" // call micro-op "q", // arg0 = sav0 (machine) disp, uop); AlignJit(m->path.jb, 8, 0); Connect(A, m->ip, true); FinishPath(m); } } static void OpJmp(P) { m->ip += disp; Terminate(A, FastJmp); } static cc_f GetCc(P) { int code; code = Opcode(rde) & 15; unassert(code != 0xA); // JP unassert(code != 0xB); // JNP return kConditionCode[code]; } static void OpJcc(P) { cc_f cc; cc = GetCc(A); if (IsMakingPath(m)) { FlushSkew(A); #ifdef __x86_64__ Jitter(A, "mq", cc); AlignJit(m->path.jb, 8, 4); u8 code[] = { 0x85, 0300 | kJitRes0 << 3 | kJitRes0, // test %eax,%eax 0x75, 5, // jnz +5 }; #else Jitter(A, "m" // res0 = condition code "r0a2=" // arg2 = res0 "q", // arg0 = machine cc); u32 code[] = { 0xb5000000 | (8 / 4) << 5 | kJitArg2, // cbnz x2,#8 }; #endif AppendJit(m->path.jb, code, sizeof(code)); Connect(A, m->ip, true); Jitter(A, "a1i" // arg1 = disp "m" // call micro-op "q", // arg0 = machine disp, FastJmp); AlignJit(m->path.jb, 8, 0); Connect(A, m->ip + disp, false); FinishPath(m); } if (cc(m)) { m->ip += disp; } } static void OpJp(P) { if (IsParity(m)) { m->ip += disp; } } static void OpJnp(P) { if (!IsParity(m)) { m->ip += disp; } } static void SetEb(P, bool x) { Store8(GetModrmRegisterBytePointerWrite1(A), x); } static void OpSetcc(P) { cc_f cc; cc = GetCc(A); SetEb(A, cc(m)); if (IsMakingPath(m)) { Jitter(A, "m" // call micro-op "r0z0D", // PutRegOrMem[force8](RexbRm, res0) cc); } } static void OpSetp(P) { SetEb(A, IsParity(m)); } static void OpSetnp(P) { SetEb(A, !IsParity(m)); } static void OpCmovImpl(P, bool cond) { u64 x; if (cond) { x = ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(A)); } else { x = Get64(RegRexrReg(m, rde)); } WriteRegister(rde, RegRexrReg(m, rde), x); } static void OpCmov(P) { cc_f cc; cc = GetCc(A); OpCmovImpl(A, cc(m)); if (IsMakingPath(m)) { Jitter(A, "wB" // res0 = GetRegOrMem[force16+bit](RexbRm) "r0s1=" // sav1 = res0 "wA" // res0 = GetReg[force16+bit](RexrReg) "r0s2=" // sav2 = res0 "q" // arg0 = sav0 (machine) "m" // call micro-op (cc) "s2a2=" // arg2 = sav2 "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "m" // call micro-op (Pick) "r0wC", // PutReg[force16+bit](RexrReg, res0) cc, Pick); } } static void OpCmovp(P) { OpCmovImpl(A, IsParity(m)); } static void OpCmovnp(P) { OpCmovImpl(A, !IsParity(m)); } static void OpJcxz(P) { if (!MaskAddress(Eamode(rde), Get64(m->cx))) { m->ip += disp; } } static u64 AluPopcnt(u64 x, struct Machine *m) { m->flags = SetFlag(m->flags, FLAGS_ZF, !x); m->flags = SetFlag(m->flags, FLAGS_CF, false); m->flags = SetFlag(m->flags, FLAGS_SF, false); m->flags = SetFlag(m->flags, FLAGS_OF, false); m->flags = SetFlag(m->flags, FLAGS_PF, false); return popcount(x); } static u64 AluLzcnt(u64 x, struct Machine *m, int bits) { u64 r = x ? bsf(x) : bits; m->flags = SetFlag(m->flags, FLAGS_CF, !x); m->flags = SetFlag(m->flags, FLAGS_ZF, !r); return r; } static u64 AluLzcnt64(u64 x, struct Machine *m) { return AluLzcnt(x, m, 64); } static u64 AluLzcnt32(u64 x, struct Machine *m) { return AluLzcnt(x, m, 32); } static u64 AluLzcnt16(u64 x, struct Machine *m) { return AluLzcnt(x, m, 16); } static u64 AluBsf(u64 x, struct Machine *m) { m->flags = SetFlag(m->flags, FLAGS_ZF, !x); return x ? bsf(x) : 0; } static u64 AluTzcnt(u64 x, struct Machine *m, int bits) { u64 r = x ? bsr(x) : bits; m->flags = SetFlag(m->flags, FLAGS_CF, !x); m->flags = SetFlag(m->flags, FLAGS_ZF, !r); return r; } static u64 AluTzcnt64(u64 x, struct Machine *m) { return AluTzcnt(x, m, 64); } static u64 AluTzcnt32(u64 x, struct Machine *m) { return AluTzcnt(x, m, 32); } static u64 AluTzcnt16(u64 x, struct Machine *m) { return AluTzcnt(x, m, 16); } static u64 AluBsr(u64 x, struct Machine *m) { m->flags = SetFlag(m->flags, FLAGS_ZF, !x); return x ? bsr(x) : 0; } static void Bitscan(P, u64 op(u64, struct Machine *)) { WriteRegister( rde, RegRexrReg(m, rde), op(ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(A)), m)); if (IsMakingPath(m)) { Jitter(A, "wB" // res0 = GetRegOrMem[force16+bit](RexbRm) "s0a1=" // arg1 = sav0 "t" // arg0 = res0 "c" // call function (op) "r0wC", // PutReg[force16+bit](RexrReg, res0) op); } } static void OpBsf(P) { u64 (*op)(u64, struct Machine *); if (Rep(rde) == 3) { if (Rexw(rde)) { op = AluLzcnt64; } else if (!Osz(rde)) { op = AluLzcnt32; } else { op = AluLzcnt16; } } else { op = AluBsf; } Bitscan(A, op); } static void OpBsr(P) { u64 (*op)(u64, struct Machine *); if (Rep(rde) == 3) { if (Rexw(rde)) { op = AluTzcnt64; } else if (!Osz(rde)) { op = AluTzcnt32; } else { op = AluTzcnt16; } } else { op = AluBsr; } Bitscan(A, op); } static void Op1b8(P) { if (Rep(rde) == 3) { Bitscan(A, AluPopcnt); } else { OpUdImpl(m); } } static relegated void Loop(P, bool cond) { u64 cx; cx = Get64(m->cx) - 1; if (Eamode(rde) != XED_MODE_REAL) { if (Eamode(rde) == XED_MODE_LEGACY) { cx &= 0xffffffff; } Put64(m->cx, cx); } else { cx &= 0xffff; Put16(m->cx, cx); } if (cx && cond) { m->ip += disp; } } static relegated void OpLoope(P) { Loop(A, GetFlag(m->flags, FLAGS_ZF)); } static relegated void OpLoopne(P) { Loop(A, !GetFlag(m->flags, FLAGS_ZF)); } static relegated void OpLoop1(P) { Loop(A, true); } static const nexgen32e_f kOp0f6[] = { OpTest, OpTest, OpNotEb, OpNegEb, OpMulAxAlEbUnsigned, OpMulAxAlEbSigned, OpDivAlAhAxEbUnsigned, OpDivAlAhAxEbSigned, }; static void Op0f6(P) { kOp0f6[ModrmReg(rde)](A); } static const nexgen32e_f kOp0f7[] = { OpTest, OpTest, OpNotEvqp, OpNegEvqp, OpMulRdxRaxEvqpUnsigned, OpMulRdxRaxEvqpSigned, OpDivRdxRaxEvqpUnsigned, OpDivRdxRaxEvqpSigned, }; static void Op0f7(P) { kOp0f7[ModrmReg(rde)](A); } #ifdef DISABLE_METAL #define OpCallfEq OpUd #define OpJmpfEq OpUd #endif static const nexgen32e_f kOp0ff[] = { OpIncEvqp, // OpDecEvqp, // OpCallEq, // OpCallfEq, // OpJmpEq, // OpJmpfEq, // OpPushEvq, // OpUd, // }; static void Op0ff(P) { kOp0ff[ModrmReg(rde)](A); } static void OpDoubleShift(P) { u8 *p; u8 W[2][2] = {{2, 3}, {1, 3}}; p = GetModrmRegisterWordPointerWriteOszRexw(A); WriteRegisterOrMemory( rde, p, BsuDoubleShift(m, W[Osz(rde)][Rexw(rde)], ReadMemory(rde, p), ReadRegister(rde, RegRexrReg(m, rde)), Opcode(rde) & 1 ? m->cl : uimm0, Opcode(rde) & 8)); } static void OpFxsave(P) { i64 v; u8 buf[32]; memset(buf, 0, 32); Write16(buf + 0, m->fpu.cw); #ifndef DISABLE_X87 Write16(buf + 2, m->fpu.sw); Write8(buf + 4, m->fpu.tw); Write16(buf + 6, m->fpu.op); Write32(buf + 8, m->fpu.ip); #endif Write32(buf + 24, m->mxcsr); v = ComputeAddress(A); CopyToUser(m, v + 0, buf, 32); #ifndef DISABLE_X87 CopyToUser(m, v + 32, m->fpu.st, 128); #endif CopyToUser(m, v + 160, m->xmm, 256); SetWriteAddr(m, v, 416); } static void OpFxrstor(P) { i64 v; u8 buf[32]; v = ComputeAddress(A); SetReadAddr(m, v, 416); CopyFromUser(m, buf, v + 0, 32); #ifndef DISABLE_X87 CopyFromUser(m, m->fpu.st, v + 32, 128); #endif CopyFromUser(m, m->xmm, v + 160, 256); m->fpu.cw = Load16(buf + 0); #ifndef DISABLE_X87 m->fpu.sw = Load16(buf + 2); m->fpu.tw = Load8(buf + 4); m->fpu.op = Load16(buf + 6); m->fpu.ip = Load32(buf + 8); #endif m->mxcsr = Load32(buf + 24); } static void OpXsave(P) { } static void OpLdmxcsr(P) { m->mxcsr = Load32(ComputeReserveAddressRead4(A)); } static void OpStmxcsr(P) { Store32(ComputeReserveAddressWrite4(A), m->mxcsr); } static void OpRdfsbase(P) { WriteRegister(rde, RegRexbRm(m, rde), m->fs.base); } static void OpRdgsbase(P) { WriteRegister(rde, RegRexbRm(m, rde), m->gs.base); } static void OpWrfsbase(P) { m->fs.base = ReadRegister(rde, RegRexbRm(m, rde)); } static void OpWrgsbase(P) { m->gs.base = ReadRegister(rde, RegRexbRm(m, rde)); } static void OpMfence(P) { atomic_thread_fence(memory_order_seq_cst); } static void OpLfence(P) { OpMfence(A); } static void OpSfence(P) { OpMfence(A); } static void OpWbinvd(P) { OpMfence(A); } static void OpClflush(P) { OpMfence(A); } static void Op1ae(P) { bool ismem; ismem = !IsModrmRegister(rde); switch (ModrmReg(rde)) { case 0: if (ismem) { OpFxsave(A); } else { OpRdfsbase(A); } break; case 1: if (ismem) { OpFxrstor(A); } else { OpRdgsbase(A); } break; case 2: if (ismem) { OpLdmxcsr(A); } else { OpWrfsbase(A); } break; case 3: if (ismem) { OpStmxcsr(A); } else { OpWrgsbase(A); } break; case 4: if (ismem) { OpXsave(A); } else { OpUdImpl(m); } break; case 5: OpLfence(A); break; case 6: OpMfence(A); break; case 7: if (ismem) { OpClflush(A); } else { OpSfence(A); } break; default: OpUdImpl(m); } } static relegated void OpSalc(P) { if (GetFlag(m->flags, FLAGS_CF)) { m->al = 255; } else { m->al = 0; } } static relegated void OpBofram(P) { if (disp) { m->bofram[0] = m->ip; m->bofram[1] = m->ip + (disp & 0xff); } else { m->bofram[0] = 0; m->bofram[1] = 0; } } static relegated void OpBinbase(P) { if (m->system->onbinbase) { m->system->onbinbase(m); } } static void OpNoop(P) { if (IsMakingPath(m)) { AppendJitNop(m->path.jb); } } static void OpNopEv(P) { switch (ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde)) { case 0105: OpBofram(A); break; case 0007: case 0107: case 0207: OpBinbase(A); break; default: OpNoop(A); } } #ifndef DISABLE_METAL static void OpHvcall(P) { HaltMachine(m, disp); } static void OpHvtailcall(P) { OpIret(A); HaltMachine(m, disp); } static void OpUd0GvqpEvqp(P) { if (Cpl(m) == 3) { OpUd(A); } else { // define `hvcall` & `hvtailcall` instructions which trap to our Blink // hypervisor; these are encoded as x86 "invalid opcodes" in 16-bit mode: // - 0f ff 3f hvcall 0 ud0 (%bx), %di // - 0f ff 7f disp8 hvcall ±disp ud0 ±disp(%bx), %di // - 0f ff bf disp16 hvcall ±disp ud0 ±disp(%bx), %di // - 0f ff 37 hvtailcall 0 ud0 (%bx), %si // - 0f ff 77 disp8 hvtailcall ±disp ud0 ±disp(%bx), %si // - 0f ff b7 disp16 hvtailcall ±disp ud0 ±disp(%bx), %si // // `hvcall` invokes a "hypervisor trap" with the trap number given by // the displacement value // // `hvtailcall`, when run from within an interrupt service routine, will // return (`iret`) to the ISR's caller & then invoke the numbered trap switch (Rep(rde) << 9 | ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde)) { case 00067: case 00167: case 00267: OpHvtailcall(A); break; case 00077: case 00177: case 00277: OpHvcall(A); break; default: OpUd(A); } } } #endif static void OpNop(P) { if (Rexb(rde)) { OpXchgZvqp(A); } else if (Rep(rde) == 3) { OpPause(A); } else { OpNoop(A); } } static void OpEmms(P) { #ifndef DISABLE_X87 m->fpu.tw = -1; #endif } #ifdef DISABLE_METAL #define OpCallf OpUd #define OpDecZv OpUd #define OpInAlDx OpUd #define OpInAlImm OpUd #define OpInAxDx OpUd #define OpInAxImm OpUd #define OpIncZv OpUd #define OpJmpf OpUd #define OpLds OpUd #define OpLes OpUd #define OpLfs OpUd #define OpLgs OpUd #define OpLss OpUd #define OpMovCqRq OpUd #define OpMovEvqpSw OpUd #define OpMovRqCq OpUd #define OpMovSwEvqp OpUd #define OpOutDxAl OpUd #define OpOutDxAx OpUd #define OpOutImmAl OpUd #define OpOutImmAx OpUd #define OpPopSeg OpUd #define OpPopa OpUd #define OpPushSeg OpUd #define OpPusha OpUd #define OpClts OpUd #define OpRdmsr OpUd #define OpRetf OpUd #define OpInto OpUd #define OpIret OpUd #define OpWrmsr OpUd #define OpUd0GvqpEvqp OpUd #endif #ifdef DISABLE_X87 #define OpFwait OpUd #endif #ifdef DISABLE_BMI2 #define Op2f5 OpUd #define Op2f6 OpUd #define OpShx OpUd #define OpRorx OpUd #endif #ifdef DISABLE_BCD #define OpDas OpUd #define OpAaa OpUd #define OpAas OpUd #define OpAam OpUd #define OpAad OpUd #define OpDaa OpUd #endif static const nexgen32e_f kNexgen32e[] = { /*000*/ OpAlub, // /*001*/ OpAluw, // #8 (5.653689%) /*002*/ OpAluFlip, // #180 (0.000087%) /*003*/ OpAluFlip, // #7 (5.840835%) /*004*/ OpAluAxImm, // /*005*/ OpAluAxImm, // #166 (0.000114%) /*006*/ OpPushSeg, // /*007*/ OpPopSeg, // /*008*/ OpAlub, // #154 (0.000207%) /*009*/ OpAluw, // #21 (0.520082%) /*00A*/ OpAluFlip, // #120 (0.001072%) /*00B*/ OpAluFlip, // #114 (0.001252%) /*00C*/ OpAluAxImm, // /*00D*/ OpAluAxImm, // #282 (0.000001%) /*00E*/ OpPushSeg, // /*00F*/ OpPopSeg, // /*010*/ OpAlub, // /*011*/ OpAluw, // #11 (5.307809%) /*012*/ OpAluFlip, // /*013*/ OpAluFlip, // #108 (0.001526%) /*014*/ OpAluAxImm, // #97 (0.002566%) /*015*/ OpAluAxImm, // /*016*/ OpPushSeg, // /*017*/ OpPopSeg, // /*018*/ OpAlub, // /*019*/ OpAluw, // #65 (0.015300%) /*01A*/ OpAluFlip, // /*01B*/ OpAluFlip, // #44 (0.241806%) /*01C*/ OpAluAxImm, // #96 (0.002566%) /*01D*/ OpAluAxImm, // /*01E*/ OpPushSeg, // /*01F*/ OpPopSeg, // /*020*/ OpAlub, // #165 (0.000130%) /*021*/ OpAluw, // #59 (0.019691%) /*022*/ OpAluFlip, // /*023*/ OpAluFlip, // #41 (0.279852%) /*024*/ OpAluAxImm, // #279 (0.000001%) /*025*/ OpAluAxImm, // #43 (0.275823%) /*026*/ OpUd, // /*027*/ OpDaa, // /*028*/ OpAlub, // /*029*/ OpAluw, // #29 (0.334693%) /*02A*/ OpAluFlip, // #179 (0.000087%) /*02B*/ OpAluFlip, // #71 (0.012465%) /*02C*/ OpAluAxImm, // /*02D*/ OpAluAxImm, // #112 (0.001317%) /*02E*/ OpUd, // /*02F*/ OpDas, // /*030*/ OpAlub, // #140 (0.000397%) /*031*/ OpAluw, // #3 (6.612252%) /*032*/ OpAluFlip, // #81 (0.007453%) /*033*/ OpAluFlip, // #47 (0.138021%) /*034*/ OpAluAxImm, // /*035*/ OpAluAxImm, // #295 (0.000000%) /*036*/ OpUd, // /*037*/ OpAaa, // /*038*/ OpAluCmp, // #98 (0.002454%) /*039*/ OpAluCmp, // #2 (6.687374%) /*03A*/ OpAluFlipCmp, // #103 (0.001846%) /*03B*/ OpAluFlipCmp, // #75 (0.010320%) /*03C*/ OpCmpAxImm, // #85 (0.006267%) /*03D*/ OpCmpAxImm, // #42 (0.279462%) /*03E*/ OpUd, // /*03F*/ OpAas, // /*040*/ OpIncZv, // /*041*/ OpIncZv, // /*042*/ OpIncZv, // /*043*/ OpIncZv, // /*044*/ OpIncZv, // /*045*/ OpIncZv, // /*046*/ OpIncZv, // /*047*/ OpIncZv, // /*048*/ OpDecZv, // /*049*/ OpDecZv, // /*04A*/ OpDecZv, // /*04B*/ OpDecZv, // /*04C*/ OpDecZv, // /*04D*/ OpDecZv, // /*04E*/ OpDecZv, // /*04F*/ OpDecZv, // /*050*/ OpPushZvq, // #82 (0.007191%) /*051*/ OpPushZvq, // #91 (0.003740%) /*052*/ OpPushZvq, // #138 (0.000405%) /*053*/ OpPushZvq, // #27 (0.343891%) /*054*/ OpPushZvq, // #30 (0.332411%) /*055*/ OpPushZvq, // #16 (0.661109%) /*056*/ OpPushZvq, // #35 (0.297138%) /*057*/ OpPushZvq, // #38 (0.289927%) /*058*/ OpPopZvq, // #155 (0.000199%) /*059*/ OpPopZvq, // #190 (0.000054%) /*05A*/ OpPopZvq, // #74 (0.011075%) /*05B*/ OpPopZvq, // #28 (0.343770%) /*05C*/ OpPopZvq, // #31 (0.332403%) /*05D*/ OpPopZvq, // #17 (0.659868%) /*05E*/ OpPopZvq, // #36 (0.296997%) /*05F*/ OpPopZvq, // #39 (0.289680%) /*060*/ OpPusha, // /*061*/ OpPopa, // /*062*/ OpUd, // /*063*/ OpMovslGdqpEd, // #58 (0.026117%) /*064*/ OpUd, // /*065*/ OpUd, // /*066*/ OpUd, // /*067*/ OpUd, // /*068*/ OpPushImm, // #168 (0.000112%) /*069*/ OpImulGvqpEvqpImm, // #147 (0.000253%) /*06A*/ OpPushImm, // #143 (0.000370%) /*06B*/ OpImulGvqpEvqpImm, // #131 (0.000720%) /*06C*/ OpIns, // /*06D*/ OpIns, // /*06E*/ OpOuts, // /*06F*/ OpOuts, // /*070*/ OpJcc, // #177 (0.000094%) /*071*/ OpJcc, // #200 (0.000034%) /*072*/ OpJcc, // #64 (0.015441%) /*073*/ OpJcc, // #9 (5.615257%) /*074*/ OpJcc, // #15 (0.713108%) /*075*/ OpJcc, // #13 (0.825247%) /*076*/ OpJcc, // #23 (0.475584%) /*077*/ OpJcc, // #48 (0.054677%) /*078*/ OpJcc, // #66 (0.014096%) /*079*/ OpJcc, // #84 (0.006506%) /*07A*/ OpJp, // #175 (0.000112%) /*07B*/ OpJnp, // #174 (0.000112%) /*07C*/ OpJcc, // #223 (0.000008%) /*07D*/ OpJcc, // #80 (0.007801%) /*07E*/ OpJcc, // #70 (0.012536%) /*07F*/ OpJcc, // #76 (0.010144%) /*080*/ OpAlui, // #53 (0.033021%) /*081*/ OpAlui, // #60 (0.018910%) /*082*/ OpAlui, // /*083*/ OpAlui, // #4 (6.518845%) /*084*/ OpAluTest, // #54 (0.030642%) /*085*/ OpAluTest, // #18 (0.628547%) /*086*/ OpXchgGbEb, // #219 (0.000011%) /*087*/ OpXchgGvqpEvqp, // #161 (0.000141%) /*088*/ OpMovEbGb, // #49 (0.042510%) /*089*/ OpMovEvqpGvqp, // #1 (22.226650%) /*08A*/ OpMovGbEb, // #51 (0.038177%) /*08B*/ OpMovGvqpEvqp, // #12 (2.903141%) /*08C*/ OpMovEvqpSw, // /*08D*/ OpLeaGvqpM, // #14 (0.800508%) /*08E*/ OpMovSwEvqp, // /*08F*/ OpPopEvq, // #288 (0.000000%) /*090*/ OpNop, // #218 (0.000011%) /*091*/ OpXchgZvqp, // #278 (0.000001%) /*092*/ OpXchgZvqp, // #284 (0.000001%) /*093*/ OpXchgZvqp, // #213 (0.000018%) /*094*/ OpXchgZvqp, // /*095*/ OpXchgZvqp, // /*096*/ OpXchgZvqp, // /*097*/ OpXchgZvqp, // #286 (0.000001%) /*098*/ OpSax, // #83 (0.006728%) /*099*/ OpConvert, // #163 (0.000137%) /*09A*/ OpCallf, // /*09B*/ OpFwait, // /*09C*/ OpPushf, // /*09D*/ OpPopf, // /*09E*/ OpSahf, // /*09F*/ OpLahf, // /*0A0*/ OpMovAlOb, // /*0A1*/ OpMovRaxOvqp, // /*0A2*/ OpMovObAl, // /*0A3*/ OpMovOvqpRax, // /*0A4*/ OpMovsb, // #73 (0.011594%) /*0A5*/ OpMovs, // #158 (0.000147%) /*0A6*/ OpCmps, // /*0A7*/ OpCmps, // /*0A8*/ OpTestAxImm, // #115 (0.001247%) /*0A9*/ OpTestAxImm, // #113 (0.001300%) /*0AA*/ OpStosb, // #67 (0.013327%) /*0AB*/ OpStos, // #194 (0.000044%) /*0AC*/ OpLods, // #198 (0.000035%) /*0AD*/ OpLods, // #296 (0.000000%) /*0AE*/ OpScas, // #157 (0.000152%) /*0AF*/ OpScas, // #292 (0.000000%) /*0B0*/ OpMovZbIb, // #135 (0.000500%) /*0B1*/ OpMovZbIb, // #178 (0.000093%) /*0B2*/ OpMovZbIb, // #176 (0.000099%) /*0B3*/ OpMovZbIb, // #202 (0.000028%) /*0B4*/ OpMovZbIb, // /*0B5*/ OpMovZbIb, // #220 (0.000010%) /*0B6*/ OpMovZbIb, // #136 (0.000488%) /*0B7*/ OpMovZbIb, // #216 (0.000014%) /*0B8*/ OpMovZvqpIvqp, // #33 (0.315404%) /*0B9*/ OpMovZvqpIvqp, // #50 (0.039176%) /*0BA*/ OpMovZvqpIvqp, // #32 (0.315927%) /*0BB*/ OpMovZvqpIvqp, // #93 (0.003549%) /*0BC*/ OpMovZvqpIvqp, // #109 (0.001380%) /*0BD*/ OpMovZvqpIvqp, // #101 (0.002061%) /*0BE*/ OpMovZvqpIvqp, // #68 (0.013223%) /*0BF*/ OpMovZvqpIvqp, // #79 (0.008900%) /*0C0*/ OpBsubiImm, // #111 (0.001368%) /*0C1*/ OpBsuwiImm, // #20 (0.536537%) /*0C2*/ OpRetIw, // /*0C3*/ OpRet, // #24 (0.422698%) /*0C4*/ OpLes, // /*0C5*/ OpLds, // /*0C6*/ OpMovImm, // #90 (0.004525%) /*0C7*/ OpMovImm, // #45 (0.161349%) /*0C8*/ OpEnter, // /*0C9*/ OpLeave, // #116 (0.001237%) /*0CA*/ OpRetf, // /*0CB*/ OpRetf, // /*0CC*/ OpInterrupt3, // /*0CD*/ OpInterruptImm, // /*0CE*/ OpInto, // /*0CF*/ OpIret, // /*0D0*/ OpBsubi1, // #212 (0.000021%) /*0D1*/ OpBsuwi1, // #61 (0.016958%) /*0D2*/ OpBsubiCl, // /*0D3*/ OpBsuwiCl, // #19 (0.621270%) /*0D4*/ OpAam, // /*0D5*/ OpAad, // /*0D6*/ OpSalc, // /*0D7*/ OpXlatAlBbb, // /*0D8*/ OpFpu, // #258 (0.000005%) /*0D9*/ OpFpu, // #145 (0.000335%) /*0DA*/ OpFpu, // #290 (0.000000%) /*0DB*/ OpFpu, // #139 (0.000399%) /*0DC*/ OpFpu, // #283 (0.000001%) /*0DD*/ OpFpu, // #144 (0.000340%) /*0DE*/ OpFpu, // #193 (0.000046%) /*0DF*/ OpFpu, // #215 (0.000014%) /*0E0*/ OpLoopne, // /*0E1*/ OpLoope, // /*0E2*/ OpLoop1, // /*0E3*/ OpJcxz, // /*0E4*/ OpInAlImm, // /*0E5*/ OpInAxImm, // /*0E6*/ OpOutImmAl, // /*0E7*/ OpOutImmAx, // /*0E8*/ OpCallJvds, // #25 (0.403872%) /*0E9*/ OpJmp, // #22 (0.476546%) /*0EA*/ OpJmpf, // /*0EB*/ OpJmp, // #6 (6.012044%) /*0EC*/ OpInAlDx, // /*0ED*/ OpInAxDx, // /*0EE*/ OpOutDxAl, // /*0EF*/ OpOutDxAx, // /*0F0*/ OpUd, // /*0F1*/ OpInterrupt1, // /*0F2*/ OpUd, // /*0F3*/ OpUd, // /*0F4*/ OpHlt, // /*0F5*/ OpCmc, // /*0F6*/ Op0f6, // #56 (0.028122%) /*0F7*/ Op0f7, // #10 (5.484639%) /*0F8*/ OpClc, // #156 (0.000187%) /*0F9*/ OpStc, // /*0FA*/ OpCli, // /*0FB*/ OpSti, // /*0FC*/ OpCld, // #142 (0.000379%) /*0FD*/ OpStd, // #141 (0.000379%) /*0FE*/ Op0fe, // #181 (0.000083%) /*0FF*/ Op0ff, // #5 (6.314024%) /*100*/ OpUd, // /*101*/ Op101, // /*102*/ OpUd, // /*103*/ OpLsl, // /*104*/ OpUd, // /*105*/ OpSyscall, // #133 (0.000663%) /*106*/ OpClts, // /*107*/ OpUd, // /*108*/ OpUd, // /*109*/ OpWbinvd, // /*10A*/ OpUd, // /*10B*/ OpUd, // /*10C*/ OpUd, // /*10D*/ OpHintNopEv, // /*10E*/ OpUd, // /*10F*/ OpUd, // /*110*/ OpMov0f10, // #89 (0.004629%) /*111*/ OpMovWpsVps, // #104 (0.001831%) /*112*/ OpMov0f12, // /*113*/ OpMov0f13, // /*114*/ OpUnpcklpsd, // /*115*/ OpUnpckhpsd, // /*116*/ OpMov0f16, // /*117*/ OpMov0f17, // /*118*/ OpHintNopEv, // /*119*/ OpHintNopEv, // /*11A*/ OpHintNopEv, // /*11B*/ OpHintNopEv, // /*11C*/ OpHintNopEv, // /*11D*/ OpHintNopEv, // /*11E*/ OpHintNopEv, // /*11F*/ OpNopEv, // #62 (0.016260%) /*120*/ OpMovRqCq, // /*121*/ OpUd, // /*122*/ OpMovCqRq, // /*123*/ OpUd, // /*124*/ OpUd, // /*125*/ OpUd, // /*126*/ OpUd, // /*127*/ OpUd, // /*128*/ OpMov0f28, // #100 (0.002220%) /*129*/ OpMovWpsVps, // #99 (0.002294%) /*12A*/ OpCvt0f2a, // #173 (0.000112%) /*12B*/ OpMov0f2b, // /*12C*/ OpCvtt0f2c, // #172 (0.000112%) /*12D*/ OpCvt0f2d, // /*12E*/ OpComissVsWs, // #153 (0.000223%) /*12F*/ OpComissVsWs, // #152 (0.000223%) /*130*/ OpWrmsr, // /*131*/ OpRdtsc, // #214 (0.000016%) /*132*/ OpRdmsr, // /*133*/ OpUd, // /*134*/ OpUd, // /*135*/ OpUd, // /*136*/ OpUd, // /*137*/ OpUd, // /*138*/ OpUd, // /*139*/ OpUd, // /*13A*/ OpUd, // /*13B*/ OpUd, // /*13C*/ OpUd, // /*13D*/ OpUd, // /*13E*/ OpUd, // /*13F*/ OpUd, // /*140*/ OpCmov, // /*141*/ OpCmov, // /*142*/ OpCmov, // #69 (0.012667%) /*143*/ OpCmov, // #276 (0.000002%) /*144*/ OpCmov, // #134 (0.000584%) /*145*/ OpCmov, // #132 (0.000700%) /*146*/ OpCmov, // #125 (0.000945%) /*147*/ OpCmov, // #40 (0.289378%) /*148*/ OpCmov, // #130 (0.000774%) /*149*/ OpCmov, // #149 (0.000228%) /*14A*/ OpCmovp, // /*14B*/ OpCmovnp, // /*14C*/ OpCmov, // #102 (0.002008%) /*14D*/ OpCmov, // #196 (0.000044%) /*14E*/ OpCmov, // #110 (0.001379%) /*14F*/ OpCmov, // #121 (0.001029%) /*150*/ OpMovmskpsd, // /*151*/ OpSqrtpsd, // /*152*/ OpRsqrtps, // /*153*/ OpRcpps, // /*154*/ OpAndpsd, // #171 (0.000112%) /*155*/ OpAndnpsd, // /*156*/ OpOrpsd, // /*157*/ OpXorpsd, // #148 (0.000245%) /*158*/ OpAddpsd, // #151 (0.000223%) /*159*/ OpMulpsd, // #150 (0.000223%) /*15A*/ OpCvt0f5a, // /*15B*/ OpCvt0f5b, // /*15C*/ OpSubpsd, // #146 (0.000335%) /*15D*/ OpMinpsd, // /*15E*/ OpDivpsd, // #170 (0.000112%) /*15F*/ OpMaxpsd, // /*160*/ OpSsePunpcklbw, // #259 (0.000003%) /*161*/ OpSsePunpcklwd, // #221 (0.000009%) /*162*/ OpSsePunpckldq, // #262 (0.000003%) /*163*/ OpSsePacksswb, // #297 (0.000000%) /*164*/ OpSsePcmpgtb, // #274 (0.000003%) /*165*/ OpSsePcmpgtw, // #273 (0.000003%) /*166*/ OpSsePcmpgtd, // #272 (0.000003%) /*167*/ OpSsePackuswb, // #231 (0.000005%) /*168*/ OpSsePunpckhbw, // #271 (0.000003%) /*169*/ OpSsePunpckhwd, // #261 (0.000003%) /*16A*/ OpSsePunpckhdq, // #260 (0.000003%) /*16B*/ OpSsePackssdw, // #257 (0.000005%) /*16C*/ OpSsePunpcklqdq, // #264 (0.000003%) /*16D*/ OpSsePunpckhqdq, // #263 (0.000003%) /*16E*/ OpMov0f6e, // #289 (0.000000%) /*16F*/ OpMov0f6f, // #191 (0.000051%) /*170*/ OpShuffle, // #164 (0.000131%) /*171*/ Op171, // #294 (0.000000%) /*172*/ Op172, // #293 (0.000000%) /*173*/ Op173, // #211 (0.000022%) /*174*/ OpSsePcmpeqb, // #118 (0.001215%) /*175*/ OpSsePcmpeqw, // #201 (0.000028%) /*176*/ OpSsePcmpeqd, // #222 (0.000008%) /*177*/ OpEmms, // /*178*/ OpUd, // /*179*/ OpUd, // /*17A*/ OpUd, // /*17B*/ OpUd, // /*17C*/ OpHaddpsd, // /*17D*/ OpHsubpsd, // /*17E*/ OpMov0f7e, // #122 (0.001005%) /*17F*/ OpMov0f7f, // #192 (0.000048%) /*180*/ OpJcc, // /*181*/ OpJcc, // /*182*/ OpJcc, // #107 (0.001532%) /*183*/ OpJcc, // #72 (0.011761%) /*184*/ OpJcc, // #55 (0.029121%) /*185*/ OpJcc, // #57 (0.027593%) /*186*/ OpJcc, // #46 (0.147358%) /*187*/ OpJcc, // #86 (0.005907%) /*188*/ OpJcc, // #106 (0.001569%) /*189*/ OpJcc, // #160 (0.000142%) /*18A*/ OpJp, // /*18B*/ OpJnp, // /*18C*/ OpJcc, // #105 (0.001786%) /*18D*/ OpJcc, // #281 (0.000001%) /*18E*/ OpJcc, // #77 (0.009607%) /*18F*/ OpJcc, // #126 (0.000890%) /*190*/ OpSetcc, // #280 (0.000001%) /*191*/ OpSetcc, // /*192*/ OpSetcc, // #26 (0.364366%) /*193*/ OpSetcc, // #183 (0.000063%) /*194*/ OpSetcc, // #78 (0.009363%) /*195*/ OpSetcc, // #94 (0.003096%) /*196*/ OpSetcc, // #162 (0.000139%) /*197*/ OpSetcc, // #92 (0.003559%) /*198*/ OpSetcc, // /*199*/ OpSetcc, // /*19A*/ OpSetp, // /*19B*/ OpSetnp, // /*19C*/ OpSetcc, // #119 (0.001079%) /*19D*/ OpSetcc, // #275 (0.000002%) /*19E*/ OpSetcc, // #167 (0.000112%) /*19F*/ OpSetcc, // #95 (0.002688%) /*1A0*/ OpPushSeg, // /*1A1*/ OpPopSeg, // /*1A2*/ OpCpuid, // #285 (0.000001%) /*1A3*/ OpBit, // /*1A4*/ OpDoubleShift, // /*1A5*/ OpDoubleShift, // /*1A6*/ OpUd, // /*1A7*/ OpUd, // /*1A8*/ OpPushSeg, // /*1A9*/ OpPopSeg, // /*1AA*/ OpUd, // /*1AB*/ OpBit, // #291 (0.000000%) /*1AC*/ OpDoubleShift, // /*1AD*/ OpDoubleShift, // /*1AE*/ Op1ae, // #287 (0.000000%) /*1AF*/ OpImulGvqpEvqp, // #34 (0.299503%) /*1B0*/ OpCmpxchgEbAlGb, // /*1B1*/ OpCmpxchgEvqpRaxGvqp, // #87 (0.005376%) /*1B2*/ OpLss, // /*1B3*/ OpBit, // #199 (0.000035%) /*1B4*/ OpLfs, // /*1B5*/ OpLgs, // /*1B6*/ OpMovzbGvqpEb, // #37 (0.296523%) /*1B7*/ OpMovzwGvqpEw, // #137 (0.000433%) /*1B8*/ Op1b8, // /*1B9*/ OpUd, // /*1BA*/ OpBit, // #127 (0.000879%) /*1BB*/ OpBit, // /*1BC*/ OpBsf, // #88 (0.005117%) /*1BD*/ OpBsr, // #123 (0.000985%) /*1BE*/ OpMovsbGvqpEb, // #52 (0.035351%) /*1BF*/ OpMovswGvqpEw, // #63 (0.015753%) /*1C0*/ OpXaddEbGb, // /*1C1*/ OpXaddEvqpGvqp, // /*1C2*/ OpCmppsd, // /*1C3*/ OpMovntiMdqpGdqp, // /*1C4*/ OpPinsrwVdqEwIb, // #124 (0.000981%) /*1C5*/ OpPextrwGdqpUdqIb, // #277 (0.000002%) /*1C6*/ OpShufpsd, // /*1C7*/ Op1c7, // #189 (0.000054%) /*1C8*/ OpBswapZvqp, // #159 (0.000145%) /*1C9*/ OpBswapZvqp, // #182 (0.000069%) /*1CA*/ OpBswapZvqp, // #197 (0.000039%) /*1CB*/ OpBswapZvqp, // #217 (0.000012%) /*1CC*/ OpBswapZvqp, // /*1CD*/ OpBswapZvqp, // /*1CE*/ OpBswapZvqp, // #129 (0.000863%) /*1CF*/ OpBswapZvqp, // #128 (0.000863%) /*1D0*/ OpAddsubpsd, // /*1D1*/ OpSsePsrlwv, // #256 (0.000005%) /*1D2*/ OpSsePsrldv, // #255 (0.000005%) /*1D3*/ OpSsePsrlqv, // #254 (0.000005%) /*1D4*/ OpSsePaddq, // #253 (0.000005%) /*1D5*/ OpSsePmullw, // #188 (0.000054%) /*1D6*/ OpMov0fD6, // #169 (0.000112%) /*1D7*/ OpPmovmskbGdqpNqUdq, // #117 (0.001235%) /*1D8*/ OpSsePsubusb, // #252 (0.000005%) /*1D9*/ OpSsePsubusw, // #251 (0.000005%) /*1DA*/ OpSsePminub, // #250 (0.000005%) /*1DB*/ OpSsePand, // #249 (0.000005%) /*1DC*/ OpSsePaddusb, // #248 (0.000005%) /*1DD*/ OpSsePaddusw, // #247 (0.000005%) /*1DE*/ OpSsePmaxub, // #246 (0.000005%) /*1DF*/ OpSsePandn, // #245 (0.000005%) /*1E0*/ OpSsePavgb, // #244 (0.000005%) /*1E1*/ OpSsePsrawv, // #230 (0.000005%) /*1E2*/ OpSsePsradv, // #224 (0.000008%) /*1E3*/ OpSsePavgw, // #243 (0.000005%) /*1E4*/ OpSsePmulhuw, // #229 (0.000005%) /*1E5*/ OpSsePmulhw, // #187 (0.000054%) /*1E6*/ OpCvt0fE6, // /*1E7*/ OpMov0fE7, // /*1E8*/ OpSsePsubsb, // #242 (0.000005%) /*1E9*/ OpSsePsubsw, // #241 (0.000005%) /*1EA*/ OpSsePminsw, // #240 (0.000005%) /*1EB*/ OpSsePor, // #239 (0.000005%) /*1EC*/ OpSsePaddsb, // #238 (0.000005%) /*1ED*/ OpSsePaddsw, // #228 (0.000006%) /*1EE*/ OpSsePmaxsw, // #237 (0.000005%) /*1EF*/ OpSsePxor, // #195 (0.000044%) /*1F0*/ OpLddquVdqMdq, // /*1F1*/ OpSsePsllwv, // #226 (0.000006%) /*1F2*/ OpSsePslldv, // #225 (0.000006%) /*1F3*/ OpSsePsllqv, // #236 (0.000005%) /*1F4*/ OpSsePmuludq, // #186 (0.000054%) /*1F5*/ OpSsePmaddwd, // #185 (0.000054%) /*1F6*/ OpSsePsadbw, // #270 (0.000003%) /*1F7*/ OpMaskMovDiXmmRegXmmRm, // /*1F8*/ OpSsePsubb, // #235 (0.000005%) /*1F9*/ OpSsePsubw, // #234 (0.000005%) /*1FA*/ OpSsePsubd, // #184 (0.000054%) /*1FB*/ OpSsePsubq, // #269 (0.000003%) /*1FC*/ OpSsePaddb, // #233 (0.000005%) /*1FD*/ OpSsePaddw, // #227 (0.000006%) /*1FE*/ OpSsePaddd, // #232 (0.000005%) /*1FF*/ OpUd0GvqpEvqp, // /*200*/ OpSsePshufb, // #268 (0.000003%) /*201*/ OpSsePhaddw, // #204 (0.000027%) /*202*/ OpSsePhaddd, // #210 (0.000027%) /*203*/ OpSsePhaddsw, // #203 (0.000027%) /*204*/ OpSsePmaddubsw, // #209 (0.000027%) /*205*/ OpSsePhsubw, // #208 (0.000027%) /*206*/ OpSsePhsubd, // #207 (0.000027%) /*207*/ OpSsePhsubsw, // #206 (0.000027%) /*208*/ OpSsePsignb, // #267 (0.000003%) /*209*/ OpSsePsignw, // #266 (0.000003%) /*20A*/ OpSsePsignd, // #265 (0.000003%) /*20B*/ OpSsePmulhrsw, // #205 (0.000027%) }; nexgen32e_f GetOp(long op) { if (op < ARRAYLEN(kNexgen32e)) { return kNexgen32e[op]; } else { switch (op) { XLAT(0x21c, OpSsePabsb); XLAT(0x21d, OpSsePabsw); XLAT(0x21e, OpSsePabsd); XLAT(0x22a, OpMovntdqaVdqMdq); XLAT(0x240, OpSsePmulld); XLAT(0x2f0, Op2f01); XLAT(0x2f1, Op2f01); XLAT(0x2f5, Op2f5); XLAT(0x2f6, Op2f6); XLAT(0x2f7, OpShx); XLAT(0x30f, OpSsePalignr); XLAT(0x344, OpSsePclmulqdq); XLAT(0x3f0, OpRorx); default: return OpUd; } } } static bool CanJit(struct Machine *m) { return !IsJitDisabled(&m->system->jit); } void JitlessDispatch(P) { ASM_LOGF("decoding [%s] at address %" PRIx64, DescribeOp(m, GetPc(m)), GetPc(m)); COSTLY_STATISTIC(++instructions_dispatched); LoadInstruction(m, GetPc(m)); rde = m->xedd->op.rde; disp = m->xedd->op.disp; uimm0 = m->xedd->op.uimm0; m->oplen = Oplength(rde); m->ip += Oplength(rde); GetOp(Mopcode(rde))(A); if (m->stashaddr) CommitStash(m); m->oplen = 0; } static void GeneralDispatch(P) { #ifdef HAVE_JIT int opclass; uintptr_t jitpc = 0; bool op_overlaps_page_boundary; bool path_would_overlap_page_boundary; ASM_LOGF("decoding [%s] at address %" PRIx64, DescribeOp(m, GetPc(m)), GetPc(m)); LoadInstruction(m, GetPc(m)); rde = m->xedd->op.rde; disp = m->xedd->op.disp; uimm0 = m->xedd->op.uimm0; opclass = ClassifyOp(rde); // try to fast-track precious ops, since they hit this every time // each jit path should be fully contained within a single page op_overlaps_page_boundary = (m->ip & -4096) != ((m->ip + Oplength(rde) - 1) & -4096); path_would_overlap_page_boundary = IsMakingPath(m) && (m->ip & -4096) != (m->path.start & -4096); if (IsMakingPath(m) && (opclass == kOpPrecious || opclass == kOpSerializing || op_overlaps_page_boundary || path_would_overlap_page_boundary)) { // complete path where last instruction in path is previously run op CompletePath(A); } // if we're in a jit path, or we're able to create a new path if (IsMakingPath(m) || (opclass != kOpPrecious && opclass != kOpSerializing && !op_overlaps_page_boundary && CanJit(m) && CreatePath(A))) { // begin adding this op to the jit path unassert(opclass == kOpNormal || opclass == kOpBranching); ++m->path.elements; STATISTIC(++path_elements); AddPath_StartOp(A); jitpc = GetJitPc(m->path.jb); JIP_LOGF("adding [%s] from address %" PRIx64 " to path starting at %" PRIx64, DescribeOp(m, GetPc(m)), GetPc(m), m->path.start); } // advance the instruction pointer // record the op length so it can be rewound upon fault m->oplen = Oplength(rde); m->ip += Oplength(rde); // call the c implementation of the opcode GetOp(Mopcode(rde))(A); // cleanup after ReserveAddress() if a memory access overlapped a page if (m->stashaddr) { CommitStash(m); } if (IsMakingPath(m)) { // finish adding new element to jit path unassert(opclass == kOpNormal || opclass == kOpBranching); // did the op generate its own assembly code? if (GetJitPc(m->path.jb) != jitpc) { // it did; that means we're done AddPath_EndOp(A); } else { // otherwise generate "one size fits all" assembly code AddPath(A); AddPath_EndOp(A); STATISTIC(++path_elements_auto); } if (opclass == kOpBranching) { // branches, calls, and jumps always force end of path // unlike precious ops the branching op can be in path CompletePath(A); } } m->oplen = 0; #endif } void ExecuteInstruction(struct Machine *m) { #if LOG_CPU LogCpu(m); #endif #ifdef HAVE_JIT u8 *dst; nexgen32e_f func; unassert(m->canhalt); if (CanJit(m)) { if ((func = (nexgen32e_f)GetJitHook(&m->system->jit, m->ip))) { if (!IsMakingPath(m)) { func(DISPATCH_NOTHING); return; } else if (func == JitlessDispatch) { JIT_LOGF("abandoning path starting at %" PRIx64 " due to running into staged path", m->path.start); AbandonPath(m); func(DISPATCH_NOTHING); return; } else { JIT_LOGF("splicing path starting at %#" PRIx64 " into previously created function %p at %#" PRIx64, m->path.start, func, m->ip); FlushSkew(DISPATCH_NOTHING); AppendJitSetReg(m->path.jb, kJitArg0, kJitSav0); STATISTIC(++path_spliced); if (RecordJitEdge(&m->system->jit, m->path.start, m->ip)) { dst = (u8 *)(uintptr_t)func + GetPrologueSize(); STATISTIC(++path_connected_directly); } else { STATISTIC(++path_connected_interpreter); dst = (u8 *)m->system->ender; } AppendJitJump(m->path.jb, dst); FinishPath(m); func(DISPATCH_NOTHING); return; } } GeneralDispatch(DISPATCH_NOTHING); } else { JitlessDispatch(DISPATCH_NOTHING); } #else JitlessDispatch(DISPATCH_NOTHING); #endif } void Actor(struct Machine *mm) { #ifdef __CYGWIN__ // TODO: Why does JIT clobber %rbx on Cygwin? struct Machine *volatile m; #else struct Machine *m; #endif for (g_machine = mm, m = mm;;) { #ifndef __CYGWIN__ STATISTIC(++interps); #endif if (!atomic_load_explicit(&m->attention, memory_order_acquire)) { ExecuteInstruction(m); } else { CheckForSignals(m); } } } void Blink(struct Machine *m) { int rc; for (;;) { if (!(rc = sigsetjmp(m->onhalt, 1))) { m->canhalt = true; Actor(m); } m->sysdepth = 0; m->sigdepth = 0; m->canhalt = false; m->nofault = false; m->insyscall = false; CollectPageLocks(m); CollectGarbage(m, 0); if (IsMakingPath(m)) { AbandonPath(m); } if (rc == kMachineFatalSystemSignal) { HandleFatalSystemSignal(m, &g_siginfo); } } } void HandleFatalSystemSignal(struct Machine *m, const siginfo_t *si) { int sig; RestoreIp(m); m->faultaddr = ConvertHostToGuestAddress(m->system, si->si_addr, 0); sig = UnXlatSignal(si->si_signo); DeliverSignalToUser(m, sig, UnXlatSiCode(sig, si->si_code)); } ================================================ FILE: blink/machine.h ================================================ #ifndef BLINK_MACHINE_H_ #define BLINK_MACHINE_H_ #include #include #include #include #ifdef __COSMOPOLITAN__ #define _COSMO_SOURCE #include #endif #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/dll.h" #include "blink/elf.h" #include "blink/fds.h" #include "blink/jit.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/thread.h" #include "blink/tsan.h" #include "blink/tunables.h" #include "blink/x86.h" #define EXIT_FAILURE_EXEC_FAILED 127 #define EXIT_FAILURE_WITH_SIGNAL(sig) 128 + sig #define kArgRde 1 #define kArgDisp 2 #define kArgUimm0 3 #define kArgArg 4 #define kOpNormal 0 #define kOpBranching 1 #define kOpPrecious 2 #define kOpSerializing kOpPrecious #define kMaxThreadIds 32768 #define kMinThreadId 262144 #define kInstructionBytes 40 #define kMachineExit 256 #define kMachineHalt -1 #define kMachineDecodeError -2 #define kMachineUndefinedInstruction -3 #define kMachineSegmentationFault -4 #define kMachineEscape -5 #define kMachineDivideError -6 #define kMachineFpuException -7 #define kMachineProtectionFault -8 #define kMachineSimdException -9 #define kMachineExitTrap -10 #define kMachineFatalSystemSignal -11 #define CR0_PE 0x01 // protected mode enabled #define CR0_MP 0x02 // monitor coprocessor #define CR0_EM 0x04 // no x87 fpu present if set #define CR0_TS 0x08 // task switched x87 #define CR0_ET 0x10 // extension type 287 or 387 #define CR0_NE 0x20 // enable x87 error reporting #define CR0_WP 0x00010000 // write protect read-only pages @pl0 #define CR0_AM 0x00040000 // alignment mask #define CR0_NW 0x20000000 // global write-through cache disable #define CR0_CD 0x40000000 // global cache disable #define CR0_PG 0x80000000 // paging enabled /* Long Mode Paging @see Intel Manual V.3A §4.1 §4.5 IsValid (ignored on CR3) V┐ ┌XD:No Inst. Fetches (if NXE) IsWritable (ignored on CR3) RW┐│ │ Permit User-Mode Access - u┐││ │ Page-level Write-Through - PWT┐│││ │ Page-level Cache Disable - PCD┐││││ │ Set if has been read - Accessed┐│││││ │ Set if has been written - Dirty┐││││││ │ IsPage 2MB/1GB (if PDPTE/PDE) or PAT (if PT)┐│││││││ │ (If this maps page and CR4.PGE) Global┐││││││││ │ (If IsPage 2MB/1GB, see Intel V3A § 11.12) PAT │││││││││ │ │ │││││││││ │ ┌─────────────────────────────────────┤ │││││││││ │ Must Be 0┐│ Next Page Table Address (!IsPage) │ │││││││││ │ │├─────────────────────────────────────┤ │││││││││ │ ││ Physical Address 4KB │ │││││││││ │┌──┐┌─────┐│├────────────────────────────┐ │ign│││││││││ ││PK││ ign │││ Physical Address 2MB │ │┌┴┐│││││││││ ││ ││ ││├───────────────────┐ │ ││ ││││││││││ ││ ││ │││ Phys. Addr. 1GB │ │ ││ ││││││││││ ││ ││ │││ │ │ ││ ││││││││││ ───────────────────────────────────────────────────────────────*/ #define PAGE_V 0x0000000000000001 // valid #define PAGE_RW 0x0000000000000002 // writeable #define PAGE_U 0x0000000000000004 // permit ring3 access or read protect #define PAGE_PS 0x0000000000000080 // IsPage (PDPTE/PDE) or PAT (PT) #define PAGE_G 0x0000000000000100 // global #define PAGE_RSRV 0x0000000000000200 // PAGE_TA bits havent been chosen yet #define PAGE_HOST 0x0000000000000400 // PAGE_TA bits point to system memory #define PAGE_MAP 0x0000000000000800 // PAGE_TA bits are a linear host mmap #define PAGE_TA 0x0000fffffffff000 // bits used for host, or real address #define PAGE_GROW 0x0010000000000000 // for future support of MAP_GROWSDOWN #define PAGE_MUG 0x0020000000000000 // host page magic mapped individually #define PAGE_FILE 0x0040000000000000 // page has tracking bit in s->filemap #define PAGE_LOCK 0x0080000000000000 // a bit used to increment lock counts #define PAGE_LOCKS 0x7f80000000000000 // a page can be locked by 255 threads #define PAGE_XD 0x8000000000000000 // disable executing memory if bit set #define SREG_ES 0 #define SREG_CS 1 #define SREG_SS 2 #define SREG_DS 3 #define SREG_FS 4 #define SREG_GS 5 #define P struct Machine *m, u64 rde, i64 disp, u64 uimm0 #define A m, rde, disp, uimm0 #define DISPATCH_NOTHING m, 0, 0, 0 #define MACHINE_CONTAINER(e) DLL_CONTAINER(struct Machine, elem, e) #define FILEMAP_CONTAINER(e) DLL_CONTAINER(struct FileMap, elem, e) #define HOSTPAGE_CONTAINER(e) DLL_CONTAINER(struct HostPage, elem, e) #if defined(NOLINEAR) || defined(__SANITIZE_THREAD__) || \ defined(__CYGWIN__) || defined(__NetBSD__) || defined(__COSMOPOLITAN__) || \ defined(__FILC__) #define CanHaveLinearMemory() false #else #define CanHaveLinearMemory() CAN_64BIT #endif #ifdef HAVE_JIT #define IsMakingPath(m) m->path.jb #else #define IsMakingPath(m) 0 #endif #define HasLinearMapping() (CanHaveLinearMemory() && !FLAG_nolinear) #if CAN_64BIT #define _Atomicish(t) _Atomic(t) #else #define _Atomicish(t) t #endif MICRO_OP_SAFE u8 *ToHost(i64 v) { return (u8 *)(uintptr_t)(v + kSkew); } static inline i64 ToGuest(void *r) { i64 v = (uintptr_t)r - kSkew; return v; } struct Dis; struct Machine; typedef void (*nexgen32e_f)(P); struct FreeList { int n; void **p; }; struct HostPage { u8 *page; struct HostPage *next; }; struct HostPages { size_t n; size_t c; u8 **p; }; struct PageLock { i64 page; u8 *pslot; int sysdepth; }; struct SmcQueue { i64 p[kSmcQueueSize]; }; struct PageLocks { int i, n; struct PageLock *p; }; struct FileMap { i64 virt; // start address of map i64 size; // bytes originally mapped u64 pages; // population count of present i64 offset; // file offset (-1 if descriptive) char *path; // duplicated (owned) pointer to filename u64 *present; // bitset of present pages in [virt,virt+size) struct Dll elem; // see System::filemaps }; struct MachineFpu { #ifndef DISABLE_X87 double st[8]; u32 sw; int tw; int op; i64 ip; #endif u32 cw; i64 dp; }; struct MachineMemstat { long tables; long reserved; long committed; }; // Segment descriptor cache // @see Intel Manual V3A §3.4.3 // Currently only the base address for each segment register is maintained; // a full implementation will also cache its limit & access rights struct DescriptorCache { u16 sel; // visible selector value (or paragraph value in real mode) u64 base; // base linear address }; struct MachineState { u64 ip; struct DescriptorCache cs; struct DescriptorCache ss; struct DescriptorCache es; struct DescriptorCache ds; struct DescriptorCache fs; struct DescriptorCache gs; u8 weg[16][8]; u8 xmm[16][16]; u32 mxcsr; struct MachineFpu fpu; struct MachineMemstat memstat; }; struct Elf { char *prog; char *execfn; char *interpreter; i64 base; i64 aslr; u8 rng[16]; i64 at_base; i64 at_phdr; i64 at_phent; i64 at_entry; i64 at_phnum; }; struct OpCache { u8 stash[16]; // for memory ops that overlap page u64 codevirt; // current rip page in guest memory u8 *codehost; // current rip page in host memory u32 stashsize; // for writes that overlap page bool writable; _Atomic(bool) invalidated; u64 icache[512][kInstructionBytes / 8]; }; struct System { struct XedMachineMode mode; bool dlab; bool isfork; bool exited; bool loaded; bool iscosmo; bool trapexit; bool brkchanged; _Atomic(bool) killer; u16 gdt_limit; u16 idt_limit; int exitcode; u32 efer; int pid; unsigned next_tid; u8 *real; u64 gdt_base; u64 idt_base; u64 cr0; u64 cr2; u64 cr3; u64 cr4; i64 brk; i64 automap; i64 memchurn; i64 codestart; long codesize; _Atomic(long) rss; _Atomic(long) vss; struct Dis *dis; struct Dll *filemaps; struct MachineMemstat memstat; struct Dll *machines; uintptr_t ender; struct Jit jit; struct Fds fds; struct Elf elf; sigset_t exec_sigmask; struct sigaction_linux hands[64]; u64 blinksigs; // signals blink itself handles struct rlimit_linux rlim[RLIM_NLIMITS_LINUX]; #ifdef HAVE_THREADS pthread_cond_t_ machines_cond; pthread_mutex_t_ machines_lock; pthread_cond_t_ pagelocks_cond; pthread_mutex_t_ pagelocks_lock; pthread_mutex_t_ exec_lock; pthread_mutex_t_ sig_lock; pthread_mutex_t_ mmap_lock; #endif void (*onfilemap)(struct System *, struct FileMap *); void (*onsymbols)(struct System *); void (*onbinbase)(struct Machine *); void (*onlongbranch)(struct Machine *); void (*onromwriteattempt)(struct Machine *, u8 *); int (*exec)(char *, char *, char **, char **); void (*redraw)(bool); }; // Default segment selector values in non-metal mode, per Linux 5.9 #define USER_DS_LINUX 0x2b // default selector for ss (N.B.) #define USER_CS_LINUX 0x33 // default selector for cs struct JitPath { int skip; int elements; u64 skew; i64 start; struct JitBlock *jb; }; struct MachineTlb { i64 page; u64 entry; }; struct Machine { // u64 ip; // instruction pointer u8 oplen; // length of operation struct XedMachineMode mode; // [dup] XED_MACHINE_MODE_REAL etc. bool threaded; // must use synchronization _Atomic(bool) attention; // signals main interpreter loop u32 flags; // x86 eflags register i64 stashaddr; // it's our page overlap buffer union { // GENERAL REGISTER FILE u64 align8_; // u8 beg[128]; // u8 weg[16][8]; // struct { // union { // u8 ax[8]; // [vol] accumulator, result:1/2 struct { // u8 al; // lo byte of ax u8 ah; // hi byte of ax }; // }; // union { // u8 cx[8]; // [vol] param:4/6 struct { // u8 cl; // lo byte of cx u8 ch; // hi byte of cx }; // }; // union { // u8 dx[8]; // [vol] param:3/6, result:2/2 struct { // u8 dl; // lo byte of dx u8 dh; // hi byte of dx }; // }; // union { // u8 bx[8]; // [sav] base index struct { // u8 bl; // lo byte of bx u8 bh; // hi byte of bx }; // }; // u8 sp[8]; // [sav] stack pointer u8 bp[8]; // [sav] backtrace pointer u8 si[8]; // [vol] param:2/6 u8 di[8]; // [vol] param:1/6 u8 r8[8]; // [vol] param:5/6 u8 r9[8]; // [vol] param:6/6 u8 r10[8]; // [vol] u8 r11[8]; // [vol] u8 r12[8]; // [sav] u8 r13[8]; // [sav] u8 r14[8]; // [sav] u8 r15[8]; // [sav] }; // }; // _Alignas(16) u8 xmm[16][16]; // 128-BIT VECTOR REGISTER FILE struct XedDecodedInst *xedd; // ->opcache->icache if non-jit i64 readaddr; // so tui can show memory reads i64 writeaddr; // so tui can show memory write i64 readsize; // bytes length of last read op i64 writesize; // byte length of last write op union { // struct DescriptorCache seg[8]; // struct { // struct DescriptorCache es; // xtra segment (legacy / real) struct DescriptorCache cs; // code segment (legacy / real) struct DescriptorCache ss; // stak segment (legacy / real) struct DescriptorCache ds; // data segment (legacy / real) struct DescriptorCache fs; // thred-local segment register struct DescriptorCache gs; // winple thread-local register }; // }; // struct MachineFpu fpu; // FLOATING-POINT REGISTER FILE u32 mxcsr; // SIMD status control register pthread_t thread; // POSIX thread of this machine struct FreeList freelist; // to make system calls simpler struct PageLocks pagelocks; // track page table entry locks struct JitPath path; // under construction jit route _Atomicish(u64) signals; // [attention] pending delivery _Atomicish(u64) sigmask; // signals that've been blocked i64 bofram[2]; // helps debug bootloading code i64 faultaddr; // used for tui error reporting struct System *system; // int sigdepth; // int sysdepth; // _Atomic(bool) killed; // [attention] slay this thread _Atomic(bool) invalidated; // the tlb must be flushed bool restored; // [attention] rt_sigreturn()'d bool selfmodifying; // [attention] need usmc restore bool reserving; // bool insyscall; // bool nofault; // bool canhalt; // bool metal; // bool interrupted; // bool issigsuspend; // bool traprdtsc; // bool trapcpuid; // bool boop; // i8 trapno; // i8 segvcode; // struct MachineTlb tlb[32]; // sigjmp_buf onhalt; // struct sigaltstack_linux sigaltstack; // i64 robust_list; // i64 ctid; // int tid; // sigset_t spawn_sigmask; // struct Dll elem; // struct SmcQueue smcqueue; // struct OpCache opcache[1]; // }; // extern struct HostPages g_hostpages; extern _Thread_local siginfo_t g_siginfo; extern _Thread_local struct Machine *g_machine; extern const nexgen32e_f kConvert[3]; extern const nexgen32e_f kSax[3]; struct System *NewSystem(struct XedMachineMode); void FreeSystem(struct System *); void SignalActor(struct Machine *); void SetMachineMode(struct Machine *, struct XedMachineMode); struct Machine *NewMachine(struct System *, struct Machine *); i64 AreAllPagesUnlocked(struct System *) nosideeffect; bool IsOrphan(struct Machine *) nosideeffect; _Noreturn void Blink(struct Machine *); _Noreturn void Actor(struct Machine *); void Jitter(P, const char *, ...); void FreeMachine(struct Machine *); void InvalidateSystem(struct System *, bool, bool); void RemoveOtherThreads(struct System *); void KillOtherThreads(struct System *); void ResetCpu(struct Machine *); void ResetTlb(struct Machine *); void CollectGarbage(struct Machine *, size_t); void ResetInstructionCache(struct Machine *); nexgen32e_f GetOp(long); void LoadInstruction(struct Machine *, u64); int LoadInstruction2(struct Machine *, u64); void ExecuteInstruction(struct Machine *); u64 AllocatePageTable(struct System *); u64 AllocateAnonymousPage(struct System *); void FreeAnonymousPage(struct System *, u8 *); u64 FindPageTableEntry(struct Machine *, u64); bool CheckMemoryInvariants(struct System *) nosideeffect dontdiscard; i64 ReserveVirtual(struct System *, i64, i64, u64, int, i64, bool, bool); char *FormatPml4t(struct Machine *); i64 FindVirtual(struct System *, i64, i64); int FreeVirtual(struct System *, i64, i64); void CleanseMemory(struct System *, size_t); void LoadArgv(struct Machine *, char *, char *, char **, char **, u8[16]); _Noreturn void HaltMachine(struct Machine *, int); _Noreturn void RaiseDivideError(struct Machine *); _Noreturn void ThrowSegmentationFault(struct Machine *, i64); _Noreturn void ThrowProtectionFault(struct Machine *); _Noreturn void OpUdImpl(struct Machine *); _Noreturn void OpUd(P); void OpHlt(P); void JitlessDispatch(P); void RestoreIp(struct Machine *); void CheckForSignals(struct Machine *); void UnlockRobustFutexes(struct Machine *); void *AddToFreeList(struct Machine *, void *); bool IsValidAddrSize(i64, i64) pureconst; char **CopyStrList(struct Machine *, i64); char *CopyStr(struct Machine *, i64); char *LoadStr(struct Machine *, i64); void *Schlep(struct Machine *, i64, size_t, u64, u64); void *SchlepR(struct Machine *, i64, size_t); void *SchlepW(struct Machine *, i64, size_t); void *SchlepRW(struct Machine *, i64, size_t); bool IsValidMemory(struct Machine *, i64, i64, int); int RegisterMemory(struct Machine *, i64, void *, size_t); i64 ConvertHostToGuestAddress(struct System *, void *, u64 *); u8 *GetPageAddress(struct System *, u64, bool); u8 *GetHostAddress(struct Machine *, u64, long); u8 *AccessRam(struct Machine *, i64, size_t, void *[2], u8 *, bool); u8 *BeginLoadStore(struct Machine *, i64, size_t, void *[2], u8 *); u8 *BeginStore(struct Machine *, i64, size_t, void *[2], u8 *); u8 *BeginStoreNp(struct Machine *, i64, size_t, void *[2], u8 *); int GetFileDescriptorLimit(struct System *); bool HasPageLock(const struct Machine *, i64) nosideeffect; void CollectPageLocks(struct Machine *); u8 *LookupAddress(struct Machine *, i64); u8 *LookupAddress2(struct Machine *, i64, u64, u64); u8 *SpyAddress(struct Machine *, i64); u8 *Load(struct Machine *, i64, size_t, u8 *); u8 *MallocPage(void); u8 *RealAddress(struct Machine *, i64); u8 *ReserveAddress(struct Machine *, i64, size_t, bool); u8 *ResolveAddress(struct Machine *, i64); u8 *GetAddress(struct Machine *, i64); void CommitStash(struct Machine *); int CopyFromUser(struct Machine *, void *, i64, u64); int CopyFromUserRead(struct Machine *, void *, i64, u64); int CopyToUser(struct Machine *, i64, void *, u64); int CopyToUserWrite(struct Machine *, i64, void *, u64); void EndStore(struct Machine *, i64, size_t, void *[2], u8 *); void EndStoreNp(struct Machine *, i64, size_t, void *[2], u8 *); int GetDescriptor(struct Machine *, int, u64 *); void ResetRam(struct Machine *); void SetReadAddr(struct Machine *, i64, u32); void SetWriteAddr(struct Machine *, i64, u32); int SyncVirtual(struct System *, i64, i64, int); int ProtectVirtual(struct System *, i64, i64, int, bool); bool IsFullyMapped(struct System *, i64, i64); bool IsFullyUnmapped(struct System *, i64, i64); int GetProtection(u64); u64 SetProtection(int); int ClassifyOp(u64) pureconst; void Terminate(P, void (*)(struct Machine *, u64)); long GetMaxRss(struct System *); long GetMaxVss(struct System *); void FlushSmcQueue(struct Machine *); bool IsPageInSmcQueue(struct Machine *, i64); void AddPageToSmcQueue(struct Machine *, i64); i64 ProtectRwxMemory(struct System *, i64, i64, i64, long, int); void HandleFatalSystemSignal(struct Machine *, const siginfo_t *); bool IsSelfModifyingCodeSegfault(struct Machine *, const siginfo_t *); int FixXnuSignal(struct Machine *, int, siginfo_t *); int FixPpcSignal(struct Machine *, int, siginfo_t *); void CountOp(long *); void FastPush(struct Machine *, long); void FastPop(struct Machine *, long); void FastCall(struct Machine *, u64); void FastCallAbs(u64, struct Machine *); void FastJmp(struct Machine *, u64); void FastJmpAbs(u64, struct Machine *); void FastLeave(struct Machine *); i64 PredictRet(struct Machine *, i64); typedef void (*putreg64_f)(u64, struct Machine *); extern const putreg64_f kPutReg64[16]; u64 Pick(u32, u64, u64); typedef u32 (*cc_f)(struct Machine *); extern const cc_f kConditionCode[16]; void Push(P, u64); u64 Pop(P, u16); void PopVq(P); void PushVq(P); int OpOut(struct Machine *, u16, u32); u64 OpIn(struct Machine *, u16); void OpBit(P); void Op0fe(P); void Op101(P); void Op171(P); void Op172(P); void Op173(P); void OpAaa(P); void OpAad(P); void OpAam(P); void OpAas(P); void OpAlub(P); void OpAluw(P); void OpAluwi(P); void OpCallEq(P); void OpCallJvds(P); void OpCallf(P); void OpCallfEq(P); void OpCmpxchgEbAlGb(P); void OpCmpxchgEvqpRaxGvqp(P); void OpCpuid(P); void OpCvt0f2a(P); void OpCvt0f2d(P); void OpCvt0f5a(P); void OpCvt0f5b(P); void OpCvt0fE6(P); void OpCvtt0f2c(P); void OpDaa(P); void OpDas(P); void OpDecEvqp(P); void OpDivAlAhAxEbSigned(P); void OpDivAlAhAxEbUnsigned(P); void OpDivRdxRaxEvqpSigned(P); void OpDivRdxRaxEvqpUnsigned(P); void OpEnter(P); void OpImulGvqpEvqp(P); void OpImulGvqpEvqpImm(P); void OpIncEvqp(P); void OpJmpEq(P); void OpLeave(P); void OpMulAxAlEbSigned(P); void OpMulAxAlEbUnsigned(P); void OpMulRdxRaxEvqpSigned(P); void OpMulRdxRaxEvqpUnsigned(P); void OpNegEb(P); void OpNegEvqp(P); void OpNotEb(P); void OpNotEvqp(P); void OpPopEvq(P); void OpPopZvq(P); void OpPopa(P); void OpPushEvq(P); void OpPushZvq(P); void OpPusha(P); void OpRdrand(P); void OpRdseed(P); void OpRet(P); void OpRetf(P); void OpRetIw(P); void OpSsePclmulqdq(P); void OpXaddEbGb(P); void OpXaddEvqpGvqp(P); void OpXchgGbEb(P); void OpXchgGvqpEvqp(P); void Op2f5(P); void Op2f6(P); void OpShx(P); void OpRorx(P); void FreeBig(void *, size_t); void *AllocateBig(size_t, int, int, int, off_t); u64 MaskAddress(u32, u64); i64 GetIp(struct Machine *); i64 GetPc(struct Machine *); u64 AddressOb(P); u64 AddressDi(P); i64 AddressSi(P); u64 GetSegmentBase(P, unsigned); void SetCs(P, u16); void LongBranch(P, u16, u64); i64 DataSegment(P, u64); i64 AddSegment(P, u64, u64); void OpLddquVdqMdq(P); void OpMaskMovDiXmmRegXmmRm(P); void OpMov0f10(P); void OpMov0f12(P); void OpMov0f13(P); void OpMov0f16(P); void OpMov0f17(P); void OpMov0f28(P); void OpMov0f29(P); void OpMov0f2b(P); void OpMov0f6e(P); void OpMov0f6f(P); void OpMov0f7e(P); void OpMov0f7f(P); void OpMov0fD6(P); void OpMov0fE7(P); void OpMovWpsVps(P); void OpMovntdqaVdqMdq(P); void OpMovntiMdqpGdqp(P); void OpPmovmskbGdqpNqUdq(P); void OpUnpcklpsd(P); void OpUnpckhpsd(P); void OpPextrwGdqpUdqIb(P); void OpPinsrwVdqEwIb(P); void OpShuffle(P); void OpShufpsd(P); void OpSqrtpsd(P); void OpRsqrtps(P); void OpRcpps(P); void OpComissVsWs(P); void OpAddpsd(P); void OpMulpsd(P); void OpSubpsd(P); void OpDivpsd(P); void OpMinpsd(P); void OpMaxpsd(P); void OpCmppsd(P); void OpAndpsd(P); void OpAndnpsd(P); void OpOrpsd(P); void OpXorpsd(P); void OpHaddpsd(P); void OpHsubpsd(P); void OpAddsubpsd(P); void OpMovmskpsd(P); void OpIncZv(P); void OpDecZv(P); void OpLes(P); void OpLds(P); void OpLss(P); void OpLfs(P); void OpLgs(P); void OpJmpf(P); void OpJmpfEq(P); void OpClts(P); void OpRdmsr(P); void OpWrmsr(P); void OpMovRqCq(P); void OpMovCqRq(P); void OpInAlImm(P); void OpInAxImm(P); void OpInAlDx(P); void OpInAxDx(P); void OpOutImmAl(P); void OpOutImmAx(P); void OpOutDxAl(P); void OpOutDxAx(P); void OpMovSwEvqp(P); void OpMovEvqpSw(P); void OpPushSeg(P); void OpPopSeg(P); extern void (*AddPath_StartOp_Hook)(P); bool AddPath(P); void FlushSkew(P); bool CreatePath(P); void CompletePath(P); void AddPath_EndOp(P); bool FuseBranchTest(P); void AddPath_StartOp(P); void Connect(P, u64, bool); long GetPrologueSize(void); bool FuseBranchCmp(P, bool); i64 GetIp(struct Machine *); void FinishPath(struct Machine *); void FuseOp(struct Machine *, i64); void AbandonPath(struct Machine *); void AddIp(struct Machine *, long); void BeginCod(struct Machine *, i64); void AdvanceIp(struct Machine *, long); void SkewIp(struct Machine *, long, long); void Op2f01(P); void OpTest(P); void OpAlui(P); void LoadAluArgs(P); void LoadAluFlipArgs(P); void ZeroRegFlags(struct Machine *, long); i32 Imul32(i32, i32, struct Machine *); i64 Imul64(i64, i64, struct Machine *); void Mulx64(u64, struct Machine *, long, long); u32 JustMul32(u32, u32, struct Machine *); u64 JustMul64(u64, u64, struct Machine *); void MulAxDx(u64, struct Machine *); void JustMulAxDx(u64, struct Machine *); void OpPsdMuls1(u8 *, struct Machine *, long); void OpPsdAdds1(u8 *, struct Machine *, long); void OpPsdSubs1(u8 *, struct Machine *, long); void OpPsdDivs1(u8 *, struct Machine *, long); void OpPsdMins1(u8 *, struct Machine *, long); void OpPsdMaxs1(u8 *, struct Machine *, long); void OpPsdMuld1(u8 *, struct Machine *, long); void OpPsdAddd1(u8 *, struct Machine *, long); void OpPsdSubd1(u8 *, struct Machine *, long); void OpPsdDivd1(u8 *, struct Machine *, long); void OpPsdMind1(u8 *, struct Machine *, long); void OpPsdMaxd1(u8 *, struct Machine *, long); void Int64ToFloat(i64, struct Machine *, long); void Int32ToFloat(i32, struct Machine *, long); void Int64ToDouble(i64, struct Machine *, long); void Int32ToDouble(i32, struct Machine *, long); void MovsdWpsVpsOp(u8 *, struct Machine *, long); void LogCpu(struct Machine *); const char *GetBacktrace(struct Machine *); const char *DescribeOp(struct Machine *, i64); int GetInstruction(struct Machine *, i64, struct XedDecodedInst *); struct FileMap *GetFileMap(struct System *, i64); const char *GetDirFildesPath(struct System *, int); struct FileMap *AddFileMap(struct System *, i64, i64, const char *, u64); void FlushCod(struct JitBlock *); #if LOG_COD void SetupCod(struct Machine *); void WriteCod(const char *, ...) printf_attr(1); void LogCodOp(struct Machine *, const char *); #else #define SetupCod(m) (void)0 #define LogCodOp(m, s) (void)0 #define WriteCod(...) (void)0 #endif MICRO_OP_SAFE u8 Cpl(struct Machine *m) { return !m->metal ? 3u : m->mode.genmode != XED_GEN_MODE_REAL ? (m->cs.sel & 3u) : 0u; } #define BEGIN_NO_PAGE_FAULTS \ { \ bool nofault_; \ nofault_ = m->nofault; \ m->nofault = true #define END_NO_PAGE_FAULTS \ m->nofault = nofault_; \ } static inline u8 *FindHostPage(u64 entry) { if (HasLinearMapping()) { return (u8 *)(uintptr_t)(entry & PAGE_TA); } else { return g_hostpages.p[(entry & PAGE_TA) >> 12]; } } #endif /* BLINK_MACHINE_H_ */ ================================================ FILE: blink/macros.h ================================================ #ifndef BLINK_MACROS_H_ #define BLINK_MACROS_H_ #ifdef MIN #undef MIN #endif #ifdef MAX #undef MAX #endif #define ROUNDDOWN(X, K) ((X) & -(K)) #define ROUNDUP(X, K) (((X) + (K)-1) & -(K)) #define IS2POW(X) (!((X) & ((X)-1))) #define ABS(X) ((X) >= 0 ? (X) : -(X)) #define MIN(X, Y) ((Y) > (X) ? (X) : (Y)) #define MAX(X, Y) ((Y) < (X) ? (X) : (Y)) #define ARRAYLEN(A) \ ((long)((sizeof(A) / sizeof(*(A))) / ((unsigned)!(sizeof(A) % sizeof(*(A)))))) #endif /* BLINK_MACROS_H_ */ ================================================ FILE: blink/magikarp.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/macros.h" #include "blink/types.h" #include "blink/util.h" /** * Decimates array using John Costella's Magic Kernel Sharp. * * The Magic Kernel Sharp is the combination of two kernels: * * - `{1, 3, 3, 1}` for scaling * - `{1, 6, 1}` for sharpening * * Together they form the kernel `{-1, -3, 3, 17, 17, 3, -3, -1}` which * resembles the sinc function. Here's an example of how it works. Let's * say we want to shrink the following array in half: * * u8 A[] = {20, 20, 0, 0, 20, 20, 0, 0, 20, 20}; * * Using Magikarp, we'd write the following code: * * int i, n = Magikarp(A, ARRAYLEN(A)); * for (i = 0; i < n; ++i) { * if (i) printf(", "); * printf("%d", A[i]); * } * printf("\n"); * * Which would then print the new array: * * 20, 0, 20, 0, 20 * * @param p is array of unsigned bytes, which is modified in place * @param n is number of bytes in `p` * @return new length of array */ long Magikarp(u8 *p, long n) { u8 *q; long h, i; if (n < 2) return n; q = (u8 *)malloc(3 + n + 4); q[0] = p[0]; q[1] = p[0]; q[2] = p[0]; memcpy(q + 3, p, n); q[3 + n + 0] = p[n - 1]; q[3 + n + 1] = p[n - 1]; q[3 + n + 2] = p[n - 1]; q[3 + n + 3] = p[n - 1]; q += 3; h = (n + 1) >> 1; for (i = 0; i < h; ++i) { short x0, x1, x2, x3, x4, x5, x6, x7; x0 = q[i * 2 - 3]; x1 = q[i * 2 - 2]; x2 = q[i * 2 - 1]; x3 = q[i * 2 + 0]; x4 = q[i * 2 + 1]; x5 = q[i * 2 + 2]; x6 = q[i * 2 + 3]; x7 = q[i * 2 + 4]; x0 *= -1; x1 *= -3; x2 *= +3; x3 *= 17; x4 *= 17; x5 *= +3; x6 *= -3; x7 *= -1; x0 += x1; x2 += x3; x4 += x5; x6 += x7; x0 += x2; x4 += x6; x0 += x4; x0 += 1 << 4; x0 >>= 5; p[i] = MIN(255, MAX(0, x0)); } free(q - 3); return h; } ================================================ FILE: blink/map.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/map.h" #include #include #include #include #include #include #include "blink/assert.h" #include "blink/bitscan.h" #include "blink/bus.h" #include "blink/debug.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/tunables.h" #include "blink/types.h" #include "blink/util.h" #include "blink/vfs.h" static long GetSystemPageSize(void) { #ifdef __EMSCRIPTEN__ // "pages" in Emscripten only refer to the granularity the memory // buffer can be grown at but does not affect functions like mmap return 4096; #else long z; #ifdef _SC_GRANSIZE unassert((z = sysconf(_SC_GRANSIZE)) > 0); #else unassert((z = sysconf(_SC_PAGESIZE)) > 0); #endif unassert(IS2POW(z)); return MAX(4096, z); #endif } static void *PortableMmap(void *addr, // size_t length, // int prot, // int flags, // int fd, // off_t offset) { void *res; #ifdef HAVE_MAP_ANONYMOUS res = VfsMmap(addr, length, prot, flags, fd, offset); #else // MAP_ANONYMOUS isn't defined by POSIX.1 // they do however define the unlink hack _Static_assert(!(MAP_ANONYMOUS_ & MAP_FIXED), ""); _Static_assert(!(MAP_ANONYMOUS_ & MAP_SHARED), ""); _Static_assert(!(MAP_ANONYMOUS_ & MAP_PRIVATE), ""); int tfd; char path[] = "/tmp/blink.dat.XXXXXX"; if (~flags & MAP_ANONYMOUS_) { res = VfsMmap(addr, length, prot, flags, fd, offset); } else if ((tfd = mkstemp(path)) != -1) { unlink(path); if (!ftruncate(tfd, length)) { res = mmap(addr, length, prot, flags & ~MAP_ANONYMOUS_, tfd, 0); } else { res = MAP_FAILED; } close(tfd); } else { res = MAP_FAILED; } #endif #ifdef MAP_FIXED_NOREPLACE if ((flags & MAP_FIXED_NOREPLACE) && res == MAP_FAILED && errno == EOPNOTSUPP) { res = VfsMmap(addr, length, prot, flags & ~MAP_FIXED_NOREPLACE, fd, offset); if (res != addr) { VfsMunmap(res, length); res = MAP_FAILED; errno = EEXIST; } } #endif return res; } static int GetBitsInAddressSpace(void) { #ifdef __EMSCRIPTEN__ return 32; #else int i; void *ptr; uint64_t want; for (i = 16; i < 40; ++i) { want = UINT64_C(0x8123000000000000) >> i; if (want > UINTPTR_MAX) continue; if (Msync((void *)(uintptr_t)want, 1, MS_ASYNC, "vabits") == 0 || errno == EBUSY) { return 64 - i; } ptr = PortableMmap((void *)(uintptr_t)want, 1, PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS_, -1, 0); if (ptr != MAP_FAILED) { VfsMunmap(ptr, 1); return 64 - i; } } Abort(); #endif } static u64 GetVirtualAddressSpace(int vabits, long pagesize) { u64 vaspace; vaspace = (u64)1 << (vabits - 1); // 0000400000000000 vaspace |= vaspace - 1; // 00007fffffffffff vaspace &= ~(pagesize - 1); // 00007ffffffff000 return vaspace; } static u64 ScaleAddress(u64 address) { long pagesize; u64 result, vaspace; vaspace = FLAG_vaspace; pagesize = FLAG_pagesize; result = address; do result &= ~(pagesize - 1); while ((result & ~vaspace) && (result >>= 1)); return result; } // if the guest used mmap(0, ...) to let blink decide the address, // then the goal is to supply mmap(0, ...) to the host kernel too; // but we can't do that on systems like rasberry pi, since they'll // assign addresses greater than 2**47 which won't fit with x86_64 void InitMap(void) { FLAG_pagesize = GetSystemPageSize(); FLAG_vabits = GetBitsInAddressSpace(); FLAG_vaspace = GetVirtualAddressSpace(FLAG_vabits, FLAG_pagesize); FLAG_aslrmask = ScaleAddress(kAslrMask); FLAG_imagestart = ScaleAddress(kImageStart); FLAG_automapstart = ScaleAddress(kAutomapStart); FLAG_automapend = ScaleAddress(kAutomapEnd); FLAG_dyninterpaddr = ScaleAddress(kDynInterpAddr); FLAG_stacktop = ScaleAddress(kStackTop); } void *Mmap(void *addr, // size_t length, // int prot, // int flags, // int fd, // off_t offset, // const char *owner) { void *res; #if LOG_MEM char szbuf[16]; #endif #if defined(__NetBSD__) if (!(flags & MAP_SHARED)) { prot |= PROT_MPROTECT(PROT_EXEC | PROT_WRITE | PROT_READ); } #endif res = PortableMmap(addr, length, prot, flags, fd, offset); #if LOG_MEM FormatSize(szbuf, length, 1024); if (res != MAP_FAILED) { MEM_LOGF("%s created %s byte %smap [%p,%p) as %s flags=%#x fd=%d " "offset=%#" PRIx64, owner, szbuf, (flags & MAP_SHARED) ? "shared " : "", res, (u8 *)res + length, DescribeProt(prot), flags, fd, (i64)offset); } else { MEM_LOGF("%s failed to create %s map [%p,%p) as %s flags %#x: %s " "(system page size is %ld)", owner, szbuf, (u8 *)addr, (u8 *)addr + length, DescribeProt(prot), flags, DescribeHostErrno(errno), FLAG_pagesize); } #endif return res; } int Munmap(void *addr, size_t length) { int rc; rc = VfsMunmap(addr, length); #if LOG_MEM char szbuf[16]; FormatSize(szbuf, length, 1024); if (!rc) { MEM_LOGF("unmapped %s bytes at [%p,%p)", szbuf, addr, (u8 *)addr + length); } else { MEM_LOGF("failed to unmap %s bytes at [%p,%p): %s", szbuf, addr, (u8 *)addr + length, DescribeHostErrno(errno)); } #endif return rc; } int Mprotect(void *addr, // size_t length, // int prot, // const char *owner) { int res = VfsMprotect(addr, length, prot); #if LOG_MEM char szbuf[16]; FormatSize(szbuf, length, 1024); if (res != -1) { MEM_LOGF("%s protected %s byte map [%p,%p) as %s", owner, szbuf, addr, (u8 *)addr + length, DescribeProt(prot)); } else { MEM_LOGF("%s failed to protect %s byte map [%p,%p) as %s: %s", owner, szbuf, (u8 *)addr, (u8 *)addr + length, DescribeProt(prot), DescribeHostErrno(errno)); } #endif return res; } int Msync(void *addr, // size_t length, // int flags, // const char *owner) { #if defined(__FILC__) if (1) return 0; #endif int res = VfsMsync(addr, length, flags); #if LOG_MEM char szbuf[16]; FormatSize(szbuf, length, 1024); if (res != -1) { MEM_LOGF("%s synced %s byte map [%p,%p) as %#x", owner, szbuf, addr, (u8 *)addr + length, flags); } else { MEM_LOGF("%s failed to sync %s byte map [%p,%p) as %#x: %s", owner, szbuf, (u8 *)addr, (u8 *)addr + length, flags, DescribeHostErrno(errno)); } #endif return res; } ================================================ FILE: blink/map.h ================================================ #ifndef BLINK_MAP_H_ #define BLINK_MAP_H_ #include #include #include "blink/builtin.h" #include "blink/thread.h" #include "blink/types.h" #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 #endif #if defined(__APPLE__) && defined(__aarch64__) #include #else #define pthread_jit_write_protect_supported_np() 0 #define pthread_jit_write_protect_np(x) (void)(x) #define sys_icache_invalidate(addr, size) \ __builtin___clear_cache((char *)(addr), (char *)(addr) + (size)); #endif #ifdef HAVE_MAP_ANONYMOUS #define MAP_ANONYMOUS_ MAP_ANONYMOUS #else #define MAP_ANONYMOUS_ 0x10000000 #endif // MAP_DEMAND means use MAP_FIXED only if it won't clobber other maps #if defined(MAP_FIXED_NOREPLACE) && !defined(__SANITIZE_THREAD__) // The mmap() address parameter without MAP_FIXED is documented by // Linux as a hint for locality. However our testing indicates the // kernel is still likely to assign addresses that're outrageously // far away from what was requested. So we're just going to choose // something that's past the program break, and hope for the best. #define MAP_DEMAND MAP_FIXED_NOREPLACE #define MAP_DENIED EEXIST #elif defined(MAP_EXCL) // FreeBSD also supports this feature but it uses a clumsier errno #define MAP_DEMAND (MAP_FIXED | MAP_EXCL) #define MAP_DENIED EINVAL #else // Otherwise detect overlap when mmap() returns an unexpected address #define MAP_DEMAND 0 #define MAP_DENIED 0 #endif // from the xnu codebase #define _COMM_PAGE_START_ADDRESS UINT64_C(0x0000000FFFFFC000) #define _COMM_PAGE_APRR_SUPPORT (_COMM_PAGE_START_ADDRESS + 0x10C) #define _COMM_PAGE_APRR_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x110) #define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118) void InitMap(void); int Munmap(void *, size_t); int Msync(void *, size_t, int, const char *); void *Mmap(void *, size_t, int, int, int, off_t, const char *); int Mprotect(void *, size_t, int, const char *); void OverridePageSize(long); #endif /* BLINK_MAP_H_ */ ================================================ FILE: blink/mda.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/mda.h" #include "blink/bda.h" #include "blink/blinkenlights.h" #include "blink/buffer.h" #include "blink/macros.h" #include "blink/util.h" #define kBlink 1 #define kVisible 2 #define kUnderline 4 #define kBold 8 #define kReverse 16 #define CURSOR '_' /** * Decodes Monochrome Display Adapter attributes. * @see https://www.seasip.info/VintagePC/mda.html */ static u8 DecodeMdaAttributes(i8 a) { u8 r = 0; if (a & 0x77) { if ((a & 0x77) == 0x70) r |= kReverse; if ((a & 0x07) == 0x01) r |= kUnderline; if (a & 0x08) r |= kBold; if (a < 0) r |= kBlink; r |= kVisible; } return r; } void DrawMda(struct Panel *p, u8 v[25][80][2], int curx, int cury) { wint_t wch = 0; unsigned y, x, n, a, b, ch, attr; n = MIN(25, p->bottom - p->top); for (y = 0; y < n; ++y) { a = -1; for (x = 0; x < 80; ++x) { ch = v[y][x][0]; attr = v[y][x][1]; if (!BdaCurhidden && x == curx && y == cury) { if (ch == ' ' || ch == '\0') { ch = CURSOR; attr = 0x07; } else { wch = GetVidyaByte(ch); attr = 0x70; } a = -1; } else { wch = GetVidyaByte(ch); } b = DecodeMdaAttributes(attr); if (a != b) { a = b; AppendStr(&p->lines[y], "\033[0"); if (a & kBold) AppendStr(&p->lines[y], ";1"); if (a & kUnderline) AppendStr(&p->lines[y], ";4"); if (a & kBlink) AppendStr(&p->lines[y], ";5"); if (a & kReverse) AppendStr(&p->lines[y], ";7"); AppendChar(&p->lines[y], 'm'); } AppendWide(&p->lines[y], wch); } } } ================================================ FILE: blink/mda.h ================================================ #ifndef BLINK_MDA_H_ #define BLINK_MDA_H_ #include "blink/panel.h" #include "blink/types.h" void DrawMda(struct Panel *, u8[25][80][2], int, int); #endif /* BLINK_MDA_H_ */ ================================================ FILE: blink/memccpy.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/util.h" void *memccpy_(void *dst, const void *src, int c, size_t n) { size_t i; unsigned char *d = (unsigned char *)dst; const unsigned char *s = (const unsigned char *)src; for (i = 0; i < n; ++i) { if ((d[i] = s[i]) == (c & 255)) { return d + i + 1; } } return 0; } ================================================ FILE: blink/memcpy.h ================================================ #ifndef BLINK_MEMCPY_H_ #define BLINK_MEMCPY_H_ #include #include #include "blink/builtin.h" #if !defined(TINY) && defined(__x86_64__) && defined(__GNUC__) && \ !defined(__COSMOPOLITAN__) && !defined(__GLIBC__) && !defined(__FILC__) #ifdef memcpy #undef memcpy #endif #define memcpy(x, y, z) BetterMemcpyX86(x, y, z) forceinline void *RepMovsb(void *di, const void *si, size_t cx) { asm("rep movsb" : "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di) : "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si)); return di; } static inline void *BetterMemcpyX86(void *dst, const void *src, size_t n) { char *d; size_t i; uint64_t a, b; const char *s; d = (char *)dst; s = (const char *)src; switch (n) { case 0: return d; case 1: *d = *s; return d; case 2: __builtin_memcpy(&a, s, 2); __builtin_memcpy(d, &a, 2); return d; case 3: __builtin_memcpy(&a, s, 2); __builtin_memcpy(&b, s + 1, 2); __builtin_memcpy(d, &a, 2); __builtin_memcpy(d + 1, &b, 2); return d; case 4: __builtin_memcpy(&a, s, 4); __builtin_memcpy(d, &a, 4); return d; case 5: case 6: case 7: __builtin_memcpy(&a, s, 4); __builtin_memcpy(&b, s + n - 4, 4); __builtin_memcpy(d, &a, 4); __builtin_memcpy(d + n - 4, &b, 4); return d; case 8: __builtin_memcpy(&a, s, 8); __builtin_memcpy(d, &a, 8); return d; case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: __builtin_memcpy(&a, s, 8); __builtin_memcpy(&b, s + n - 8, 8); __builtin_memcpy(d, &a, 8); __builtin_memcpy(d + n - 8, &b, 8); return d; default: if (n <= 64) { i = 0; do { __builtin_memcpy(&a, s + i, 8); asm volatile("" ::: "memory"); __builtin_memcpy(d + i, &a, 8); } while ((i += 8) + 8 <= n); for (; i < n; ++i) d[i] = s[i]; return d; } else { RepMovsb(d, s, n); return d; } } } #endif /* MUSL */ #endif /* BLINK_MEMCPY_H_ */ ================================================ FILE: blink/memory.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include "blink/assert.h" #include "blink/biosrom.h" #include "blink/bus.h" #include "blink/checked.h" #include "blink/debug.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/pml4t.h" #include "blink/stats.h" #include "blink/thread.h" #include "blink/util.h" #include "blink/x86.h" void SetReadAddr(struct Machine *m, i64 addr, u32 size) { if (size) { m->readaddr = addr; m->readsize = size; } } void SetWriteAddr(struct Machine *m, i64 addr, u32 size) { if (size) { m->writeaddr = addr; m->writesize = size; } } u8 *GetPageAddress(struct System *s, u64 entry, bool is_cr3) { unassert(is_cr3 || (entry & PAGE_V)); unassert(~entry & PAGE_RSRV); if (entry & PAGE_HOST) { return FindHostPage(entry); } else { unassert(s->real); if ((entry & PAGE_TA) + 4096 <= kRealSize) { return s->real + (entry & PAGE_TA); } else { return 0; } } } u64 HandlePageFault(struct Machine *m, u8 *pslot, u64 entry) { u64 x, page; unassert(entry & PAGE_RSRV); unassert(!HasLinearMapping()); if (m->nofault) { m->segvcode = SEGV_MAPERR_LINUX; errno = ENOBUFS; return 0; } do { if (entry & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) { // a file-mapped page is being accessed for the first time unassert((entry & (PAGE_HOST | PAGE_MAP)) == (PAGE_HOST | PAGE_MAP)); x = entry & ~PAGE_RSRV; if (CasPte(pslot, entry, x)) { m->system->memstat.committed += 1; m->system->memstat.reserved -= 1; m->system->rss += 1; entry = x; } else { entry = LoadPte(pslot); } } else { // an anonymous page is being accessed for the first time if ((page = AllocateAnonymousPage(m->system)) == -1) { m->segvcode = SEGV_MAPERR_LINUX; entry = 0; break; } x = (page & (PAGE_TA | PAGE_HOST)) | (entry & ~(PAGE_TA | PAGE_RSRV)); if (CasPte(pslot, entry, x)) { m->system->memstat.committed += 1; m->system->memstat.reserved -= 1; entry = x; } else { FreeAnonymousPage(m->system, (u8 *)(uintptr_t)(page & PAGE_TA)); entry = LoadPte(pslot); m->system->rss -= 1; } } } while (entry & PAGE_RSRV); return entry; } bool HasPageLock(const struct Machine *m, i64 page) { int i; unassert(!(page & 4095)); for (i = m->pagelocks.i; i--;) { if (m->pagelocks.p[i].page == page) { return true; } } return false; } static bool RecordPageLock(struct Machine *m, i64 page, u8 *pslot) { unassert(m->sysdepth > 0); unassert(!m->pagelocks.i || m->pagelocks.p[m->pagelocks.i - 1].sysdepth <= m->sysdepth); if (m->pagelocks.i == m->pagelocks.n) { int n2; struct PageLock *p2; p2 = m->pagelocks.p; n2 = m->pagelocks.n; n2 += 3; n2 += n2 >> 1; if ((p2 = (struct PageLock *)realloc(p2, n2 * sizeof(*p2)))) { m->pagelocks.p = p2; m->pagelocks.n = n2; } else { return false; } } m->pagelocks.p[m->pagelocks.i].page = page; m->pagelocks.p[m->pagelocks.i].pslot = pslot; m->pagelocks.p[m->pagelocks.i].sysdepth = m->sysdepth; ++m->pagelocks.i; STATISTIC(++page_locks); return true; } static void ReleasePageLock(u8 *pslot) { u64 entry; do { entry = LoadPte(pslot); unassert(entry & PAGE_V); unassert(entry & PAGE_LOCKS); } while (!CasPte(pslot, entry, entry - PAGE_LOCK)); } static bool HasOutdatedPageLocks(struct Machine *m) { return m->pagelocks.i && m->pagelocks.p[m->pagelocks.i - 1].sysdepth > m->sysdepth; } void CollectPageLocks(struct Machine *m) { if (HasOutdatedPageLocks(m)) { LOCK(&m->system->pagelocks_lock); do ReleasePageLock(m->pagelocks.p[--m->pagelocks.i].pslot); while (HasOutdatedPageLocks(m)); unassert(!pthread_cond_broadcast(&m->system->pagelocks_cond)); UNLOCK(&m->system->pagelocks_lock); } } // returns page directory entry associated with virtual address // @return raw page directory entry contents, or zero w/ errno // @raise EFAULT if a valid 4096 page didn't exist at address // @raise ENOMEM if memory couldn't be allocated internally // @raise EAGAIN if too many locks are held on a page u64 FindPageTableEntry(struct Machine *m, u64 page) { u8 *pslot; i64 table; u64 entry; long tlbkey; unsigned level, index; if (UNLIKELY(atomic_load_explicit(&m->invalidated, memory_order_acquire))) { ResetTlb(m); atomic_store_explicit(&m->invalidated, false, memory_order_relaxed); } tlbkey = (page >> 12) & (ARRAYLEN(m->tlb) - 1); if (LIKELY(m->tlb[tlbkey].page == page && ((entry = m->tlb[tlbkey].entry) & PAGE_V))) { STATISTIC(++tlb_hits); return entry; } STATISTIC(++tlb_misses); unassert(!(page & 4095)); if (!(-0x800000000000 <= (i64)page && (i64)page < 0x800000000000)) { m->segvcode = SEGV_MAPERR_LINUX; return (u64)(uintptr_t)efault0(); } TryAgain: unassert((entry = m->system->cr3)); level = 39; do { table = entry; index = (page >> level) & 511; pslot = GetPageAddress(m->system, table, level == 39) + index * 8; if (!pslot) goto MapError; entry = LoadPte(pslot); if (!(entry & PAGE_V)) goto MapError; if (m->metal) { entry &= ~(u64)(PAGE_RSRV | PAGE_HOST | PAGE_MAP | PAGE_GROW | PAGE_MUG | PAGE_FILE); } if ((entry & PAGE_PS) && level > 12) { // huge (1 GiB or 2 MiB) page; "rewrite" the TLB copy of the page table // entry, to point to the 4 KiB subpage being accessed // TODO: if partial TLB flushes are implemented in the future, we will // also need to somehow record the original huge page size in the TLB, // so we can correctly invalidate all TLB entries for the huge page u64 submask = ((u64)1 << level) - 4096; entry &= ~submask; entry |= page & submask; break; } } while ((level -= 9) >= 12); if ((entry & PAGE_RSRV) && !(entry = HandlePageFault(m, pslot, entry))) { return 0; } // system calls lock the pages they access // this prevents race conditions w/ munmap if (m->insyscall && !m->nofault && !HasPageLock(m, page)) { if ((entry & PAGE_LOCKS) < PAGE_LOCKS) { if (CasPte(pslot, entry, entry + PAGE_LOCK)) { unassert(LoadPte(pslot) & PAGE_LOCKS); if (RecordPageLock(m, page, pslot)) { entry += PAGE_LOCK; } else { ReleasePageLock(pslot); m->segvcode = SEGV_MAPERR_LINUX; return 0; } } else { goto TryAgain; } } else { LOGF("too many threads locked page %#" PRIx64, page); m->segvcode = SEGV_MAPERR_LINUX; errno = EAGAIN; return 0; } } m->tlb[tlbkey].page = page; m->tlb[tlbkey].entry = entry; return entry; MapError: m->segvcode = SEGV_MAPERR_LINUX; return (uintptr_t)efault0(); } u8 *LookupAddress2(struct Machine *m, i64 virt, u64 mask, u64 need) { u8 *host; u64 entry; if (!m->metal || m->mode.omode == XED_MODE_LONG || (m->mode.genmode != XED_GEN_MODE_REAL && (m->system->cr0 & CR0_PG))) { if (!(entry = FindPageTableEntry(m, virt & -4096))) { return 0; } } else if (virt >= 0 && virt <= 0xffffffff && (virt & 0xffffffff) + 4095 < kRealSize) { unassert(m->system->real); return m->system->real + virt; } else { m->segvcode = SEGV_MAPERR_LINUX; return (u8 *)efault0(); } if ((entry & mask) != need) { m->segvcode = SEGV_ACCERR_LINUX; return (u8 *)efault0(); } #ifndef DISABLE_JIT if ((need & PAGE_RW) && (entry & (PAGE_U | PAGE_RW | PAGE_XD)) == (PAGE_U | PAGE_RW) && !IsJitDisabled(&m->system->jit) && !IsPageInSmcQueue(m, virt)) { AddPageToSmcQueue(m, virt); } #endif if ((host = GetPageAddress(m->system, entry, false))) { return host + (virt & 4095); } else { m->segvcode = SEGV_MAPERR_LINUX; return (u8 *)efault0(); } } u8 *LookupAddress(struct Machine *m, i64 virt) { u64 need = 0; if (Cpl(m) == 3) need = PAGE_U; return LookupAddress2(m, virt, need, need); } flattencalls u8 *GetAddress(struct Machine *m, i64 v) { if (HasLinearMapping()) return ToHost(v); return LookupAddress(m, v); } /** * Translates virtual address into pointer. * * This function bypasses memory protection, since it's used to display * memory in the debugger tui. That's useful, for example, if debugging * programs that specify an eXecute-only program header. * * It's recommended that the caller use: * * BEGIN_NO_PAGE_FAULTS; * i64 address = ...; * u8 *pointer = SpyAddress(m, address); * END_NO_PAGE_FAULTS; * * When calling this function. */ u8 *SpyAddress(struct Machine *m, i64 virt) { return LookupAddress2(m, virt, 0, 0); } u8 *ResolveAddress(struct Machine *m, i64 v) { u8 *r; if ((r = GetAddress(m, v))) return r; ThrowSegmentationFault(m, v); } bool IsValidMemory(struct Machine *m, i64 virt, i64 size, int prot) { i64 p, pe; u64 pte, mask, need; size += virt & 4095; virt &= -4096; unassert(m->mode.omode == XED_MODE_LONG); unassert(prot && !(prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))); need = mask = 0; if (prot & PROT_READ) { mask |= PAGE_U; need |= PAGE_U; } if (prot & PROT_WRITE) { mask |= PAGE_RW; need |= PAGE_RW; } if (prot & PROT_EXEC) { mask |= PAGE_XD; } if (ckd_add(&pe, virt, size)) { eoverflow(); return false; } for (p = virt; p < pe; p += 4096) { if (!(pte = FindPageTableEntry(m, p))) { return false; } if ((pte & mask) != need) { errno = EFAULT; return false; } } return true; } int VirtualCopy(struct Machine *m, i64 v, char *r, u64 n, bool d) { u8 *p; u64 k; k = 4096 - (v & 4095); while (n) { k = MIN(k, n); if (!(p = LookupAddress(m, v))) return -1; if (d) { memcpy(r, p, k); } else if (!IsRomAddress(m, p)) { memcpy(p, r, k); } n -= k; r += k; v += k; k = 4096; } return 0; } int CopyFromUser(struct Machine *m, void *dst, i64 src, u64 n) { return VirtualCopy(m, src, (char *)dst, n, true); } int CopyFromUserRead(struct Machine *m, void *dst, i64 addr, u64 n) { if (CopyFromUser(m, dst, addr, n) == -1) return -1; SetReadAddr(m, addr, n); return 0; } int CopyToUser(struct Machine *m, i64 dst, void *src, u64 n) { return VirtualCopy(m, dst, (char *)src, n, false); } int CopyToUserWrite(struct Machine *m, i64 addr, void *src, u64 n) { if (CopyToUser(m, addr, src, n) == -1) return -1; SetWriteAddr(m, addr, n); return 0; } void CommitStash(struct Machine *m) { unassert(m->stashaddr); if (m->opcache->writable) { CopyToUser(m, m->stashaddr, m->opcache->stash, m->opcache->stashsize); } m->stashaddr = 0; } u8 *ReserveAddress(struct Machine *m, i64 v, size_t n, bool writable) { long k; u64 mask, need; u8 *res, *p1, *p2; if (writable) { SetWriteAddr(m, v, n); } else { SetReadAddr(m, v, n); } if (HasLinearMapping()) { return ToHost(v); } m->reserving = true; if (Cpl(m) == 3) { if (!writable) { mask = PAGE_U; need = PAGE_U; } else { mask = PAGE_U | PAGE_RW; need = PAGE_U | PAGE_RW; } } else { mask = 0; need = 0; } if ((v & 4095) + n <= 4096) { if ((res = LookupAddress2(m, v, mask, need))) { if (!IsRomAddress(m, res)) return res; p1 = res; m->stashaddr = v; m->opcache->stashsize = n; m->opcache->writable = writable; res = m->opcache->stash; IGNORE_RACES_START(); memcpy(res, p1, n); IGNORE_RACES_END(); return res; } else { ThrowSegmentationFault(m, v); } } STATISTIC(++page_overlaps); unassert(n <= 4096); m->stashaddr = v; m->opcache->stashsize = n; m->opcache->writable = writable; res = m->opcache->stash; k = 4096 - (v & 4095); if ((p1 = LookupAddress2(m, v, mask, need))) { if ((p2 = LookupAddress2(m, v + k, mask, need))) { IGNORE_RACES_START(); memcpy(res, p1, k); memcpy(res + k, p2, n - k); IGNORE_RACES_END(); return res; } else { ThrowSegmentationFault(m, v + k); } } else { ThrowSegmentationFault(m, v); } } static u8 *AccessRam2(struct Machine *m, i64 v, size_t n, void *p[2], u8 *tmp, bool copy, bool protect_rom) { u8 *a, *b; unsigned k; unassert(n <= 4096); if ((v & 4095) + n <= 4096) { a = ResolveAddress(m, v); if (!protect_rom || !IsRomAddress(m, a)) return a; if (copy) memcpy(tmp, a, n); return tmp; } STATISTIC(++page_overlaps); k = 4096; k -= v & 4095; unassert(k <= 4096); a = ResolveAddress(m, v); b = ResolveAddress(m, v + k); if (copy) { memcpy(tmp, a, k); memcpy(tmp + k, b, n - k); } if (protect_rom) { if (IsRomAddress(m, a)) a = NULL; if (IsRomAddress(m, b)) b = NULL; } p[0] = a; p[1] = b; return tmp; } u8 *AccessRam(struct Machine *m, i64 v, size_t n, void *p[2], u8 *tmp, bool d) { return AccessRam2(m, v, n, p, tmp, d, !d); } u8 *Load(struct Machine *m, i64 v, size_t n, u8 *b) { void *p[2]; SetReadAddr(m, v, n); return AccessRam(m, v, n, p, b, true); } u8 *BeginStore(struct Machine *m, i64 v, size_t n, void *p[2], u8 *b) { SetWriteAddr(m, v, n); return AccessRam(m, v, n, p, b, false); } u8 *BeginStoreNp(struct Machine *m, i64 v, size_t n, void *p[2], u8 *b) { if (!v) return NULL; return BeginStore(m, v, n, p, b); } #if 0 u8 *BeginLoadStore(struct Machine *m, i64 v, size_t n, void *p[2], u8 *b) { SetWriteAddr(m, v, n); return AccessRam2(m, v, n, p, b, true, true); } #endif void EndStore(struct Machine *m, i64 v, size_t n, void *p[2], u8 *b) { unsigned k; unassert(n <= 4096); if ((v & 4095) + n <= 4096) return; k = 4096; k -= v & 4095; unassert(n > k); #ifdef DISABLE_ROM unassert(p[0]); unassert(p[1]); memcpy(p[0], b, k); memcpy(p[1], b + k, n - k); #else if (p[0]) memcpy(p[0], b, k); if (p[1]) memcpy(p[1], b + k, n - k); #endif } void EndStoreNp(struct Machine *m, i64 v, size_t n, void *p[2], u8 *b) { if (v) EndStore(m, v, n, p, b); } void *AddToFreeList(struct Machine *m, void *mem) { int n; void *p; p = m->freelist.p; n = m->freelist.n + 1; if ((p = realloc(p, n * sizeof(*m->freelist.p)))) { STATISTIC(++freelisted); m->freelist.p = (void **)p; m->freelist.n = n; m->freelist.p[n - 1] = mem; return mem; } else { free(mem); return 0; } } // Returns pointer to memory in guest memory. If the memory overlaps a // page boundary, then it's copied, and the temporary memory is pushed // to the free list. Returns NULL w/ EFAULT or ENOMEM on error. void *Schlep(struct Machine *m, i64 addr, size_t size, u64 mask, u64 need) { char *copy; size_t have; void *res, *page; if (!size) return 0; if (!(page = LookupAddress2(m, addr, mask, need))) return 0; have = 4096 - (addr & 4095); if (size <= have) { res = page; } else { if (!(copy = (char *)malloc(size))) return 0; memcpy(copy, page, have); for (; have < size; have += 4096) { if (!(page = LookupAddress2(m, addr + have, mask, need))) { free(copy); return 0; } memcpy(copy + have, page, MIN(4096, size - have)); } res = AddToFreeList(m, copy); } return res; } void *SchlepR(struct Machine *m, i64 addr, size_t size) { SetReadAddr(m, addr, size); return Schlep(m, addr, size, PAGE_U, PAGE_U); } void *SchlepW(struct Machine *m, i64 addr, size_t size) { SetWriteAddr(m, addr, size); return Schlep(m, addr, size, PAGE_RW, PAGE_RW); } void *SchlepRW(struct Machine *m, i64 addr, size_t size) { SetReadAddr(m, addr, size); SetWriteAddr(m, addr, size); return Schlep(m, addr, size, PAGE_U | PAGE_RW, PAGE_U | PAGE_RW); } // Returns pointer to string in guest memory. If the string overlaps a // page boundary, then it's copied, and the temporary memory is pushed // to the free list. Returns NULL w/ EFAULT or ENOMEM on error. char *LoadStr(struct Machine *m, i64 addr) { size_t have; char *copy, *page, *p; have = 4096 - (addr & 4095); if (!addr) return 0; if (!(page = (char *)LookupAddress2(m, addr, PAGE_U, PAGE_U))) return 0; if ((p = (char *)memchr(page, '\0', have))) { SetReadAddr(m, addr, p - page + 1); return page; } if (!(copy = (char *)malloc(have + 4096))) return 0; memcpy(copy, page, have); for (;;) { if (!(page = (char *)LookupAddress2(m, addr + have, PAGE_U, PAGE_U))) break; if ((p = (char *)memccpy(copy + have, page, '\0', 4096))) { SetReadAddr(m, addr, have + (p - (copy + have)) + 1); return (char *)AddToFreeList(m, copy); } have += 4096; if (!(p = (char *)realloc(copy, have + 4096))) break; copy = p; } free(copy); return 0; } // Copies string from guest memory. The returned memory is pushed to the // machine free list. NULL w/ ENOMEM is returned if we're out of memory. char *CopyStr(struct Machine *m, i64 addr) { char *s; if (!(s = LoadStr(m, addr))) return 0; return (char *)AddToFreeList(m, strdup(s)); } // Returns fully copied NULL-terminated NUL-terminated string list. All // memory allocated by this routine is pushed to the machine free list. char **CopyStrList(struct Machine *m, i64 addr) { int n; u8 b[8]; char *s; void *mem; char **list; for (list = 0, n = 0;;) { if ((mem = realloc(list, ++n * sizeof(*list)))) { list = (char **)mem; } else { free(list); return 0; } CopyFromUserRead(m, b, addr + n * 8 - 8, 8); if (Read64(b)) { if ((s = CopyStr(m, Read64(b)))) { list[n - 1] = s; } else { free(list); return 0; } } else { list[n - 1] = 0; return (char **)AddToFreeList(m, list); } } } ================================================ FILE: blink/memorymalloc.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/bitscan.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/debug.h" #include "blink/errno.h" #include "blink/fds.h" #include "blink/jit.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/pml4t.h" #include "blink/random.h" #include "blink/thread.h" #include "blink/timespec.h" #include "blink/types.h" #include "blink/util.h" #include "blink/x86.h" struct Allocator { pthread_mutex_t_ lock; struct HostPage *pages GUARDED_BY(lock); } g_allocator = { PTHREAD_MUTEX_INITIALIZER_, }; struct Machine g_bssmachine; struct HostPages g_hostpages; static void FillPage(void *p, int c) { memset(p, c, 4096); } static void ClearPage(void *p) { FillPage(p, 0); } static struct HostPage *NewHostPage(void) { return (struct HostPage *)malloc(sizeof(struct HostPage)); } static void FreeHostPage(struct HostPage *hp) { free(hp); } static u64 TrackHostPage(u8 *ptr) { u64 entry; if (HasLinearMapping()) { return (uintptr_t)ptr; } else { if (g_hostpages.n == g_hostpages.c) { g_hostpages.c += 1; g_hostpages.c += g_hostpages.c >> 1; g_hostpages.p = realloc(g_hostpages.p, g_hostpages.c * sizeof(*g_hostpages.p)); } entry = g_hostpages.n++; g_hostpages.p[entry] = ptr; return entry << 12; } } void FreeAnonymousPage(struct System *s, u8 *page) { struct HostPage *h; unassert((h = NewHostPage())); LOCK(&g_allocator.lock); h->page = page; h->next = g_allocator.pages; g_allocator.pages = h; UNLOCK(&g_allocator.lock); } static size_t GetBigSize(size_t n) { unassert(n); long z = FLAG_pagesize; return ROUNDUP(n, z); } static void FreeFileMap(struct FileMap *fm) { if (fm) { free(fm->present); free(fm->path); free(fm); } } void FreeBig(void *p, size_t n) { if (!p) return; unassert(!Munmap(p, n)); } void *AllocateBig(size_t n, int prot, int flags, int fd, off_t off) { void *p = Mmap(0, n, prot, flags, fd, off, "big"); return p != MAP_FAILED ? p : 0; } static void FreePageTable(struct System *s, u8 *page) { FreeAnonymousPage(s, page); s->memstat.tables -= 1; s->rss -= 1; } static bool FreeEmptyPageTables(struct System *s, u64 pt, long level) { u8 *mi; long i; bool isempty = true; mi = GetPageAddress(s, pt, level == 1); for (i = 0; i < 512; ++i) { if (level == 4) { if (LoadPte(mi + i * 8)) { isempty = false; } } else { pt = LoadPte(mi + i * 8); if (pt & PAGE_V) { if (FreeEmptyPageTables(s, pt, level + 1)) { StorePte(mi + i * 8, 0); } else { isempty = false; } } else { unassert(!pt); } } } if (isempty) { FreePageTable(s, mi); } return isempty; } static void FreeHostPages(struct System *s) { if (!s->real && s->cr3) { unassert(!FreeVirtual(s, -0x800000000000, 0x1000000000000)); unassert(FreeEmptyPageTables(s, s->cr3, 1)); #if 0 unassert(!s->memstat.committed); unassert(!s->memstat.reserved); unassert(!s->memstat.tables); unassert(!s->vss); unassert(!s->rss); #endif s->cr3 = 0; } else if (s->real) { Munmap(s->real, ROUNDUP(kRealSize, FLAG_pagesize)); } s->real = 0; } static void FreeFileMaps(struct System *s) { struct Dll *e; while ((e = dll_first(s->filemaps))) { dll_remove(&s->filemaps, e); FreeFileMap(FILEMAP_CONTAINER(e)); } } void CleanseMemory(struct System *s, size_t size) { i64 oldrss; if (s->memchurn >= (s->rss >> 1)) { (void)(oldrss = s->rss); FreeEmptyPageTables(s, s->cr3, 1); MEM_LOGF("freed %" PRId64 " page tables", oldrss - s->rss); s->memchurn = 0; } } int GetFileDescriptorLimit(struct System *s) { u64 lim; LOCK(&s->mmap_lock); lim = Read64(s->rlim[RLIMIT_NOFILE_LINUX].cur); UNLOCK(&s->mmap_lock); if (lim > INT_MAX) lim = INT_MAX; return lim; } long GetMaxVss(struct System *s) { return MIN(kMaxVirtual, Read64(s->rlim[RLIMIT_AS_LINUX].cur)) / 4096; } long GetMaxRss(struct System *s) { return MIN(kMaxResident, Read64(s->rlim[RLIMIT_AS_LINUX].cur)) / 4096; } struct System *NewSystem(struct XedMachineMode mode) { long i; struct System *s; unassert(mode.omode == XED_MODE_REAL || // mode.omode == XED_MODE_LEGACY || // mode.omode == XED_MODE_LONG); unassert(mode.genmode == XED_GEN_MODE_REAL || // mode.genmode == XED_GEN_MODE_PROTECTED); if (posix_memalign((void **)&s, _Alignof(struct System), sizeof(*s))) { enomem(); return 0; } memset(s, 0, sizeof(*s)); s->mode = mode; if (s->mode.omode == XED_MODE_REAL) { u8 *real = Mmap(NULL, ROUNDUP(kRealSize, FLAG_pagesize), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS_, -1, 0, "real"); if (!real) { free(s); enomem(); return 0; } s->real = real; s->gdt_limit = s->idt_limit = 0xFFFF; s->gdt_base = s->idt_base = 0; } #ifdef HAVE_JIT InitJit(&s->jit, (uintptr_t)JitlessDispatch); #endif InitFds(&s->fds); unassert(!pthread_mutex_init(&s->sig_lock, 0)); unassert(!pthread_mutex_init(&s->mmap_lock, 0)); unassert(!pthread_mutex_init(&s->exec_lock, 0)); unassert(!pthread_cond_init(&s->machines_cond, 0)); unassert(!pthread_mutex_init(&s->machines_lock, 0)); unassert(!pthread_cond_init(&s->pagelocks_cond, 0)); unassert(!pthread_mutex_init(&s->pagelocks_lock, 0)); s->blinksigs = (u64)1 << (SIGSYS_LINUX - 1) | // (u64)1 << (SIGILL_LINUX - 1) | // (u64)1 << (SIGFPE_LINUX - 1) | // (u64)1 << (SIGSEGV_LINUX - 1) | // (u64)1 << (SIGBUS_LINUX - 1) | // (u64)1 << (SIGPIPE_LINUX - 1) | // (u64)1 << (SIGTRAP_LINUX - 1); for (i = 0; i < RLIM_NLIMITS_LINUX; ++i) { Write64(s->rlim[i].cur, RLIM_INFINITY_LINUX); Write64(s->rlim[i].max, RLIM_INFINITY_LINUX); } s->pid = getpid(); return s; } static void FreeMachineUnlocked(struct Machine *m) { THR_LOGF("pid=%d tid=%d FreeMachine", m->system->pid, m->tid); UnlockRobustFutexes(m); if (IsMakingPath(m)) { AbandonJit(&m->system->jit, m->path.jb); } m->sysdepth = 0; CollectPageLocks(m); CollectGarbage(m, 0); free(m->pagelocks.p); free(m->freelist.p); free(m); if (g_machine == m) { g_machine = 0; } } bool IsOrphan(struct Machine *m) { bool res; LOCK(&m->system->machines_lock); if (m->system->machines == m->system->machines->next && m->system->machines == m->system->machines->prev) { unassert(m == MACHINE_CONTAINER(m->system->machines)); res = true; } else { res = false; } UNLOCK(&m->system->machines_lock); return res; } void KillOtherThreads(struct System *s) { #ifdef HAVE_THREADS int r, t; struct Dll *e; struct Machine *m; struct timespec deadline; if (atomic_exchange(&s->killer, true)) { FreeMachine(g_machine); pthread_exit(EXIT_SUCCESS); } StartOver: unassert(s == g_machine->system); unassert(!dll_is_empty(s->machines)); for (t = 0; !IsOrphan(g_machine); ++t) { LOCK(&s->machines_lock); for (e = dll_first(s->machines); e; e = dll_next(s->machines, e)) { if ((m = MACHINE_CONTAINER(e)) != g_machine) { THR_LOGF("pid=%d tid=%d is killing tid %d", s->pid, g_machine->tid, m->tid); atomic_store_explicit(&m->killed, true, memory_order_release); atomic_store_explicit(&m->attention, true, memory_order_release); if (t < 10) { pthread_kill(m->thread, SIGSYS); } else { LOGF("kill9'd thread after 10 tries"); pthread_kill(m->thread, SIGKILL); dll_remove(&s->machines, e); UNLOCK(&s->machines_lock); goto StartOver; } } } deadline = AddTime(GetTime(), FromMilliseconds(kPollingMs)); r = pthread_cond_timedwait(&s->machines_cond, &s->machines_lock, &deadline); unassert(r == 0 || r == ETIMEDOUT); UNLOCK(&s->machines_lock); } #endif } void RemoveOtherThreads(struct System *s) { #ifdef HAVE_THREADS struct Dll *e, *g; struct Machine *m; LOCK(&s->machines_lock); for (e = dll_first(s->machines); e; e = g) { g = dll_next(s->machines, e); m = MACHINE_CONTAINER(e); if (m != g_machine) { dll_remove(&s->machines, e); FreeMachineUnlocked(m); } } UNLOCK(&s->machines_lock); #endif } void FreeSystem(struct System *s) { THR_LOGF("pid=%d FreeSystem", s->pid); unassert(dll_is_empty(s->machines)); // Use KillOtherThreads & FreeMachine FreeHostPages(s); unassert(!pthread_mutex_destroy(&s->machines_lock)); unassert(!pthread_cond_destroy(&s->machines_cond)); unassert(!pthread_mutex_destroy(&s->pagelocks_lock)); unassert(!pthread_cond_destroy(&s->pagelocks_cond)); unassert(!pthread_mutex_destroy(&s->exec_lock)); unassert(!pthread_mutex_destroy(&s->mmap_lock)); // TODO(jart): Figure out why sig_lock sometimes fails to destroy (void)pthread_mutex_destroy(&s->sig_lock); free(s->elf.interpreter); DestroyFds(&s->fds); free(s->elf.execfn); free(s->elf.prog); FreeFileMaps(s); #ifdef HAVE_JIT DestroyJit(&s->jit); #endif free(s); } struct Machine *NewMachine(struct System *system, struct Machine *parent) { _Static_assert(IS2POW(kMaxThreadIds), ""); struct Machine *m; unassert(system); unassert(!parent || system == parent->system); if (posix_memalign((void **)&m, _Alignof(struct Machine), sizeof(*m))) { enomem(); return 0; } // TODO(jart): We shouldn't be doing expensive ops in an allocator. LOCK(&system->machines_lock); if (parent) { memcpy(m, parent, sizeof(*m)); memset(&m->path, 0, sizeof(m->path)); memset(&m->freelist, 0, sizeof(m->freelist)); memset(&m->pagelocks, 0, sizeof(m->pagelocks)); ResetInstructionCache(m); m->insyscall = false; m->nofault = false; m->sysdepth = 0; m->sigdepth = 0; m->signals = 0; } else { memset(m, 0, sizeof(*m)); ResetCpu(m); } m->ctid = 0; m->oplen = 0; m->system = system; m->mode = system->mode; m->thread = pthread_self(); Write32(m->sigaltstack.flags, SS_DISABLE_LINUX); if (parent) { m->tid = (system->next_tid++ & (kMaxThreadIds - 1)) + kMinThreadId; } else { // TODO(jart): We shouldn't be doing system calls in an allocator. m->tid = m->system->pid; } dll_init(&m->elem); // TODO(jart): Child thread should add itself to system. dll_make_first(&system->machines, &m->elem); UNLOCK(&system->machines_lock); THR_LOGF("new machine thread pid=%d tid=%d", m->system->pid, m->tid); return m; } void CollectGarbage(struct Machine *m, size_t mark) { long i; for (i = mark; i < m->freelist.n; ++i) { free(m->freelist.p[i]); } m->freelist.n = mark; } void FreeMachine(struct Machine *m) { bool orphan; struct System *s; if (m) { unassert((s = m->system)); m->sysdepth = 0; CollectPageLocks(m); LOCK(&s->machines_lock); dll_remove(&s->machines, &m->elem); if (!(orphan = dll_is_empty(s->machines))) { unassert(!pthread_cond_signal(&s->machines_cond)); } UNLOCK(&s->machines_lock); FreeMachineUnlocked(m); if (orphan) { FreeSystem(s); } else { THR_LOGF("more threads remain in operation"); } } } u64 AllocateAnonymousPage(struct System *s) { u8 *page; size_t i, n; struct HostPage *h; LOCK(&g_allocator.lock); if ((h = g_allocator.pages)) { g_allocator.pages = h->next; UNLOCK(&g_allocator.lock); page = h->page; FreeHostPage(h); goto Finished; } else { UNLOCK(&g_allocator.lock); } n = 64; page = (u8 *)AllocateBig(n * 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS_ | MAP_PRIVATE, -1, 0); if (!page) return -1; LOCK(&g_allocator.lock); for (i = n; i-- > 1;) { unassert((h = NewHostPage())); h->page = page + i * 4096; h->next = g_allocator.pages; g_allocator.pages = h; } UNLOCK(&g_allocator.lock); Finished: s->rss += 1; i = TrackHostPage(page); unassert(!(i & ~PAGE_TA)); return i | PAGE_HOST | PAGE_U | PAGE_RW | PAGE_V; } u64 AllocatePageTable(struct System *s) { u64 res; if ((res = AllocateAnonymousPage(s)) != -1) { s->memstat.tables += 1; res &= ~PAGE_U; } return res; } bool IsValidAddrSize(i64 virt, i64 size) { virt = (i64)((u64)virt << 16) >> 16; return size > 0 && // !(virt & 4095) && // virt >= -0x800000000000 && // virt < 0x800000000000 && // size <= 0x1000000000000 && // virt + size <= 0x800000000000; } void InvalidateSystem(struct System *s, bool tlb, bool icache) { struct Dll *e; struct Machine *m; if (tlb || icache) { LOCK(&s->machines_lock); for (e = dll_first(s->machines); e; e = dll_next(s->machines, e)) { m = MACHINE_CONTAINER(e); if (tlb) { atomic_store_explicit(&m->invalidated, true, memory_order_release); } if (icache) { atomic_store_explicit(&m->opcache->invalidated, true, memory_order_release); } } UNLOCK(&s->machines_lock); } } struct FileMap *AddFileMap(struct System *s, i64 virt, i64 size, const char *path, u64 offset) { struct FileMap *fm; size_t pages, words; if (!path) return 0; if ((fm = (struct FileMap *)calloc(1, sizeof(struct FileMap)))) { fm->virt = virt; fm->size = size; fm->path = strdup(path); fm->offset = offset; pages = ROUNDUP(size, 4096) / 4096; words = ROUNDUP(pages, 64) / 64; if (fm->path && (fm->present = (u64 *)malloc(words * sizeof(u64)))) { memset(fm->present, -1, pages / 64 * sizeof(u64)); if (pages % 64) { fm->present[pages / 64] = ((u64)1 << (pages % 64)) - 1; } fm->pages = pages; dll_init(&fm->elem); dll_make_first(&s->filemaps, &fm->elem); ELF_LOGF("AddFileMap(%#" PRIx64 ", %#" PRIx64 ", %s, %#" PRIx64 ")", virt, size, path, offset); return fm; } } FreeFileMap(fm); return 0; } static void AddFileMapViaMap(struct System *s, i64 virt, i64 size, int fildes, u64 offset) { char *path; struct Fd *fd; struct FileMap *fm; LOCK(&s->fds.lock); path = (fd = GetFd(&s->fds, fildes)) ? strdup(fd->path) : 0; UNLOCK(&s->fds.lock); fm = AddFileMap(s, virt, size, path, offset); free(path); if (fm && s->dis && s->onfilemap) { s->onfilemap(s, fm); } } struct FileMap *GetFileMap(struct System *s, i64 virt) { u64 i; struct Dll *e; struct FileMap *fm; for (e = dll_first(s->filemaps); e; e = dll_next(s->filemaps, e)) { fm = FILEMAP_CONTAINER(e); if (virt >= fm->virt && virt < fm->virt + fm->size) { i = virt - fm->virt; i /= 4096; if (fm->present[i / 64] & ((u64)1 << (i % 64))) { return fm; } } } return 0; } static void UnmarkFilePage(struct System *s, i64 virt) { u64 i; bool lru; struct Dll *e; struct FileMap *fm; lru = false; for (e = dll_first(s->filemaps); e; e = dll_next(s->filemaps, e)) { fm = FILEMAP_CONTAINER(e); if (virt >= fm->virt && virt < fm->virt + fm->size) { unassert(fm->pages); i = virt - fm->virt; i /= 4096; if (fm->present[i / 64] & ((u64)1 << (i % 64))) { fm->present[i / 64] &= ~((u64)1 << (i % 64)); if (!--fm->pages) { dll_remove(&s->filemaps, e); FreeFileMap(fm); } else if (lru) { dll_remove(&s->filemaps, e); dll_make_first(&s->filemaps, e); } break; } } lru = true; } } static void WaitForPageToNotBeLocked(struct System *s, i64 virt, u8 *pte) { unassert(g_machine); #ifdef DEBUG unassert(!IsOrphan(g_machine)); unassert(!HasPageLock(g_machine, virt & -4096)); #endif LOCK(&s->pagelocks_lock); while (LoadPte(pte) & PAGE_LOCKS) { unassert(!pthread_cond_wait(&s->pagelocks_cond, &s->pagelocks_lock)); } UNLOCK(&s->pagelocks_lock); } static bool FreePage(struct System *s, i64 virt, u64 entry, u64 size, bool *executable_code_was_made_non_executable, long *rss_delta) { u8 *page; long pagesize; unassert(entry & PAGE_V); if (entry & PAGE_FILE) UnmarkFilePage(s, virt); if (!(entry & PAGE_XD) && !(entry & PAGE_RSRV)) { *executable_code_was_made_non_executable = true; #ifndef DISABLE_JIT if (!IsJitDisabled(&s->jit)) { ResetJitPage(&s->jit, virt); } #endif } if ((entry & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) == PAGE_HOST) { unassert(~entry & PAGE_RSRV); s->memstat.committed -= 1; ClearPage((page = FindHostPage(entry))); FreeAnonymousPage(s, page); --*rss_delta; return false; } else if ((entry & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) == (PAGE_HOST | PAGE_MAP | PAGE_MUG)) { u8 *real, *mug; pagesize = FLAG_pagesize; real = mug = FindHostPage(entry); while ((uintptr_t)mug & (pagesize - 1)) mug -= 4096; unassert(!Munmap(mug, real - mug + size)); if (entry & PAGE_RSRV) { s->memstat.reserved -= 1; } else { s->memstat.committed -= 1; --*rss_delta; } return false; } else if ((entry & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) == (PAGE_HOST | PAGE_MAP)) { unassert(!(entry & PAGE_RSRV)); s->memstat.committed -= 1; --*rss_delta; return true; // call is responsible for freeing } else if (entry & PAGE_RSRV) { s->memstat.reserved -= 1; return false; } else { unassert(!"impossible memory"); return false; } } static void AddPageToRanges(struct ContiguousMemoryRanges *ranges, i64 virt, i64 end) { if (!(ranges->i && ranges->p[ranges->i - 1].b == virt)) { if (ranges->i == ranges->n) { if (ranges->n) { ranges->n += ranges->n >> 1; } else { ranges->n = 8; } unassert(ranges->p = (struct ContiguousMemoryRange *)realloc( ranges->p, ranges->n * sizeof(*ranges->p))); } ranges->p[ranges->i++].a = virt; } ranges->p[ranges->i - 1].b = virt + MIN(4096, end - virt); } // removes page table entries. anonymous pages will be added to the // system's free list. mug pages will be freed one by one. linear pages // won't be freed, and will instead have their intervals pooled in the // ranges data structure; the caller is responsible for freeing those. static void RemoveVirtual(struct System *s, i64 virt, i64 size, struct ContiguousMemoryRanges *ranges, bool *executable_code_was_made_non_executable, bool *address_space_was_mutated, // long *vss_delta, long *rss_delta) { i64 end; u64 i, pt; u8 *pp, *pde; unsigned pi, p1; unassert(!(virt & 4095)); MEM_LOGF("RemoveVirtual(%#" PRIx64 ", %#" PRIx64 ")", virt, size); for (pde = 0, end = virt + size; virt < end; virt += (u64)1 << i) { for (pt = s->cr3, i = 39;; i -= 9) { pi = p1 = (virt >> i) & 511; pp = GetPageAddress(s, pt, i == 39) + pi * 8; if (i == 12 + 9) pde = pp; pt = LoadPte(pp); if (i > 12 && !(pt & PAGE_V)) break; if (i > 12) continue; LastLevel: if (pt & PAGE_V) { for (;;) { if (pt & PAGE_LOCKS) { WaitForPageToNotBeLocked(s, virt, pp); } else if (CasPte(pp, pt, 0)) { break; } pt = LoadPte(pp); unassert(pt & PAGE_V); } if (FreePage(s, virt, pt, MIN(4096, end - virt), executable_code_was_made_non_executable, rss_delta) && HasLinearMapping()) { AddPageToRanges(ranges, virt, end); } *address_space_was_mutated = true; --*vss_delta; } if (virt + 4096 < end && pi < 511) { pi += 1; pp += 8; pt = LoadPte(pp); virt += 4096; goto LastLevel; } else if (!p1 && pi == 511) { // when more than 512*4096 bytes are being unmapped, we // opportunistically unmap page directories too, if the // requested interval overlaps an entire page table. we // guarantee safety because mmap_lock is held, which is // required to create/remove (but not edit) the entries // therefore if we observed all entries are zero we can // say for certain it's safe to free. the only question // becomes readers like FindPageTableEntry() that still // crawl an old pointer to a free page table. free page // tables may be crawled because they always get zero'd // before being put into a freelist fifo that cools off FreePageTable(s, GetPageAddress(s, LoadPte(pde), i == 39)); StorePte(pde, 0); } break; } } } #define EXIT_FAILURE_MMAP_PANIC 250 _Noreturn static void PanicDueToMmap(void) { #ifndef NDEBUG WriteErrorString( "unrecoverable mmap() crisis: see log for further details\n"); #else WriteErrorString( "unrecoverable mmap() crisis: Blink was built with NDEBUG\n"); #endif exit(EXIT_FAILURE_MMAP_PANIC); } static int FailDueToHostAlignment(i64 virt, long pagesize, const char *kind) { LOGF("app chose mmap %s (%#" PRIx64 ") that's not aligned " "to the platform page size (%#lx) while using linear mode " "(try using `blink -m`)", kind, virt, pagesize); return einval(); } static int DetermineHostProtection(int prot) { int sysprot; // blink never executes guest memory on metal sysprot = prot & ~PROT_EXEC; // when memory is being fully virtualized, // blink will check permissions on its own // note we can't force write permission in // some cases such as shared file mappings if (!HasLinearMapping()) { sysprot |= PROT_READ; } return sysprot; } i64 ReserveVirtual(struct System *s, i64 virt, i64 size, u64 flags, int fd, i64 offset, bool shared, bool fixedmap) { u8 *mi; int demand; int method; i64 result; bool mutated; void *got, *want; long i, pagesize; int prot, sysprot; long vss_delta, rss_delta; i64 ti, pt, end, pages, level, entry; bool executable_code_was_made_non_executable; struct ContiguousMemoryRanges ranges; // we determine these unassert(!(flags & PAGE_TA)); unassert(!(flags & PAGE_MAP)); unassert(!(flags & PAGE_HOST)); unassert(!(flags & PAGE_RSRV)); unassert(s->mode.omode == XED_MODE_LONG); // determine memory protection prot = GetProtection(flags); sysprot = DetermineHostProtection(prot); MEM_LOGF("ReserveVirtual(%#" PRIx64 ", %#" PRIx64 ", %s)", virt, size, DescribeProt(prot)); if (!IsValidAddrSize(virt, size)) { LOGF("mmap(addr=%#" PRIx64 ", size=%#" PRIx64 ") is not a legal mapping", virt, size); return einval(); } if (fd != -1 && (offset & 4095)) { LOGF("mmap(offset=%#" PRIx64 ") isn't 4096-byte page aligned", offset); return einval(); } pagesize = FLAG_pagesize; if (HasLinearMapping()) { if (virt & (pagesize - 1)) { return FailDueToHostAlignment(virt, pagesize, "address"); } if (offset & (pagesize - 1)) { return FailDueToHostAlignment(offset, pagesize, "file offset"); } } // remove existing mapping vss_delta = 0; rss_delta = 0; mutated = false; executable_code_was_made_non_executable = false; pages = ROUNDUP(size, 4096) / 4096; if (HasLinearMapping() && FLAG_vabits <= 47) { if (fixedmap) { method = MAP_FIXED; } else if (virt) { method = MAP_DEMAND; } else { method = 0; } } else { if (FLAG_vabits <= 47) { demand = MAP_DEMAND; } else { demand = MAP_FIXED; } memset(&ranges, 0, sizeof(ranges)); RemoveVirtual(s, virt, size, &ranges, &executable_code_was_made_non_executable, &mutated, &vss_delta, &rss_delta); if (ranges.i) { // linear mappings exist within the requested interval if (ranges.i == 1 && // ranges.p[0].a == virt && // ranges.p[0].b == virt + size) { // it should be 100% safe to let the kernel blow it away method = MAP_FIXED; } else { // holes exist; try to create a greenfield for (i = 0; i < ranges.i; ++i) { Munmap(ToHost(ranges.p[i].a), ranges.p[i].b - ranges.p[i].a); mutated = true; } // errors in Munmap() should propagate to Mmap() below method = demand; } free(ranges.p); } else { // requested interval should be a greenfield method = demand; } } if (HasLinearMapping()) { // create a linear mapping. doing this runs the risk of destroying // things the kernel put into our address space that blink doesn't // know about. systems like linux and freebsd have a feature which // lets us report a friendly error to the user, when that happens. // the solution is most likely to rebuild with -Wl,-Ttext-segment= // please note we need to take off the seatbelt after an execve(). errno = 0; want = virt ? ToHost(virt) : 0; if ((got = Mmap(want, size, sysprot, // (method | // (fd == -1 ? MAP_ANONYMOUS_ : 0) | // (shared ? MAP_SHARED : MAP_PRIVATE)), // fd, offset, "linear")) != want) { if (got == MAP_FAILED && errno == ENOMEM && !mutated) { LOGF("host system returned ENOMEM"); return -1; } else if (got != MAP_FAILED && !want) { virt = ToGuest(got); unassert(IsValidAddrSize(virt, size)); } else { ERRF("mmap(%#" PRIx64 "[%p], %#" PRIx64 ")" " -> %#" PRIx64 "[%p] crisis: %s", virt, want, size, ToGuest(got), got, (method == MAP_DEMAND && errno == MAP_DENIED) ? "requested memory overlapped blink image or system memory. " "try using `blink -m` to disable memory optimizations, or " "try compiling blink using -Wl,--image-base=0x23000000 or " "possibly -Wl,-Ttext-segment=0x23000000 in LDFLAGS" : DescribeHostErrno(errno)); PanicDueToMmap(); } } s->memstat.committed += pages; flags |= PAGE_HOST | PAGE_MAP; vss_delta += pages; rss_delta += pages; } else if (fd != -1 || shared) { vss_delta += pages; s->memstat.reserved += pages; flags |= PAGE_HOST | PAGE_MAP | PAGE_MUG | PAGE_RSRV; } else { flags |= PAGE_RSRV; vss_delta += pages; s->memstat.reserved += pages; } MEM_LOGF("reserving virtual [%#" PRIx64 ",%#" PRIx64 ") w/ %" PRId64 " kb", virt, virt + size, size / 1024); // create a filemap object if (fd != -1 && !(flags & PAGE_FILE)) { flags |= PAGE_FILE; AddFileMapViaMap(s, virt, size, fd, offset); } // add pml4t entries ensuring intermediary tables exist for (result = virt, end = virt + size;;) { for (pt = s->cr3, level = 39; level >= 12; level -= 9) { ti = (virt >> level) & 511; mi = GetPageAddress(s, pt, level == 39) + ti * 8; if (level > 12) { pt = LoadPte(mi); if (!(pt & PAGE_V)) { if ((pt = AllocatePageTable(s)) == -1) { WriteErrorString("mmap() crisis: ran out of page table memory\n"); exit(EXIT_FAILURE_MMAP_PANIC); } StorePte(mi, pt); } continue; } for (;;) { u64 real; if (flags & PAGE_MAP) { if (flags & PAGE_MUG) { u8 *mug; off_t mugoff; int mugflags; long mugsize; long mugskew; mugsize = MIN(4096, end - virt); if (fd != -1) { mugskew = offset - ROUNDDOWN(offset, pagesize); mugoff = ROUNDDOWN(offset, pagesize); mugsize += mugskew; } else { mugoff = 0; mugskew = 0; } mugflags = (shared ? MAP_SHARED : MAP_PRIVATE) | (fd == -1 ? MAP_ANONYMOUS_ : 0); mug = AllocateBig(mugsize, sysprot, mugflags, fd, mugoff); if (!mug) { ERRF("mmap(virt=%" PRIx64 ", size=%ld, flags=%#x, fd=%d, offset=%#" PRIx64 ") crisis: %s", virt, mugsize, mugflags, fd, (u64)mugoff, DescribeHostErrno(errno)); PanicDueToMmap(); } real = TrackHostPage(mug + mugskew); offset += 4096; } else { real = (uintptr_t)ToHost(virt); } unassert(!(real & ~PAGE_TA)); entry = real | flags | PAGE_V; } else { entry = flags | PAGE_V; } for (;;) { pt = LoadPte(mi); if (pt & PAGE_LOCKS) { unassert(pt & PAGE_V); WaitForPageToNotBeLocked(s, virt, mi); } else if (CasPte(mi, pt, entry)) { break; } } if (pt & PAGE_V) { FreePage(s, virt, pt, 4096, &executable_code_was_made_non_executable, &rss_delta); } if ((virt += 4096) >= end) { s->rss += rss_delta; s->vss += vss_delta; #ifndef DISABLE_JIT if (HasLinearMapping() && !IsJitDisabled(&s->jit)) { result = ProtectRwxMemory(s, result, result, size, pagesize, prot); } #endif InvalidateSystem(s, !!rss_delta, executable_code_was_made_non_executable); return result; } if (++ti == 512) break; mi += 8; } } } } i64 FindVirtual(struct System *s, i64 virt, i64 size) { u64 i, pt, got, orig_virt = virt; (void)orig_virt; StartOver: if (!IsValidAddrSize(virt, size)) { LOGF("FindVirtual [%#" PRIx64 ",%#" PRIx64 ") -> " "[%#" PRIx64 ",%#" PRIx64 ") not possible", orig_virt, orig_virt + size, virt, virt + size); return enomem(); } got = 0; do { for (i = 39, pt = s->cr3;; i -= 9) { pt = LoadPte(GetPageAddress(s, pt, i == 39) + (((virt + got) >> i) & 511) * 8); if (i == 12 || !(pt & PAGE_V)) break; } got += (u64)1 << i; if ((pt & PAGE_V)) { virt += got; goto StartOver; } } while (got < size); return virt; } int FreeVirtual(struct System *s, i64 virt, i64 size) { int rc; long i; bool mutated; long vss_delta, rss_delta; bool executable_code_was_made_non_executable; struct ContiguousMemoryRanges ranges; MEM_LOGF("freeing virtual [%#" PRIx64 ",%#" PRIx64 ") w/ %" PRId64 " kb", virt, virt + size, size / 1024); if (!IsValidAddrSize(virt, size)) { LOGF("invalid addr size"); return einval(); } vss_delta = 0; rss_delta = 0; memset(&ranges, 0, sizeof(ranges)); executable_code_was_made_non_executable = false; RemoveVirtual(s, virt, size, &ranges, &executable_code_was_made_non_executable, &mutated, &vss_delta, &rss_delta); for (rc = i = 0; i < ranges.i; ++i) { if (Munmap(ToHost(ranges.p[i].a), ranges.p[i].b - ranges.p[i].a)) { LOGF("failed to %s subrange" " [%" PRIx64 ",%" PRIx64 ") within requested range" " [%" PRIx64 ",%" PRIx64 "): %s", "munmap", ranges.p[i].a, ranges.p[i].b, virt, virt + size, DescribeHostErrno(errno)); rc = einval(); } } free(ranges.p); s->vss += vss_delta; s->rss += rss_delta; s->memchurn -= vss_delta; InvalidateSystem(s, !!rss_delta, executable_code_was_made_non_executable); return rc; } int GetProtection(u64 key) { int prot = 0; if (key & PAGE_U) prot |= PROT_READ; if (key & PAGE_RW) prot |= PROT_WRITE; if (!(key & PAGE_XD)) prot |= PROT_EXEC; return prot; } u64 SetProtection(int prot) { u64 key = 0; if (prot & PROT_READ) key |= PAGE_U; if (prot & PROT_WRITE) key |= PAGE_RW; if (~prot & PROT_EXEC) key |= PAGE_XD; return key; } bool IsFullyMapped(struct System *s, i64 virt, i64 size) { u8 *mi; u64 pt; i64 ti, end, level; for (end = virt + size;;) { for (pt = s->cr3, level = 39; level >= 12; level -= 9) { ti = (virt >> level) & 511; mi = GetPageAddress(s, pt, level == 39) + ti * 8; pt = LoadPte(mi); if (level > 12) { if (!(pt & PAGE_V)) { return false; } continue; } for (;;) { if (!(pt & PAGE_V)) { return false; } if ((virt += 4096) >= end) { return true; } if (++ti == 512) break; pt = LoadPte((mi += 8)); } } } } bool IsFullyUnmapped(struct System *s, i64 virt, i64 size) { u8 *mi; i64 end; u64 i, pt; for (end = virt + size; virt < end; virt += (u64)1 << i) { for (pt = s->cr3, i = 39;; i -= 9) { mi = GetPageAddress(s, pt, i == 39) + ((virt >> i) & 511) * 8; pt = LoadPte(mi); if (!(pt & PAGE_V)) { break; } else if (i == 12) { return false; } } } return true; } int ProtectVirtual(struct System *s, i64 virt, i64 size, int prot, bool hostonly) { u8 *mi; int rc; int sysprot; u64 pt, pt2, key; long i, pagesize; i64 a, b, ti, end, level, orig_virt; bool executable_code_was_made_non_executable; struct ContiguousMemoryRanges ranges; MEM_LOGF("protecting virtual [%#" PRIx64 ",%#" PRIx64 ") w/ %s", virt, virt + size, DescribeProt(prot)); orig_virt = virt; (void)orig_virt; pagesize = FLAG_pagesize; if (!IsValidAddrSize(virt, size)) { return einval(); } if (!IsFullyMapped(s, virt, size)) { LOGF("mprotect(%#" PRIx64 ", %#" PRIx64 ") interval has unmapped pages", virt, size); return enomem(); } key = SetProtection(prot); sysprot = DetermineHostProtection(prot); // in linear mode, the guest might try to do something like // set a 4096 byte guard page to PROT_NONE at the bottom of // its 64kb stack. if the host operating system has a 64 kb // page size, then that would be bad. we can't satisfy prot // unless the guest takes the page size into consideration. if (HasLinearMapping() && (virt - ROUNDDOWN(virt, pagesize) >= 4096 || ROUNDUP(virt + size, pagesize) - (virt + size) >= 4096)) { unassert(!hostonly); // caller should know better sysprot = PROT_READ | PROT_WRITE; } memset(&ranges, 0, sizeof(ranges)); executable_code_was_made_non_executable = false; for (rc = 0, end = virt + size;;) { for (pt = s->cr3, level = 39; level >= 12; level -= 9) { ti = (virt >> level) & 511; mi = GetPageAddress(s, pt, level == 39) + ti * 8; pt = LoadPte(mi); if (level > 12) { if (!(pt & PAGE_V)) { goto MemoryDisappeared; } continue; } for (;;) { if (!(pt & PAGE_V)) { goto MemoryDisappeared; } if (HasLinearMapping() && (pt & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) == (PAGE_HOST | PAGE_MAP)) { AddPageToRanges(&ranges, virt, end); } else if ((pt & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) == (PAGE_HOST | PAGE_MAP | PAGE_MUG)) { u8 *real = FindHostPage(pt); while ((uintptr_t)real & (pagesize - 1)) real -= 4096; if (Mprotect(real, pagesize, sysprot, "mug")) { LOGF("mprotect(pt=%#" PRIx64 ", real=%p, size=%#lx, prot=%d) failed: %s", pt, real, pagesize, prot, DescribeHostErrno(errno)); rc = -1; } } if (!hostonly) { for (;;) { pt2 = (pt & ~(PAGE_U | PAGE_RW | PAGE_XD)) | key; if (CasPte(mi, pt, pt2)) break; pt = LoadPte(mi); if (!(pt & PAGE_V)) { goto MemoryDisappeared; } } // check for exec -> non-exec if (!(pt & PAGE_XD) && (pt2 & PAGE_XD) && !(pt & PAGE_RSRV)) { executable_code_was_made_non_executable = true; #ifdef HAVE_JIT if (!IsJitDisabled(&s->jit)) { ResetJitPage(&s->jit, virt); } #endif } } if ((virt += 4096) >= end) { goto FinishedCrawling; } if (++ti == 512) break; pt = LoadPte((mi += 8)); } } } FinishedCrawling: if (HasLinearMapping()) { for (i = 0; i < ranges.i; ++i) { a = ROUNDDOWN(ranges.p[i].a, pagesize); b = ranges.p[i].b; if (Mprotect(ToHost(a), b - a, sysprot, "linear")) { LOGF("failed to %s subrange" " [%" PRIx64 ",%" PRIx64 ") within requested range" " [%" PRIx64 ",%" PRIx64 "): %s", "mprotect", a, b, orig_virt, orig_virt + size, DescribeHostErrno(errno)); rc = -1; } } free(ranges.p); } if (!hostonly) { #ifndef DISABLE_JIT if (HasLinearMapping() && !IsJitDisabled(&s->jit)) { ProtectRwxMemory(s, rc, orig_virt, size, pagesize, prot); } #endif InvalidateSystem(s, true, executable_code_was_made_non_executable); } return rc; MemoryDisappeared: // mprotect() doesn't lock pages, so a race condition can // occur if the guest fiendishly munmaps this memory from // a different thread. in that case, the main thing we do // care about is not crashing. therefore it should not be // too concerning that this failure could occur after the // address space has been mutated. if (HasLinearMapping()) { free(ranges.p); } return enomem(); } int SyncVirtual(struct System *s, i64 virt, i64 size, int sysflags) { int rc; u8 *mi; u64 pt; i64 orig_virt; i64 ti, end, level; long i, skew, pagesize; struct ContiguousMemoryRanges ranges; if (!IsValidAddrSize(virt, size)) { return einval(); } orig_virt = virt; (void)orig_virt; pagesize = FLAG_pagesize; if (HasLinearMapping() && (skew = virt & (pagesize - 1))) { size += skew; virt -= skew; } if (!IsFullyMapped(s, virt, size)) { LOGF("mprotect(%#" PRIx64 ", %#" PRIx64 ") interval has unmapped pages", virt, size); return enomem(); } memset(&ranges, 0, sizeof(ranges)); for (rc = 0, end = virt + size;;) { for (pt = s->cr3, level = 39; level >= 12; level -= 9) { ti = (virt >> level) & 511; mi = GetPageAddress(s, pt, level == 39) + ti * 8; pt = LoadPte(mi); if (level > 12) { if (!(pt & PAGE_V)) { goto MemoryDisappeared; } continue; } for (;;) { if (!(pt & PAGE_V)) { goto MemoryDisappeared; } if (HasLinearMapping() && (pt & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) == (PAGE_HOST | PAGE_MAP)) { AddPageToRanges(&ranges, virt, end); } else if ((pt & (PAGE_HOST | PAGE_MAP | PAGE_MUG)) == (PAGE_HOST | PAGE_MAP | PAGE_MUG)) { u8 *page, *real; page = real = FindHostPage(pt); while ((uintptr_t)page & (pagesize - 1)) page -= 4096; long lilsize = (real - page) + MIN(4096, end - virt); if (Msync(page, lilsize, sysflags, "mug")) { LOGF("msync(%p [pt=%#" PRIx64 "], size=%#lx, flags=%d) failed: %s\n%s", page, pt, pagesize, sysflags, DescribeHostErrno(errno), FormatPml4t(g_machine)); rc = -1; } } if ((virt += 4096) >= end) { goto FinishedCrawling; } if (++ti == 512) break; pt = LoadPte((mi += 8)); } } } FinishedCrawling: if (HasLinearMapping()) { for (i = 0; i < ranges.i; ++i) { if (Msync(ToHost(ranges.p[i].a), ranges.p[i].b - ranges.p[i].a, sysflags, "linear")) { LOGF("failed to %s subrange" " [%" PRIx64 ",%" PRIx64 ") within requested range" " [%" PRIx64 ",%" PRIx64 "): %s", "msync", ranges.p[i].a, ranges.p[i].b, orig_virt, orig_virt + size, DescribeHostErrno(errno)); rc = -1; } } free(ranges.p); } return rc; MemoryDisappeared: if (HasLinearMapping()) { free(ranges.p); } return enomem(); } // @asyncsignalsafe static i64 FindGuestAddr(struct System *s, uintptr_t hp, u64 pt, long lvl, u64 *out_pte) { u8 *mi; i64 res; u64 pte, i; if ((mi = GetPageAddress(s, pt, lvl == 1))) { for (i = 0; i < 512; ++i) { if ((pte = LoadPte(mi + i * 8)) & PAGE_V) { if (lvl == 4) { if ((pte & PAGE_HOST) && (uintptr_t)FindHostPage(pte) == hp) { if (out_pte) { *out_pte = pte; } return i << 39; } } else if ((res = FindGuestAddr(s, hp, pte, lvl + 1, out_pte)) != -1) { return i << 39 | res >> 9; } } } } return -1; } // Reverse maps real host address to virtual guest address if exists. // On failure the host address is returned and zero is stored in pte. // @asyncsignalsafe i64 ConvertHostToGuestAddress(struct System *s, void *ha, u64 *out_pte) { i64 g48; uintptr_t base; if (out_pte) *out_pte = 0; if (s->mode.omode != XED_MODE_LONG && (!(s->cr0 & CR0_PG) || s->mode.genmode == XED_GEN_MODE_REAL)) { return (uintptr_t)ha; } if ((uintptr_t)ha < kNullSize) return (uintptr_t)ha; if (HasLinearMapping() && !out_pte) return ToGuest(ha); base = (uintptr_t)ha & -4096; if ((g48 = FindGuestAddr(s, base, s->cr3, 1, out_pte)) != -1) { return ((i64)((u64)g48 << 16) >> 16) | ((uintptr_t)ha & 4095); } else { return (uintptr_t)ha; } } ================================================ FILE: blink/message.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include "blink/buffer.h" #include "blink/lines.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/panel.h" #include "blink/strwidth.h" #include "blink/util.h" static int GetWidthOfLongestLine(struct Lines *lines) { int i, w, m; for (m = i = 0; i < lines->n; ++i) { w = strwidth(lines->p[i], 0); m = MAX(m, w); } return m; } void PrintMessageBox(int fd, const char *msg, long tyn, long txn) { struct Buffer b; int i, w, h, x, y; struct Lines *lines; lines = NewLines(); AppendLines(lines, msg); h = 3 + lines->n + 3; w = 4 + GetWidthOfLongestLine(lines) + 4; x = rint(txn / 2. - w / 2.); y = rint(tyn / 2. - h / 2.); memset(&b, 0, sizeof(b)); AppendFmt(&b, "\033[%d;%dH", y++, x); for (i = 0; i < w; ++i) AppendStr(&b, " "); AppendFmt(&b, "\033[%d;%dH ╔", y++, x); for (i = 0; i < w - 4; ++i) AppendStr(&b, "═"); AppendStr(&b, "╗ "); AppendFmt(&b, "\033[%d;%dH ║ %-*s ║ ", y++, x, w - 8, ""); for (i = 0; i < lines->n; ++i) { int lw = strwidth(lines->p[i], 0); AppendFmt(&b, "\033[%d;%dH ║ %s%-*s ║ ", y++, x, lines->p[i], w - 8 - lw, ""); } FreeLines(lines); AppendFmt(&b, "\033[%d;%dH ║ %-*s ║ ", y++, x, w - 8, ""); AppendFmt(&b, "\033[%d;%dH ╚", y++, x); for (i = 0; i < w - 4; ++i) AppendStr(&b, "═"); AppendStr(&b, "╝ "); AppendFmt(&b, "\033[%d;%dH", y++, x); for (i = 0; i < w; ++i) AppendStr(&b, " "); AppendFmt(&b, "\033[%ld;%ldH", tyn, txn); UninterruptibleWrite(fd, b.p, b.i); free(b.p); } ================================================ FILE: blink/metal.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/bus.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/msr.h" #include "blink/rde.h" #include "blink/x86.h" #ifndef DISABLE_METAL static relegated const struct DescriptorCache *GetSegment(P, unsigned s) { if (s < 6) { return m->seg + s; } else { OpUdImpl(m); } } static relegated u64 GetDescriptorBase(u64 d) { return (d & 0xff00000000000000) >> 32 | (d & 0x000000ffffff0000) >> 16; } static struct XedMachineMode GetDescriptorMode(u64 d) { static const struct XedMachineMode kMode[] = { XED_MACHINE_MODE_LEGACY_16, XED_MACHINE_MODE_LONG, XED_MACHINE_MODE_LEGACY_32, XED_MACHINE_MODE_LONG}; return kMode[(d & 0x0060000000000000) >> 53]; } static relegated bool IsProtectedMode(struct Machine *m) { return m->system->cr0 & CR0_PE; } static relegated bool IsNullSelector(u16 sel) { return (sel & -4u) == 0; } static relegated void ChangeMachineMode(struct Machine *m, struct XedMachineMode mode) { if (memcmp(&mode, &m->mode, sizeof(mode)) == 0) return; ResetInstructionCache(m); SetMachineMode(m, mode); #ifdef HAVE_JIT if (mode.omode == XED_MODE_LONG && FLAG_wantjit) { EnableJit(&m->system->jit); } #endif } static relegated void SetSegment(P, unsigned sr, u16 sel, bool jumping) { u64 descriptor; if (sr == SREG_CS && !jumping) OpUdImpl(m); if (!IsProtectedMode(m)) { m->seg[sr].sel = sel; m->seg[sr].base = sel << 4; } else if (GetDescriptor(m, sel, &descriptor) != -1) { m->seg[sr].sel = sel; m->seg[sr].base = GetDescriptorBase(descriptor); if (sr == SREG_CS) { ChangeMachineMode(m, GetDescriptorMode(descriptor)); } } else if (IsNullSelector(sel)) { switch (sr) { case SREG_CS: ThrowProtectionFault(m); break; case SREG_SS: if (Cpl(m) == 3) ThrowProtectionFault(m); } m->seg[sr].sel = sel; } else { ThrowProtectionFault(m); } } relegated void SetCs(P, u16 sel) { SetSegment(A, SREG_CS, sel, true); } relegated void LongBranch(P, u16 sel, u64 ip) { SetCs(A, sel); m->ip = ip; m->oplen = 0; if (m->system->onlongbranch) { m->system->onlongbranch(m); } } relegated void OpPushSeg(P) { u8 seg = (Opcode(rde) & 070) >> 3; Push(A, GetSegment(A, seg)->sel); } relegated void OpPopSeg(P) { u8 seg = (Opcode(rde) & 070) >> 3; SetSegment(A, seg, Pop(A, 0), false); } relegated void OpMovEvqpSw(P) { WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(A), GetSegment(A, ModrmReg(rde))->sel); } relegated void OpMovSwEvqp(P) { u64 x; x = ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(A)); SetSegment(A, ModrmReg(rde), x, false); } relegated void OpJmpf(P) { LongBranch(A, uimm0, disp); } static void PutEaxAx(P, u32 x) { if (!Osz(rde)) { Put64(m->ax, x); } else { Put16(m->ax, x); } } static u32 GetEaxAx(P) { if (!Osz(rde)) { return Get32(m->ax); } else { return Get16(m->ax); } } relegated void OpInAlImm(P) { Put8(m->ax, OpIn(m, uimm0)); } relegated void OpInAxImm(P) { PutEaxAx(A, OpIn(m, uimm0)); } relegated void OpInAlDx(P) { Put8(m->ax, OpIn(m, Get16(m->dx))); } relegated void OpInAxDx(P) { PutEaxAx(A, OpIn(m, Get16(m->dx))); } relegated void OpOutImmAl(P) { OpOut(m, uimm0, Get8(m->ax)); } relegated void OpOutImmAx(P) { OpOut(m, uimm0, GetEaxAx(A)); } relegated void OpOutDxAl(P) { OpOut(m, Get16(m->dx), Get8(m->ax)); } relegated void OpOutDxAx(P) { OpOut(m, Get16(m->dx), GetEaxAx(A)); } static relegated void LoadFarPointer(P, unsigned sr, bool jumping) { unsigned n; u8 *p; u64 fp; switch (Eamode(rde)) { case XED_MODE_LONG: OpUdImpl(m); break; case XED_MODE_LEGACY: case XED_MODE_REAL: n = 1 << WordLog2(rde); p = ComputeReserveAddressRead(A, n + 2); LockBus(p); fp = Load32(p); if (n >= 4) { fp |= (u64)Load16(p + 4) << 32; SetSegment(A, sr, fp >> 32 & 0x0000ffff, jumping); fp &= 0xffffffff; } else { SetSegment(A, sr, fp >> 16 & 0x0000ffff, jumping); fp &= 0x0000ffff; } UnlockBus(p); if (!jumping) { WriteRegister(rde, RegRexrReg(m, rde), fp); // offset portion } else { m->ip = fp; m->oplen = 0; if (m->system->onlongbranch) { m->system->onlongbranch(m); } } break; default: __builtin_unreachable(); } } relegated void OpLes(P) { LoadFarPointer(A, SREG_ES, false); } relegated void OpLds(P) { LoadFarPointer(A, SREG_DS, false); } relegated void OpLss(P) { LoadFarPointer(A, SREG_SS, false); } relegated void OpLfs(P) { LoadFarPointer(A, SREG_FS, false); } relegated void OpLgs(P) { LoadFarPointer(A, SREG_GS, false); } relegated void OpJmpfEq(P) { LoadFarPointer(A, SREG_CS, true); } relegated void OpCallfEq(P) { Push(A, m->cs.sel); Push(A, m->ip); LoadFarPointer(A, SREG_CS, true); } relegated void OpClts(P) { if (Cpl(m)) { ThrowProtectionFault(m); } else { m->system->cr0 &= ~(u64)CR0_TS; } } relegated void OpWrmsr(P) { switch (Get32(m->cx)) { case MSR_IA32_EFER: m->system->efer = Get32(m->ax); break; case MSR_IA32_FS_BASE: m->fs.base = (u64)Read32(m->dx) << 32 | Read32(m->ax); break; case MSR_IA32_GS_BASE: m->gs.base = (u64)Read32(m->dx) << 32 | Read32(m->ax); break; default: LOGF("unsupported msr %#x", Get32(m->cx)); break; } } relegated void OpRdmsr(P) { switch (Get32(m->cx)) { case MSR_IA32_EFER: Put32(m->ax, m->system->efer); break; case MSR_IA32_FS_BASE: Put32(m->dx, m->fs.base >> 32); Put32(m->ax, m->fs.base); break; case MSR_IA32_GS_BASE: Put32(m->dx, m->gs.base >> 32); Put32(m->ax, m->gs.base); break; default: LOGF("unsupported msr %#x", Get32(m->cx)); break; } } relegated void OpMovRqCq(P) { switch (ModrmReg(rde)) { case 0: Put64(RegRexbRm(m, rde), m->system->cr0); break; case 2: Put64(RegRexbRm(m, rde), m->system->cr2); break; case 3: Put64(RegRexbRm(m, rde), m->system->cr3); break; case 4: Put64(RegRexbRm(m, rde), m->system->cr4); break; default: OpUdImpl(m); } } relegated void OpMovCqRq(P) { u64 cr0; struct XedMachineMode mode; switch (ModrmReg(rde)) { case 0: m->system->cr0 = cr0 = Get64(RegRexbRm(m, rde)); mode = m->system->mode; if ((cr0 & CR0_PE)) { mode.genmode = XED_GEN_MODE_PROTECTED; } else { mode.genmode = XED_GEN_MODE_REAL; } ChangeMachineMode(m, mode); break; case 2: m->system->cr2 = Get64(RegRexbRm(m, rde)); break; case 3: m->system->cr3 = Get64(RegRexbRm(m, rde)); ResetTlb(m); break; case 4: m->system->cr4 = Get64(RegRexbRm(m, rde)); ResetTlb(m); break; default: OpUdImpl(m); } } #endif /* DISABLE_METAL */ ================================================ FILE: blink/mkfifo.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/errno.h" #include "blink/log.h" int mkfifo_(const char *ph, mode_t mode) { #ifdef HAVE_MKFIFO return mkfifo(ph, mode); #else return enosys(); #endif } ================================================ FILE: blink/mkfifoat.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/errno.h" #include "blink/log.h" #include "blink/syscall.h" int mkfifoat_(int dirfd, const char *path, mode_t mode) { if (dirfd == AT_FDCWD) { return mkfifo(path, mode); } else { LOGF("this platform doesn't have mkfifoat()"); return enosys(); } } ================================================ FILE: blink/mmx.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/endian.h" #include "blink/macros.h" #include "blink/sse.h" #ifndef DISABLE_MMX relegated void MmxPsubb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] -= y[i]; } } relegated void MmxPaddb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] += y[i]; } } relegated void MmxPavgb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = (x[i] + y[i] + 1) >> 1; } } relegated void MmxPabsb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = ABS((i8)y[i]); } } relegated void MmxPminub(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = MIN(x[i], y[i]); } } relegated void MmxPmaxub(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = MAX(x[i], y[i]); } } relegated void MmxPcmpeqb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = -(x[i] == y[i]); } } relegated void MmxPcmpgtb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = -((i8)x[i] > (i8)y[i]); } } relegated void MmxPsubw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, Get16(x + i * 2) - Get16(y + i * 2)); } } relegated void MmxPaddw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, Get16(x + i * 2) + Get16(y + i * 2)); } } relegated void MmxPaddsw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, MAX(-32768, MIN(32767, ((i16)Get16(x + i * 2) + (i16)Get16(y + i * 2))))); } } relegated void MmxPsubsw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, MAX(-32768, MIN(32767, ((i16)Get16(x + i * 2) - (i16)Get16(y + i * 2))))); } } relegated void MmxPaddusw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, MIN(65535, Get16(x + i * 2) + Get16(y + i * 2))); } } relegated void MmxPcmpgtw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, -((i16)Get16(x + i * 2) > (i16)Get16(y + i * 2))); } } relegated void MmxPcmpeqw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, -(Get16(x + i * 2) == Get16(y + i * 2))); } } relegated void MmxPavgw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, (Get16(x + i * 2) + Get16(y + i * 2) + 1) >> 1); } } relegated void MmxPmulhw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, ((i16)Get16(x + i * 2) * (i16)Get16(y + i * 2)) >> 16); } } relegated void MmxPmullw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, (i16)Get16(x + i * 2) * (i16)Get16(y + i * 2)); } } static relegated int Addition(int x, int y) { return x + y; } static relegated int Subtraction(int x, int y) { return x - y; } static relegated int Clamp16(int x) { return MAX(-32768, MIN(32767, x)); } static relegated void Phsw(u8 x[8], const u8 y[8], int Op(int, int)) { u8 t[8]; unsigned i; for (i = 0; i < 2; ++i) { Put16(t + i * 2, Clamp16(Op((i16)Get16(x + (i * 2) * 2), (i16)Get16(x + (i * 2 + 1) * 2)))); } for (i = 0; i < 2; ++i) { Put16(t + (2 + i) * 2, Clamp16(Op((i16)Get16(y + (i * 2) * 2), (i16)Get16(y + (i * 2 + 1) * 2)))); } memcpy(x, t, 8); } relegated void MmxPhaddsw(u8 x[8], const u8 y[8]) { Phsw(x, y, Addition); } relegated void MmxPhsubsw(u8 x[8], const u8 y[8]) { Phsw(x, y, Subtraction); } #endif /* DISABLE_MMX */ ================================================ FILE: blink/modrm.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/modrm.h" #include "blink/assert.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/x86.h" struct AddrSeg LoadEffectiveAddress(const P) { u64 i = disp; u64 s = m->ds.base; struct AddrSeg res; unassert(!IsModrmRegister(rde)); if (Eamode(rde) != XED_MODE_REAL) { if (!SibExists(rde)) { if (IsRipRelative(rde)) { if (Mode(rde) == XED_MODE_LONG) { i += m->ip; } } else { i += Get64(RegRexbRm(m, rde)); if (RexbRm(rde) == 4 || RexbRm(rde) == 5) { s = m->ss.base; } } } else { if (SibHasBase(rde)) { i += Get64(RegRexbBase(m, rde)); if (RexbBase(rde) == 4 || RexbBase(rde) == 5) { s = m->ss.base; } } if (SibHasIndex(rde)) { i += Get64(RegRexxIndex(m, rde)) << SibScale(rde); } } if (Eamode(rde) == XED_MODE_LEGACY) { i &= 0xffffffff; } } else { switch (ModrmRm(rde)) { case 0: i += Get16(m->bx); i += Get16(m->si); break; case 1: i += Get16(m->bx); i += Get16(m->di); break; case 2: s = m->ss.base; i += Get16(m->bp); i += Get16(m->si); break; case 3: s = m->ss.base; i += Get16(m->bp); i += Get16(m->di); break; case 4: i += Get16(m->si); break; case 5: i += Get16(m->di); break; case 6: if (ModrmMod(rde)) { s = m->ss.base; i += Get16(m->bp); } break; case 7: i += Get16(m->bx); break; default: __builtin_unreachable(); } i &= 0xffff; } res.addr = i; res.seg = s; return res; } i64 ComputeAddress(P) { struct AddrSeg ea = LoadEffectiveAddress(A); return AddSegment(A, ea.addr, ea.seg); } u8 *ComputeReserveAddressRead(P, size_t n) { return ReserveAddress(m, ComputeAddress(A), n, false); } u8 *ComputeReserveAddressRead1(P) { return ComputeReserveAddressRead(A, 1); } u8 *ComputeReserveAddressRead4(P) { return ComputeReserveAddressRead(A, 4); } u8 *ComputeReserveAddressRead8(P) { return ComputeReserveAddressRead(A, 8); } u8 *ComputeReserveAddressWrite(P, size_t n) { return ReserveAddress(m, ComputeAddress(A), n, true); } u8 *ComputeReserveAddressWrite1(P) { return ComputeReserveAddressWrite(A, 1); } u8 *ComputeReserveAddressWrite4(P) { return ComputeReserveAddressWrite(A, 4); } u8 *ComputeReserveAddressWrite8(P) { return ComputeReserveAddressWrite(A, 8); } u8 *GetModrmRegisterMmPointerRead(P, size_t n) { if (IsModrmRegister(rde)) { return MmRm(m, rde); } else { return ComputeReserveAddressRead(A, n); } } u8 *GetModrmRegisterMmPointerRead8(P) { return GetModrmRegisterMmPointerRead(A, 8); } u8 *GetModrmRegisterMmPointerWrite(P, size_t n) { if (IsModrmRegister(rde)) { return MmRm(m, rde); } else { return ComputeReserveAddressWrite(A, n); } } u8 *GetModrmRegisterMmPointerWrite8(P) { return GetModrmRegisterMmPointerWrite(A, 8); } u8 *GetModrmRegisterBytePointerRead1(P) { if (IsModrmRegister(rde)) { return ByteRexbRm(m, rde); } else { return ComputeReserveAddressRead1(A); } } u8 *GetModrmRegisterBytePointerWrite1(P) { if (IsModrmRegister(rde)) { return ByteRexbRm(m, rde); } else { return ComputeReserveAddressWrite1(A); } } u8 *GetModrmRegisterWordPointerRead(P, size_t n) { if (IsModrmRegister(rde)) { return RegRexbRm(m, rde); } else { return ComputeReserveAddressRead(A, n); } } u8 *GetModrmRegisterWordPointerRead2(P) { return GetModrmRegisterWordPointerRead(A, 2); } u8 *GetModrmRegisterWordPointerRead4(P) { return GetModrmRegisterWordPointerRead(A, 4); } u8 *GetModrmRegisterWordPointerRead8(P) { return GetModrmRegisterWordPointerRead(A, 8); } u8 *GetModrmRegisterWordPointerReadOsz(P) { if (!Osz(rde)) { return GetModrmRegisterWordPointerRead8(A); } else { return GetModrmRegisterWordPointerRead2(A); } } u8 *GetModrmRegisterWordPointerReadOszRexw(P) { if (Rexw(rde)) { return GetModrmRegisterWordPointerRead8(A); } else if (!Osz(rde)) { return GetModrmRegisterWordPointerRead4(A); } else { return GetModrmRegisterWordPointerRead2(A); } } u8 *GetModrmRegisterWordPointerWrite(P, size_t n) { if (IsModrmRegister(rde)) { return RegRexbRm(m, rde); } else { return ComputeReserveAddressWrite(A, n); } } u8 *GetModrmRegisterWordPointerWrite2(P) { return GetModrmRegisterWordPointerWrite(A, 2); } u8 *GetModrmRegisterWordPointerWrite4(P) { return GetModrmRegisterWordPointerWrite(A, 4); } u8 *GetModrmRegisterWordPointerWrite8(P) { return GetModrmRegisterWordPointerWrite(A, 8); } u8 *GetModrmRegisterWordPointerWriteOszRexw(P) { if (Rexw(rde)) { return GetModrmRegisterWordPointerWrite(A, 8); } else if (!Osz(rde)) { return GetModrmRegisterWordPointerWrite(A, 4); } else { return GetModrmRegisterWordPointerWrite(A, 2); } } u8 *GetModrmRegisterWordPointerWriteOsz(P) { if (!Osz(rde)) { return GetModrmRegisterWordPointerWrite(A, 8); } else { return GetModrmRegisterWordPointerWrite(A, 2); } } static u8 *GetModrmRegisterXmmPointerRead(P, size_t n) { if (IsModrmRegister(rde)) { return XmmRexbRm(m, rde); } else { return ComputeReserveAddressRead(A, n); } } u8 *GetModrmRegisterXmmPointerRead4(P) { return GetModrmRegisterXmmPointerRead(A, 4); } u8 *GetModrmRegisterXmmPointerRead8(P) { return GetModrmRegisterXmmPointerRead(A, 8); } u8 *GetModrmRegisterXmmPointerRead16(P) { return GetModrmRegisterXmmPointerRead(A, 16); } static u8 *GetModrmRegisterXmmPointerWrite(P, size_t n) { if (IsModrmRegister(rde)) { return XmmRexbRm(m, rde); } else { return ComputeReserveAddressWrite(A, n); } } u8 *GetModrmRegisterXmmPointerWrite4(P) { return GetModrmRegisterXmmPointerWrite(A, 4); } u8 *GetModrmRegisterXmmPointerWrite8(P) { return GetModrmRegisterXmmPointerWrite(A, 8); } u8 *GetModrmRegisterXmmPointerWrite16(P) { return GetModrmRegisterXmmPointerWrite(A, 16); } static u8 *GetVectorAddress(P, size_t n) { u8 *p; i64 v; if (IsModrmRegister(rde)) { p = XmmRexbRm(m, rde); } else { v = ComputeAddress(A); SetReadAddr(m, v, n); if ((v & (n - 1)) || !(p = LookupAddress(m, v))) { ThrowSegmentationFault(m, v); } } return p; } u8 *GetMmxAddress(P) { return GetVectorAddress(A, 8); } u8 *GetXmmAddress(P) { return GetVectorAddress(A, 16); } u8 *GetModrmReadBW(P) { int lg2 = RegLog2(rde); if (IsModrmRegister(rde)) { if (!lg2) { return ByteRexbRm(m, rde); } else { return RegRexbRm(m, rde); } } else { return ComputeReserveAddressRead(A, 1 << RegLog2(rde)); } } u8 *GetModrmWriteBW(P) { int lg2 = RegLog2(rde); if (IsModrmRegister(rde)) { if (!lg2) { return ByteRexbRm(m, rde); } else { return RegRexbRm(m, rde); } } else { return ComputeReserveAddressWrite(A, 1 << RegLog2(rde)); } } ================================================ FILE: blink/modrm.h ================================================ #ifndef BLINK_MODRM_H_ #define BLINK_MODRM_H_ #include "blink/builtin.h" #include "blink/machine.h" #include "blink/rde.h" #include "blink/thread.h" #include "blink/x86.h" #define RegRexbSrm(m, x) m->weg[RexbSrm(x)] #define AddrByteReg(m, k) (m->beg + kByteReg[k]) #define ByteRexrReg(m, x) AddrByteReg(m, RexRexr(x)) #define ByteRexbRm(m, x) AddrByteReg(m, RexRexb(x)) #define ByteRexbSrm(m, x) AddrByteReg(m, RexRexbSrm(x)) #define RegSrm(m, x) m->weg[Srm(x)] #define RegVreg(m, x) m->weg[Vreg(x)] #define RegRexbRm(m, x) m->weg[RexbRm(x)] #define RegRexrReg(m, x) m->weg[RexrReg(x)] #define RegRexbBase(m, x) m->weg[RexbBase(x)] #define RegRexxIndex(m, x) m->weg[Rexx(x) << 3 | SibIndex(x)] #define MmRm(m, x) m->xmm[(x & 00000001600) >> 7] #define MmReg(m, x) m->xmm[(x & 00000000007) >> 0] #define XmmRexbRm(m, x) m->xmm[RexbRm(x)] #define XmmRexrReg(m, x) m->xmm[RexrReg(x)] #ifdef HAVE_THREADS #define Lock(x) ((x & 020000000000) >> 037) #else #define Lock(x) 0 #endif #ifndef DISABLE_METAL #define Mode(x) ((x & 001400000000) >> 032) #define Eamode(x) ((x & 000300000000) >> 030) #else #define Mode(x) XED_MODE_LONG static inline u32 Eamode(u32 x) { u32 res = (x & 000300000000) >> 030; if (res == XED_MODE_REAL) __builtin_unreachable(); return res; } #endif struct AddrSeg { i64 addr; u64 seg; }; extern const u8 kByteReg[32]; u8 *GetModrmReadBW(P); u8 *GetModrmWriteBW(P); i64 ComputeAddress(P); struct AddrSeg LoadEffectiveAddress(const P); u8 *ComputeReserveAddressRead(P, size_t); u8 *ComputeReserveAddressRead1(P); u8 *ComputeReserveAddressRead4(P); u8 *ComputeReserveAddressRead8(P); u8 *ComputeReserveAddressWrite(P, size_t); u8 *ComputeReserveAddressWrite1(P); u8 *ComputeReserveAddressWrite4(P); u8 *ComputeReserveAddressWrite8(P); u8 *GetModrmRegisterBytePointerRead1(P); u8 *GetModrmRegisterBytePointerWrite1(P); u8 *GetModrmRegisterMmPointerRead(P, size_t); u8 *GetModrmRegisterMmPointerRead8(P); u8 *GetModrmRegisterMmPointerWrite(P, size_t); u8 *GetModrmRegisterMmPointerWrite8(P); u8 *GetModrmRegisterWordPointerRead(P, size_t); u8 *GetModrmRegisterWordPointerRead2(P); u8 *GetModrmRegisterWordPointerRead4(P); u8 *GetModrmRegisterWordPointerRead8(P); u8 *GetModrmRegisterWordPointerReadOsz(P); u8 *GetModrmRegisterWordPointerReadOszRexw(P); u8 *GetModrmRegisterWordPointerWrite(P, size_t); u8 *GetModrmRegisterWordPointerWrite2(P); u8 *GetModrmRegisterWordPointerWrite4(P); u8 *GetModrmRegisterWordPointerWrite8(P); u8 *GetModrmRegisterWordPointerWriteOsz(P); u8 *GetModrmRegisterWordPointerWriteOszRexw(P); u8 *GetModrmRegisterXmmPointerRead16(P); u8 *GetModrmRegisterXmmPointerRead4(P); u8 *GetModrmRegisterXmmPointerRead8(P); u8 *GetModrmRegisterXmmPointerWrite16(P); u8 *GetModrmRegisterXmmPointerWrite4(P); u8 *GetModrmRegisterXmmPointerWrite8(P); u8 *GetXmmAddress(P) returnsaligned((16)); u8 *GetMmxAddress(P) returnsaligned((8)); #endif /* BLINK_MODRM_H_ */ ================================================ FILE: blink/msr.h ================================================ #ifndef BLINK_MSR_H_ #define BLINK_MSR_H_ #define MSR_P5_TSC 0x10 // time stamp register #define MSR_P5_CESR 0x11 // control and event select register #define MSR_P5_CTR0 0x12 // counter #0 #define MSR_P5_CTR1 0x13 // counter #1 #define MSR_P5_CESR_PC 0x0200 // pin control #define MSR_P5_CESR_CC 0x01C0 // counter control mask #define MSR_P5_CESR_ES 0x003F // event control mask #define MSR_P5_CESR_SHIFT 16 // shift to get counter 1 #define MSR_P5_CESR_MASK (MSR_P5_CESR_PC | MSR_P5_CESR_CC | MSR_P5_CESR_ES) #define MSR_IA32_EFER 0xC0000080 // extended feature enable register #define MSR_IA32_EFER_LMA 0x00000400 // long mode active #define MSR_IA32_EFER_LME 0x00000100 // long mode enable #define MSR_IA32_EFER_NXE 0x00000800 // no-execute enable #define MSR_IA32_EFER_SCE 0x00000001 // syscall/sysret enable #define MSR_IA32_FS_BASE 0xC0000100 #define MSR_IA32_GS_BASE 0xC0000101 #define MSR_IA32_GS_BASE_KERNEL 0xC0000102 #define MSR_CORE_THREAD_COUNT 0x35 #define MSR_FLEX_RATIO 0x194 #define MSR_IA32_APERF 0xE8 #define MSR_IA32_APIC_BASE 0x1b #define MSR_IA32_APIC_BASE_BASE (0xfffff << 12) #define MSR_IA32_APIC_BASE_BSP (1 << 8) #define MSR_IA32_APIC_BASE_ENABLE (1 << 11) #define MSR_IA32_APIC_BASE_EXTENDED (1 << 10) #define MSR_IA32_BBL_CR_CTL 0x119 #define MSR_IA32_BIOS_SIGN_ID 0x8b #define MSR_IA32_CLOCK_MODULATION 0x19a #define MSR_IA32_CORE_C3_RESIDENCY 0x3FC #define MSR_IA32_CORE_C6_RESIDENCY 0x3FD #define MSR_IA32_CORE_C7_RESIDENCY 0x3FE #define MSR_IA32_CR_PAT 0x277 #define MSR_IA32_CSTAR 0xC0000083 #define MSR_IA32_DDR_ENERGY_STATUS 0x619 #define MSR_IA32_DEBUGCTLMSR 0x1d9 #define MSR_IA32_DS_AREA 0x600 #define MSR_IA32_EBL_CR_POWERON 0x2a #define MSR_IA32_EVNTSEL0 0x186 #define MSR_IA32_EVNTSEL1 0x187 #define MSR_IA32_EVNTSEL2 0x188 #define MSR_IA32_EVNTSEL3 0x189 #define MSR_IA32_FEATCTL_CSTATE_SMI (1 << 16) #define MSR_IA32_FEATCTL_LOCK (1 << 0) #define MSR_IA32_FEATCTL_VMXON (1 << 2) #define MSR_IA32_FEATCTL_VMXON_SMX (1 << 1) #define MSR_IA32_FEATURE_CONTROL 0x3a #define MSR_IA32_FMASK 0xC0000084 #define MSR_IA32_GT_PERF_LIMIT_REASONS 0x6B0 #define MSR_IA32_IA_PERF_LIMIT_REASONS 0x690 #define MSR_IA32_IA_PERF_LIMIT_REASONS_SKL 0x64F #define MSR_IA32_LASTBRANCHFROMIP 0x1db #define MSR_IA32_LASTBRANCHTOIP 0x1dc #define MSR_IA32_LASTINTFROMIP 0x1dd #define MSR_IA32_LASTINTTOIP 0x1de #define MSR_IA32_LLC_FLUSHED_RESIDENCY_TIMER 0x61D #define MSR_IA32_LSTAR 0xC0000082 #define MSR_IA32_MC0_ADDR 0x402 #define MSR_IA32_MC0_CTL 0x400 #define MSR_IA32_MC0_MISC 0x403 #define MSR_IA32_MC0_STATUS 0x401 #define MSR_IA32_MCG_CAP 0x179 #define MSR_IA32_MCG_CTL 0x17b #define MSR_IA32_MCG_STATUS 0x17a #define MSR_IA32_MISC_ENABLE 0x1a0 #define MSR_IA32_MPERF 0xE7 #define MSR_IA32_MTRRCAP 0xfe #define MSR_IA32_MTRR_DEF_TYPE 0x2ff #define MSR_IA32_MTRR_FIX16K_80000 0x258 #define MSR_IA32_MTRR_FIX16K_A0000 0x259 #define MSR_IA32_MTRR_FIX4K_C0000 0x268 #define MSR_IA32_MTRR_FIX4K_C8000 0x269 #define MSR_IA32_MTRR_FIX4K_D0000 0x26a #define MSR_IA32_MTRR_FIX4K_D8000 0x26b #define MSR_IA32_MTRR_FIX4K_E0000 0x26c #define MSR_IA32_MTRR_FIX4K_E8000 0x26d #define MSR_IA32_MTRR_FIX4K_F0000 0x26e #define MSR_IA32_MTRR_FIX4K_F8000 0x26f #define MSR_IA32_MTRR_FIX64K_00000 0x250 #define MSR_IA32_MTRR_PHYSBASE(n) (0x200 + 2 * (n)) #define MSR_IA32_MTRR_PHYSMASK(n) (0x200 + 2 * (n) + 1) #define MSR_IA32_P5_MC_ADDR 0 #define MSR_IA32_P5_MC_TYPE 1 #define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x1b2 #define MSR_IA32_PACKAGE_THERM_STATUS 0x1b1 #define MSR_IA32_PERFCTR0 0xc1 #define MSR_IA32_PERFCTR1 0xc2 #define MSR_IA32_PERFCTR3 0xc3 #define MSR_IA32_PERFCTR4 0xc4 #define MSR_IA32_PERF_CTL 0x199 #define MSR_IA32_PERF_FIXED_CTR0 0x309 #define MSR_IA32_PERF_FIXED_CTR_CTRL 0x38D #define MSR_IA32_PERF_GLOBAL_CTRL 0x38F #define MSR_IA32_PERF_GLOBAL_OVF_CTRL 0x390 #define MSR_IA32_PERF_GLOBAL_STATUS 0x38E #define MSR_IA32_PERF_STS 0x198 #define MSR_IA32_PKG_C10_RESIDENCY 0x632 #define MSR_IA32_PKG_C2_RESIDENCY 0x60D #define MSR_IA32_PKG_C3_RESIDENCY 0x3F8 #define MSR_IA32_PKG_C6_RESIDENCY 0x3F9 #define MSR_IA32_PKG_C7_RESIDENCY 0x3FA #define MSR_IA32_PKG_C8_RESIDENCY 0x630 #define MSR_IA32_PKG_C9_RESIDENCY 0x631 #define MSR_IA32_PKG_ENERGY_STATUS 0x611 #define MSR_IA32_PKG_POWER_SKU_UNIT 0x606 #define MSR_IA32_PLATFORM_ID 0x17 #define MSR_IA32_PP0_ENERGY_STATUS 0x639 #define MSR_IA32_PP1_ENERGY_STATUS 0x641 #define MSR_IA32_RING_PERF_STATUS 0x621 #define MSR_IA32_STAR 0xC0000081 #define MSR_IA32_SYSENTER_CS 0x174 #define MSR_IA32_SYSENTER_EIP 0x176 #define MSR_IA32_SYSENTER_ESP 0x175 #define MSR_IA32_TSC_AUX 0xC0000103 #define MSR_IA32_TSC_DEADLINE 0x6e0 #define MSR_IA32_UCODE_REV MSR_IA32_BIOS_SIGN_ID #define MSR_IA32_UCODE_WRITE MSR_IA32_UPDT_TRIG #define MSR_IA32_UPDT_TRIG 0x79 #define MSR_IA32_VMX_BASE 0x480 #define MSR_IA32_VMX_BASIC MSR_IA32_VMX_BASE #define MSR_IA32_VMX_CR0_FIXED0 MSR_IA32_VMX_BASE + 6 #define MSR_IA32_VMX_CR0_FIXED1 MSR_IA32_VMX_BASE + 7 #define MSR_IA32_VMX_CR4_FIXED0 MSR_IA32_VMX_BASE + 8 #define MSR_IA32_VMX_CR4_FIXED1 MSR_IA32_VMX_BASE + 9 #define MSR_IA32_VMX_ENTRY_CTLS MSR_IA32_VMX_BASE + 4 #define MSR_IA32_VMX_EPT_VPID_CAP MSR_IA32_VMX_BASE + 12 #define MSR_IA32_VMX_EPT_VPID_CAP_AD_SHIFT 21 #define MSR_IA32_VMX_EXIT_CTLS MSR_IA32_VMX_BASE + 3 #define MSR_IA32_VMX_MISC MSR_IA32_VMX_BASE + 5 #define MSR_IA32_VMX_PINBASED_CTLS MSR_IA32_VMX_BASE + 1 #define MSR_IA32_VMX_PROCBASED_CTLS MSR_IA32_VMX_BASE + 2 #define MSR_IA32_VMX_PROCBASED_CTLS2 MSR_IA32_VMX_BASE + 11 #define MSR_IA32_VMX_TRUE_PINBASED_CTLS MSR_IA32_VMX_BASE + 13 #define MSR_IA32_VMX_TRUE_PROCBASED_CTLS MSR_IA32_VMX_BASE + 14 #define MSR_IA32_VMX_TRUE_VMENTRY_CTLS MSR_IA32_VMX_BASE + 16 #define MSR_IA32_VMX_TRUE_VMEXIT_CTLS MSR_IA32_VMX_BASE + 15 #define MSR_IA32_VMX_VMCS_ENUM MSR_IA32_VMX_BASE + 10 #define MSR_IA32_VMX_VMFUNC MSR_IA32_VMX_BASE + 17 #define MSR_P5_CESR_CC_CLOCK 0x0100 // Clock Counting (or Event) #define MSR_P5_CESR_CC_CPL 0x00C0 // Count regardless of the CPL #define MSR_P5_CESR_CC_CPL012 0x0040 // Count if the CPL == 0, 1, 2 #define MSR_P5_CESR_CC_CPL3 0x0080 // Count if the CPL == 3 #define MSR_P5_CESR_CC_DISABLE 0x0000 // Disable counter #define MSR_P5_CESR_ES_AGI 0x011111 // Stall because of AGI #define MSR_P5_CESR_ES_BANK_CONFLICTS 0x001010 // Bank conflicts #define MSR_P5_CESR_ES_BRANCHE 0x010010 // Branches #define MSR_P5_CESR_ES_BRANCHE_BTB 0x010100 // Taken branch or BTB Hit #define MSR_P5_CESR_ES_BREAK_DR0 0x100011 // Breakpoint matches on DR0 #define MSR_P5_CESR_ES_BREAK_DR1 0x100100 // Breakpoint matches on DR1 #define MSR_P5_CESR_ES_BREAK_DR2 0x100101 // Breakpoint matches on DR2 #define MSR_P5_CESR_ES_BREAK_DR3 0x100110 // Breakpoint matches on DR3 #define MSR_P5_CESR_ES_BTB_HIT 0x010011 // BTB Hits #define MSR_P5_CESR_ES_BUS_CYCLE 0x011000 // Clocks while bus cycle #define MSR_P5_CESR_ES_CACHE_SNOOP_HIT 0x001000 // Data cache snoop hits #define MSR_P5_CESR_ES_CODE_CACHE_MISS 0x001110 // Code Cache miss #define MSR_P5_CESR_ES_CODE_READ 0x001100 // Code Read #define MSR_P5_CESR_ES_CODE_TLB_MISS 0x001101 // Code TLB miss #define MSR_P5_CESR_ES_DATA_CACHE_WB 0x000110 // Cache lines written back #define MSR_P5_CESR_ES_DATA_MEM_READ 0x011010 // Pipeline waiting for read #define MSR_P5_CESR_ES_DATA_READ 0x000000 // Data Read #define MSR_P5_CESR_ES_DATA_READ_MISS 0x000011 // Data Read Miss #define MSR_P5_CESR_ES_DATA_RW 0x101000 // Data Read or Write #define MSR_P5_CESR_ES_DATA_RW_MISS 0x101001 // Data Read or Write Miss #define MSR_P5_CESR_ES_DATA_TLB_MISS 0x000010 // Data TLB Miss #define MSR_P5_CESR_ES_DATA_WRITE 0x000001 // Data Write #define MSR_P5_CESR_ES_DATA_WRITE_MISS 0x000100 // Data Write Miss #define MSR_P5_CESR_ES_EXTERNAL_SNOOP 0x000111 // External Snoop #define MSR_P5_CESR_ES_FLOP 0x100010 // Floating Point operations #define MSR_P5_CESR_ES_FULL_WRITE_BUF 0x011001 // Clocks while full wrt buf #define MSR_P5_CESR_ES_HARDWARE_IT 0x100111 // Hardware interrupts #define MSR_P5_CESR_ES_HIT_EM 0x000101 // Write (hit) to M|E state #define MSR_P5_CESR_ES_INSTRUCTION 0x010110 // Instruction executed #define MSR_P5_CESR_ES_INSTRUCTION_V 0x010111 // Inst. executed (v-pipe) #define MSR_P5_CESR_ES_IO_CYCLE 0x011101 // I/O Read or Write cycles #define MSR_P5_CESR_ES_LOCKED_CYCLE 0x011100 // Locked bus cycles #define MSR_P5_CESR_ES_MEM_ACCESS_PIPE 0x001001 // mem access both pipes #define MSR_P5_CESR_ES_MISALIGNED 0x001011 // Misaligned Memory or I/O #define MSR_P5_CESR_ES_NON_CACHEABLE 0x011110 // Non-cacheable Mem. read #define MSR_P5_CESR_ES_PIPELINE_FLUSH 0x010101 // Pipeline Flushes #define MSR_P5_CESR_ES_SEGMENT_LOADED 0x001111 // Any segment reg. loaded #define MSR_P5_CESR_ES_WRITE_EM 0x011011 // Stall on write E|M state #define MSR_PLATFORM_INFO 0xce #endif /* BLINK_MSR_H_ */ ================================================ FILE: blink/name.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/builtin.h" #include "blink/case.h" #include "blink/debug.h" const char *DescribeMopcode(int code) { switch (code) { XLAT(0x000, "OpAlub"); XLAT(0x001, "OpAluw"); XLAT(0x002, "OpAlubFlip"); XLAT(0x003, "OpAluwFlip"); XLAT(0x004, "OpAluAlIbAdd"); XLAT(0x005, "OpAluRaxIvds"); XLAT(0x006, "OpPushSeg"); XLAT(0x007, "OpPopSeg"); XLAT(0x008, "OpAlub"); XLAT(0x009, "OpAluw"); XLAT(0x00A, "OpAlubFlip"); XLAT(0x00B, "OpAluwFlip"); XLAT(0x00C, "OpAluAlIbOr"); XLAT(0x00D, "OpAluRaxIvds"); XLAT(0x00E, "OpPushSeg"); XLAT(0x00F, "OpPopSeg"); XLAT(0x010, "OpAlub"); XLAT(0x011, "OpAluw"); XLAT(0x012, "OpAlubFlip"); XLAT(0x013, "OpAluwFlip"); XLAT(0x014, "OpAluAlIbAdc"); XLAT(0x015, "OpAluRaxIvds"); XLAT(0x016, "OpPushSeg"); XLAT(0x017, "OpPopSeg"); XLAT(0x018, "OpAlub"); XLAT(0x019, "OpAluw"); XLAT(0x01A, "OpAlubFlip"); XLAT(0x01B, "OpAluwFlip"); XLAT(0x01C, "OpAluAlIbSbb"); XLAT(0x01D, "OpAluRaxIvds"); XLAT(0x01E, "OpPushSeg"); XLAT(0x01F, "OpPopSeg"); XLAT(0x020, "OpAlub"); XLAT(0x021, "OpAluw"); XLAT(0x022, "OpAlubFlip"); XLAT(0x023, "OpAluwFlip"); XLAT(0x024, "OpAluAlIbAnd"); XLAT(0x025, "OpAluRaxIvds"); XLAT(0x026, "OpPushSeg"); XLAT(0x027, "OpPopSeg"); XLAT(0x028, "OpAlub"); XLAT(0x029, "OpAluw"); XLAT(0x02A, "OpAlubFlip"); XLAT(0x02B, "OpAluwFlip"); XLAT(0x02C, "OpAluAlIbSub"); XLAT(0x02D, "OpAluRaxIvds"); XLAT(0x02E, "OpUd"); XLAT(0x02F, "OpDas"); XLAT(0x030, "OpAlub"); XLAT(0x031, "OpAluw"); XLAT(0x032, "OpAlubFlip"); XLAT(0x033, "OpAluwFlip"); XLAT(0x034, "OpAluAlIbXor"); XLAT(0x035, "OpAluRaxIvds"); XLAT(0x036, "OpUd"); XLAT(0x037, "OpAaa"); XLAT(0x038, "OpAlubCmp"); XLAT(0x039, "OpAluwCmp"); XLAT(0x03A, "OpAlubFlipCmp"); XLAT(0x03B, "OpAluwFlipCmp"); XLAT(0x03C, "OpCmpAlIb"); XLAT(0x03D, "OpCmpRaxIvds"); XLAT(0x03E, "OpUd"); XLAT(0x03F, "OpAas"); XLAT(0x040, "OpIncZv"); XLAT(0x041, "OpIncZv"); XLAT(0x042, "OpIncZv"); XLAT(0x043, "OpIncZv"); XLAT(0x044, "OpIncZv"); XLAT(0x045, "OpIncZv"); XLAT(0x046, "OpIncZv"); XLAT(0x047, "OpIncZv"); XLAT(0x048, "OpDecZv"); XLAT(0x049, "OpDecZv"); XLAT(0x04A, "OpDecZv"); XLAT(0x04B, "OpDecZv"); XLAT(0x04C, "OpDecZv"); XLAT(0x04D, "OpDecZv"); XLAT(0x04E, "OpDecZv"); XLAT(0x04F, "OpDecZv"); XLAT(0x050, "OpPushZvq"); XLAT(0x051, "OpPushZvq"); XLAT(0x052, "OpPushZvq"); XLAT(0x053, "OpPushZvq"); XLAT(0x054, "OpPushZvq"); XLAT(0x055, "OpPushZvq"); XLAT(0x056, "OpPushZvq"); XLAT(0x057, "OpPushZvq"); XLAT(0x058, "OpPopZvq"); XLAT(0x059, "OpPopZvq"); XLAT(0x05A, "OpPopZvq"); XLAT(0x05B, "OpPopZvq"); XLAT(0x05C, "OpPopZvq"); XLAT(0x05D, "OpPopZvq"); XLAT(0x05E, "OpPopZvq"); XLAT(0x05F, "OpPopZvq"); XLAT(0x060, "OpPusha"); XLAT(0x061, "OpPopa"); XLAT(0x062, "OpUd"); XLAT(0x063, "OpMovsxdGdqpEd"); XLAT(0x064, "OpUd"); XLAT(0x065, "OpUd"); XLAT(0x066, "OpUd"); XLAT(0x067, "OpUd"); XLAT(0x068, "OpPushImm"); XLAT(0x069, "OpImulGvqpEvqpImm"); XLAT(0x06A, "OpPushImm"); XLAT(0x06B, "OpImulGvqpEvqpImm"); XLAT(0x06C, "OpIns"); XLAT(0x06D, "OpIns"); XLAT(0x06E, "OpOuts"); XLAT(0x06F, "OpOuts"); XLAT(0x070, "OpJo"); XLAT(0x071, "OpJno"); XLAT(0x072, "OpJb"); XLAT(0x073, "OpJae"); XLAT(0x074, "OpJe"); XLAT(0x075, "OpJne"); XLAT(0x076, "OpJbe"); XLAT(0x077, "OpJa"); XLAT(0x078, "OpJs"); XLAT(0x079, "OpJns"); XLAT(0x07A, "OpJp"); XLAT(0x07B, "OpJnp"); XLAT(0x07C, "OpJl"); XLAT(0x07D, "OpJge"); XLAT(0x07E, "OpJle"); XLAT(0x07F, "OpJg"); XLAT(0x080, "OpAlubiReg"); XLAT(0x081, "OpAluwiReg"); XLAT(0x082, "OpAlubiReg"); XLAT(0x083, "OpAluwiReg"); XLAT(0x084, "OpAlubTest"); XLAT(0x085, "OpAluwTest"); XLAT(0x086, "OpXchgGbEb"); XLAT(0x087, "OpXchgGvqpEvqp"); XLAT(0x088, "OpMovEbGb"); XLAT(0x089, "OpMovEvqpGvqp"); XLAT(0x08A, "OpMovGbEb"); XLAT(0x08B, "OpMovGvqpEvqp"); XLAT(0x08C, "OpMovEvqpSw"); XLAT(0x08D, "OpLeaGvqpM"); XLAT(0x08E, "OpMovSwEvqp"); XLAT(0x08F, "OpPopEvq"); XLAT(0x090, "OpNop"); XLAT(0x091, "OpXchgZvqp"); XLAT(0x092, "OpXchgZvqp"); XLAT(0x093, "OpXchgZvqp"); XLAT(0x094, "OpXchgZvqp"); XLAT(0x095, "OpXchgZvqp"); XLAT(0x096, "OpXchgZvqp"); XLAT(0x097, "OpXchgZvqp"); XLAT(0x098, "OpSax"); XLAT(0x099, "OpConvert"); XLAT(0x09A, "OpCallf"); XLAT(0x09B, "OpFwait"); XLAT(0x09C, "OpPushf"); XLAT(0x09D, "OpPopf"); XLAT(0x09E, "OpSahf"); XLAT(0x09F, "OpLahf"); XLAT(0x0A0, "OpMovAlOb"); XLAT(0x0A1, "OpMovRaxOvqp"); XLAT(0x0A2, "OpMovObAl"); XLAT(0x0A3, "OpMovOvqpRax"); XLAT(0x0A4, "OpMovsb"); XLAT(0x0A5, "OpMovs"); XLAT(0x0A6, "OpCmps"); XLAT(0x0A7, "OpCmps"); XLAT(0x0A8, "OpTestAlIb"); XLAT(0x0A9, "OpTestRaxIvds"); XLAT(0x0AA, "OpStosb"); XLAT(0x0AB, "OpStos"); XLAT(0x0AC, "OpLods"); XLAT(0x0AD, "OpLods"); XLAT(0x0AE, "OpScas"); XLAT(0x0AF, "OpScas"); XLAT(0x0B0, "OpMovZbIb"); XLAT(0x0B1, "OpMovZbIb"); XLAT(0x0B2, "OpMovZbIb"); XLAT(0x0B3, "OpMovZbIb"); XLAT(0x0B4, "OpMovZbIb"); XLAT(0x0B5, "OpMovZbIb"); XLAT(0x0B6, "OpMovZbIb"); XLAT(0x0B7, "OpMovZbIb"); XLAT(0x0B8, "OpMovZvqpIvqp"); XLAT(0x0B9, "OpMovZvqpIvqp"); XLAT(0x0BA, "OpMovZvqpIvqp"); XLAT(0x0BB, "OpMovZvqpIvqp"); XLAT(0x0BC, "OpMovZvqpIvqp"); XLAT(0x0BD, "OpMovZvqpIvqp"); XLAT(0x0BE, "OpMovZvqpIvqp"); XLAT(0x0BF, "OpMovZvqpIvqp"); XLAT(0x0C0, "OpBsubiImm"); XLAT(0x0C1, "OpBsuwiImm"); XLAT(0x0C2, "OpRetIw"); XLAT(0x0C3, "OpRet"); XLAT(0x0C4, "OpLes"); XLAT(0x0C5, "OpLds"); XLAT(0x0C6, "OpMovEbIb"); XLAT(0x0C7, "OpMovEvqpIvds"); XLAT(0x0C8, "OpUd"); XLAT(0x0C9, "OpLeave"); XLAT(0x0CA, "OpRetf"); XLAT(0x0CB, "OpRetf"); XLAT(0x0CC, "OpInterrupt3"); XLAT(0x0CD, "OpInterruptImm"); XLAT(0x0CE, "OpUd"); XLAT(0x0CF, "OpUd"); XLAT(0x0D0, "OpBsubi1"); XLAT(0x0D1, "OpBsuwi1"); XLAT(0x0D2, "OpBsubiCl"); XLAT(0x0D3, "OpBsuwiCl"); XLAT(0x0D4, "OpAam"); XLAT(0x0D5, "OpAad"); XLAT(0x0D6, "OpSalc"); XLAT(0x0D7, "OpXlatAlBbb"); XLAT(0x0D8, "OpFpu"); XLAT(0x0D9, "OpFpu"); XLAT(0x0DA, "OpFpu"); XLAT(0x0DB, "OpFpu"); XLAT(0x0DC, "OpFpu"); XLAT(0x0DD, "OpFpu"); XLAT(0x0DE, "OpFpu"); XLAT(0x0DF, "OpFpu"); XLAT(0x0E0, "OpLoopne"); XLAT(0x0E1, "OpLoope"); XLAT(0x0E2, "OpLoop1"); XLAT(0x0E3, "OpJcxz"); XLAT(0x0E4, "OpInAlImm"); XLAT(0x0E5, "OpInAxImm"); XLAT(0x0E6, "OpOutImmAl"); XLAT(0x0E7, "OpOutImmAx"); XLAT(0x0E8, "OpCallJvds"); XLAT(0x0E9, "OpJmp"); XLAT(0x0EA, "OpJmpf"); XLAT(0x0EB, "OpJmp"); XLAT(0x0EC, "OpInAlDx"); XLAT(0x0ED, "OpInAxDx"); XLAT(0x0EE, "OpOutDxAl"); XLAT(0x0EF, "OpOutDxAx"); XLAT(0x0F0, "OpUd"); XLAT(0x0F1, "OpInterrupt1"); XLAT(0x0F2, "OpUd"); XLAT(0x0F3, "OpUd"); XLAT(0x0F4, "OpHlt"); XLAT(0x0F5, "OpCmc"); XLAT(0x0F6, "Op0f6"); XLAT(0x0F7, "Op0f7"); XLAT(0x0F8, "OpClc"); XLAT(0x0F9, "OpStc"); XLAT(0x0FA, "OpCli"); XLAT(0x0FB, "OpSti"); XLAT(0x0FC, "OpCld"); XLAT(0x0FD, "OpStd"); XLAT(0x0FE, "Op0fe"); XLAT(0x0FF, "Op0ff"); XLAT(0x100, "OpUd"); XLAT(0x101, "Op101"); XLAT(0x102, "OpUd"); XLAT(0x103, "OpLsl"); XLAT(0x104, "OpUd"); XLAT(0x105, "OpSyscall"); XLAT(0x106, "OpUd"); XLAT(0x107, "OpUd"); XLAT(0x108, "OpUd"); XLAT(0x109, "OpUd"); XLAT(0x10A, "OpUd"); XLAT(0x10B, "OpUd"); XLAT(0x10C, "OpUd"); XLAT(0x10D, "OpHintNopEv"); XLAT(0x10E, "OpUd"); XLAT(0x10F, "OpUd"); XLAT(0x110, "OpMov0f10"); XLAT(0x111, "OpMovWpsVps"); XLAT(0x112, "OpMov0f12"); XLAT(0x113, "OpMov0f13"); XLAT(0x114, "OpUnpcklpsd"); XLAT(0x115, "OpUnpckhpsd"); XLAT(0x116, "OpMov0f16"); XLAT(0x117, "OpMov0f17"); XLAT(0x118, "OpHintNopEv"); XLAT(0x119, "OpHintNopEv"); XLAT(0x11A, "OpHintNopEv"); XLAT(0x11B, "OpHintNopEv"); XLAT(0x11C, "OpHintNopEv"); XLAT(0x11D, "OpHintNopEv"); XLAT(0x11E, "OpHintNopEv"); XLAT(0x11F, "OpNopEv"); XLAT(0x120, "OpMovRqCq"); XLAT(0x121, "OpUd"); XLAT(0x122, "OpMovCqRq"); XLAT(0x123, "OpUd"); XLAT(0x124, "OpUd"); XLAT(0x125, "OpUd"); XLAT(0x126, "OpUd"); XLAT(0x127, "OpUd"); XLAT(0x128, "OpMov0f28"); XLAT(0x129, "OpMovWpsVps"); XLAT(0x12A, "OpCvt0f2a"); XLAT(0x12B, "OpMov0f2b"); XLAT(0x12C, "OpCvtt0f2c"); XLAT(0x12D, "OpCvt0f2d"); XLAT(0x12E, "OpComissVsWs"); XLAT(0x12F, "OpComissVsWs"); XLAT(0x130, "OpWrmsr"); XLAT(0x131, "OpRdtsc"); XLAT(0x132, "OpRdmsr"); XLAT(0x133, "OpUd"); XLAT(0x134, "OpUd"); XLAT(0x135, "OpUd"); XLAT(0x136, "OpUd"); XLAT(0x137, "OpUd"); XLAT(0x138, "OpUd"); XLAT(0x139, "OpUd"); XLAT(0x13A, "OpUd"); XLAT(0x13B, "OpUd"); XLAT(0x13C, "OpUd"); XLAT(0x13D, "OpUd"); XLAT(0x13E, "OpUd"); XLAT(0x13F, "OpUd"); XLAT(0x140, "OpCmovo"); XLAT(0x141, "OpCmovno"); XLAT(0x142, "OpCmovb"); XLAT(0x143, "OpCmovae"); XLAT(0x144, "OpCmove"); XLAT(0x145, "OpCmovne"); XLAT(0x146, "OpCmovbe"); XLAT(0x147, "OpCmova"); XLAT(0x148, "OpCmovs"); XLAT(0x149, "OpCmovns"); XLAT(0x14A, "OpCmovp"); XLAT(0x14B, "OpCmovnp"); XLAT(0x14C, "OpCmovl"); XLAT(0x14D, "OpCmovge"); XLAT(0x14E, "OpCmovle"); XLAT(0x14F, "OpCmovg"); XLAT(0x150, "OpMovmskpsd"); XLAT(0x151, "OpSqrtpsd"); XLAT(0x152, "OpRsqrtps"); XLAT(0x153, "OpRcpps"); XLAT(0x154, "OpAndpsd"); XLAT(0x155, "OpAndnpsd"); XLAT(0x156, "OpOrpsd"); XLAT(0x157, "OpXorpsd"); XLAT(0x158, "OpAddpsd"); XLAT(0x159, "OpMulpsd"); XLAT(0x15A, "OpCvt0f5a"); XLAT(0x15B, "OpCvt0f5b"); XLAT(0x15C, "OpSubpsd"); XLAT(0x15D, "OpMinpsd"); XLAT(0x15E, "OpDivpsd"); XLAT(0x15F, "OpMaxpsd"); XLAT(0x160, "OpSsePunpcklbw"); XLAT(0x161, "OpSsePunpcklwd"); XLAT(0x162, "OpSsePunpckldq"); XLAT(0x163, "OpSsePacksswb"); XLAT(0x164, "OpSsePcmpgtb"); XLAT(0x165, "OpSsePcmpgtw"); XLAT(0x166, "OpSsePcmpgtd"); XLAT(0x167, "OpSsePackuswb"); XLAT(0x168, "OpSsePunpckhbw"); XLAT(0x169, "OpSsePunpckhwd"); XLAT(0x16A, "OpSsePunpckhdq"); XLAT(0x16B, "OpSsePackssdw"); XLAT(0x16C, "OpSsePunpcklqdq"); XLAT(0x16D, "OpSsePunpckhqdq"); XLAT(0x16E, "OpMov0f6e"); XLAT(0x16F, "OpMov0f6f"); XLAT(0x170, "OpShuffle"); XLAT(0x171, "Op171"); XLAT(0x172, "Op172"); XLAT(0x173, "Op173"); XLAT(0x174, "OpSsePcmpeqb"); XLAT(0x175, "OpSsePcmpeqw"); XLAT(0x176, "OpSsePcmpeqd"); XLAT(0x177, "OpEmms"); XLAT(0x178, "OpUd"); XLAT(0x179, "OpUd"); XLAT(0x17A, "OpUd"); XLAT(0x17B, "OpUd"); XLAT(0x17C, "OpHaddpsd"); XLAT(0x17D, "OpHsubpsd"); XLAT(0x17E, "OpMov0f7e"); XLAT(0x17F, "OpMov0f7f"); XLAT(0x180, "OpJo"); XLAT(0x181, "OpJno"); XLAT(0x182, "OpJb"); XLAT(0x183, "OpJae"); XLAT(0x184, "OpJe"); XLAT(0x185, "OpJne"); XLAT(0x186, "OpJbe"); XLAT(0x187, "OpJa"); XLAT(0x188, "OpJs"); XLAT(0x189, "OpJns"); XLAT(0x18A, "OpJp"); XLAT(0x18B, "OpJnp"); XLAT(0x18C, "OpJl"); XLAT(0x18D, "OpJge"); XLAT(0x18E, "OpJle"); XLAT(0x18F, "OpJg"); XLAT(0x190, "OpSeto"); XLAT(0x191, "OpSetno"); XLAT(0x192, "OpSetb"); XLAT(0x193, "OpSetae"); XLAT(0x194, "OpSete"); XLAT(0x195, "OpSetne"); XLAT(0x196, "OpSetbe"); XLAT(0x197, "OpSeta"); XLAT(0x198, "OpSets"); XLAT(0x199, "OpSetns"); XLAT(0x19A, "OpSetp"); XLAT(0x19B, "OpSetnp"); XLAT(0x19C, "OpSetl"); XLAT(0x19D, "OpSetge"); XLAT(0x19E, "OpSetle"); XLAT(0x19F, "OpSetg"); XLAT(0x1A0, "OpPushSeg"); XLAT(0x1A1, "OpPopSeg"); XLAT(0x1A2, "OpCpuid"); XLAT(0x1A3, "OpBit"); XLAT(0x1A4, "OpDoubleShift"); XLAT(0x1A5, "OpDoubleShift"); XLAT(0x1A6, "OpUd"); XLAT(0x1A7, "OpUd"); XLAT(0x1A8, "OpPushSeg"); XLAT(0x1A9, "OpPopSeg"); XLAT(0x1AA, "OpUd"); XLAT(0x1AB, "OpBit"); XLAT(0x1AC, "OpDoubleShift"); XLAT(0x1AD, "OpDoubleShift"); XLAT(0x1AE, "Op1ae"); XLAT(0x1AF, "OpImulGvqpEvqp"); XLAT(0x1B0, "OpCmpxchgEbAlGb"); XLAT(0x1B1, "OpCmpxchgEvqpRaxGvqp"); XLAT(0x1B2, "OpLss"); XLAT(0x1B3, "OpBit"); XLAT(0x1B4, "OpLfs"); XLAT(0x1B5, "OpLgs"); XLAT(0x1B6, "OpMovzbGvqpEb"); XLAT(0x1B7, "OpMovzwGvqpEw"); XLAT(0x1B8, "Op1b8"); XLAT(0x1B9, "OpUd"); XLAT(0x1BA, "OpBit"); XLAT(0x1BB, "OpBit"); XLAT(0x1BC, "OpBsf"); XLAT(0x1BD, "OpBsr"); XLAT(0x1BE, "OpMovsbGvqpEb"); XLAT(0x1BF, "OpMovswGvqpEw"); XLAT(0x1C0, "OpXaddEbGb"); XLAT(0x1C1, "OpXaddEvqpGvqp"); XLAT(0x1C2, "OpCmppsd"); XLAT(0x1C3, "OpMovntiMdqpGdqp"); XLAT(0x1C4, "OpPinsrwVdqEwIb"); XLAT(0x1C5, "OpPextrwGdqpUdqIb"); XLAT(0x1C6, "OpShufpsd"); XLAT(0x1C7, "Op1c7"); XLAT(0x1C8, "OpBswapZvqp"); XLAT(0x1C9, "OpBswapZvqp"); XLAT(0x1CA, "OpBswapZvqp"); XLAT(0x1CB, "OpBswapZvqp"); XLAT(0x1CC, "OpBswapZvqp"); XLAT(0x1CD, "OpBswapZvqp"); XLAT(0x1CE, "OpBswapZvqp"); XLAT(0x1CF, "OpBswapZvqp"); XLAT(0x1D0, "OpAddsubpsd"); XLAT(0x1D1, "OpSsePsrlwv"); XLAT(0x1D2, "OpSsePsrldv"); XLAT(0x1D3, "OpSsePsrlqv"); XLAT(0x1D4, "OpSsePaddq"); XLAT(0x1D5, "OpSsePmullw"); XLAT(0x1D6, "OpMov0fD6"); XLAT(0x1D7, "OpPmovmskbGdqpNqUdq"); XLAT(0x1D8, "OpSsePsubusb"); XLAT(0x1D9, "OpSsePsubusw"); XLAT(0x1DA, "OpSsePminub"); XLAT(0x1DB, "OpSsePand"); XLAT(0x1DC, "OpSsePaddusb"); XLAT(0x1DD, "OpSsePaddusw"); XLAT(0x1DE, "OpSsePmaxub"); XLAT(0x1DF, "OpSsePandn"); XLAT(0x1E0, "OpSsePavgb"); XLAT(0x1E1, "OpSsePsrawv"); XLAT(0x1E2, "OpSsePsradv"); XLAT(0x1E3, "OpSsePavgw"); XLAT(0x1E4, "OpSsePmulhuw"); XLAT(0x1E5, "OpSsePmulhw"); XLAT(0x1E6, "OpCvt0fE6"); XLAT(0x1E7, "OpMov0fE7"); XLAT(0x1E8, "OpSsePsubsb"); XLAT(0x1E9, "OpSsePsubsw"); XLAT(0x1EA, "OpSsePminsw"); XLAT(0x1EB, "OpSsePor"); XLAT(0x1EC, "OpSsePaddsb"); XLAT(0x1ED, "OpSsePaddsw"); XLAT(0x1EE, "OpSsePmaxsw"); XLAT(0x1EF, "OpSsePxor"); XLAT(0x1F0, "OpLddquVdqMdq"); XLAT(0x1F1, "OpSsePsllwv"); XLAT(0x1F2, "OpSsePslldv"); XLAT(0x1F3, "OpSsePsllqv"); XLAT(0x1F4, "OpSsePmuludq"); XLAT(0x1F5, "OpSsePmaddwd"); XLAT(0x1F6, "OpSsePsadbw"); XLAT(0x1F7, "OpMaskMovDiXmmRegXmmRm"); XLAT(0x1F8, "OpSsePsubb"); XLAT(0x1F9, "OpSsePsubw"); XLAT(0x1FA, "OpSsePsubd"); XLAT(0x1FB, "OpSsePsubq"); XLAT(0x1FC, "OpSsePaddb"); XLAT(0x1FD, "OpSsePaddw"); XLAT(0x1FE, "OpSsePaddd"); XLAT(0x1FF, "OpUd"); XLAT(0x200, "OpSsePshufb"); XLAT(0x201, "OpSsePhaddw"); XLAT(0x202, "OpSsePhaddd"); XLAT(0x203, "OpSsePhaddsw"); XLAT(0x204, "OpSsePmaddubsw"); XLAT(0x205, "OpSsePhsubw"); XLAT(0x206, "OpSsePhsubd"); XLAT(0x207, "OpSsePhsubsw"); XLAT(0x208, "OpSsePsignb"); XLAT(0x209, "OpSsePsignw"); XLAT(0x20A, "OpSsePsignd"); XLAT(0x20B, "OpSsePmulhrsw"); XLAT(0x21c, "OpSsePabsb"); XLAT(0x21d, "OpSsePabsw"); XLAT(0x21e, "OpSsePabsd"); XLAT(0x22a, "OpMovntdqaVdqMdq"); XLAT(0x240, "OpSsePmulld"); XLAT(0x30f, "OpSsePalignr"); XLAT(0x344, "OpSsePclmulqdq"); default: return "UNKNOWN"; } } ================================================ FILE: blink/ndelay.h ================================================ #ifndef BLINK_NDELAY_H_ #define BLINK_NDELAY_H_ #include #if !defined(O_NDELAY) && defined(O_NONBLOCK) #define O_NDELAY O_NONBLOCK #endif #endif /* BLINK_NDELAY_H_ */ ================================================ FILE: blink/oneoff.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include "blink/assert.h" #include "blink/bitscan.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/timespec.h" #include "blink/types.h" int main(int argc, char *argv[]) { return 0; } ================================================ FILE: blink/op101.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/jit.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/time.h" #include "blink/x86.h" static void StoreDescriptorTable(P, u16 limit, u64 base) { u64 l; l = ComputeAddress(A); if (l + 10 <= kRealSize) { Write16(m->system->real + l, limit); if (Mode(rde) == XED_MODE_LONG) { Write64(m->system->real + l + 2, base); SetWriteAddr(m, l, 10); } else { Write32(m->system->real + l + 2, base); SetWriteAddr(m, l, 6); } } else { ThrowSegmentationFault(m, l); } } static void LoadDescriptorTable(P, u16 *out_limit, u64 *out_base) { u16 limit; u64 l, base; l = ComputeAddress(A); if (l + 10 <= kRealSize) { limit = Read16(m->system->real + l); // Intel Manual Volume 2A: // - "If the operand-size attribute is 16 bits, a 16-bit limit (lower 2 // bytes) and a 24-bit base address (third, fourth, and fifth byte) are // loaded." // - "In 64-bit mode, the instruction’s operand size is fixed at 8 + 2 // bytes (an 8-byte base and a 2-byte limit)." if (Mode(rde) == XED_MODE_LONG) { base = Read64(m->system->real + l + 2); SetReadAddr(m, l, 10); } else if (!Osz(rde)) { base = Read32(m->system->real + l + 2); SetReadAddr(m, l, 6); } else { base = Read32(m->system->real + l + 2) & 0x00ffffff; SetReadAddr(m, l, 6); } *out_limit = limit; *out_base = base; } else { ThrowSegmentationFault(m, l); } } static void SgdtMs(P) { StoreDescriptorTable(A, m->system->gdt_limit, m->system->gdt_base); } static void LgdtMs(P) { LoadDescriptorTable(A, &m->system->gdt_limit, &m->system->gdt_base); } static void SidtMs(P) { StoreDescriptorTable(A, m->system->idt_limit, m->system->idt_base); } static void LidtMs(P) { LoadDescriptorTable(A, &m->system->idt_limit, &m->system->idt_base); } static void Monitor(P) { } static void Mwait(P) { } static void Swapgs(P) { } static void Vmcall(P) { } static void Vmlaunch(P) { } static void Vmresume(P) { } static void Vmxoff(P) { } static void InvlpgM(P) { i64 virt; struct AddrSeg as; // if (Cpl(m)) OpUdImpl(m); as = LoadEffectiveAddress(A); virt = as.seg + as.addr; if (Mode(rde) == XED_MODE_LONG && !(-0x800000000000 <= virt && virt < 0x800000000000)) { // In 64-bit mode, if the memory address is in non-canonical form, // then INVLPG is the same as a NOP. -Quoth Intel §invlpg return; } #ifndef DISABLE_JIT if (!IsJitDisabled(&m->system->jit)) { ResetJitPage(&m->system->jit, virt); } #endif InvalidateSystem(m->system, true, true); } static void Smsw(P, bool ismem) { if (ismem) { Store16(GetModrmRegisterWordPointerWrite2(A), m->system->cr0); } else if (Rexw(rde)) { Put64(RegRexbRm(m, rde), m->system->cr0); } else if (!Osz(rde)) { Put64(RegRexbRm(m, rde), m->system->cr0 & 0xffffffff); } else { Put16(RegRexbRm(m, rde), m->system->cr0); } } static void Lmsw(P) { // Intel V2A § 3.2: "Only the low-order 4 bits of the source operand // (which contains the PE, MP, EM, and TS flags) are loaded into CR0. // The PG, CD, NW, AM, WP, NE, and ET flags of CR0 are not affected. // The operand-size attribute has no effect on this instruction." m->system->cr0 = (m->system->cr0 & ~(u64)0xf) | (Read16(GetModrmRegisterWordPointerRead2(A)) & 0xf); } void Op101(P) { bool ismem; ismem = !IsModrmRegister(rde); switch (ModrmReg(rde)) { #ifndef DISABLE_METAL case 0: if (ismem) { SgdtMs(A); } else { switch (ModrmRm(rde)) { case 1: Vmcall(A); break; case 2: Vmlaunch(A); break; case 3: Vmresume(A); break; case 4: Vmxoff(A); break; default: OpUdImpl(m); } } break; case 1: if (ismem) { SidtMs(A); } else { switch (ModrmRm(rde)) { case 0: Monitor(A); break; case 1: Mwait(A); break; default: OpUdImpl(m); } } break; case 2: if (ismem) { LgdtMs(A); } else { OpUdImpl(m); } break; case 3: if (ismem) { LidtMs(A); } else { OpUdImpl(m); } break; case 4: Smsw(A, ismem); break; case 6: Lmsw(A); break; #endif case 7: if (ismem) { #ifndef DISABLE_METAL InvlpgM(A); #else OpUdImpl(m); #endif } else { switch (ModrmRm(rde)) { case 0: Swapgs(A); break; case 1: OpRdtscp(A); break; default: OpUdImpl(m); } } break; default: OpUdImpl(m); } } ================================================ FILE: blink/open.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/debug.h" #include "blink/errno.h" #include "blink/fds.h" #include "blink/fspath.h" #include "blink/log.h" #include "blink/overlays.h" #include "blink/random.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/vfs.h" #include "blink/xlat.h" static int SysTmpfile(struct Machine *m, i32 dirfildes, i64 pathaddr, i32 oflags, i32 mode) { long i; int lim; u64 rng; int tmpdir; int fildes; int sysflags; char name[13]; int supported; int unsupported; sigset_t ss, oldss; sysflags = O_CREAT | O_EXCL | O_CLOEXEC; switch (oflags & O_ACCMODE_LINUX) { case O_RDWR_LINUX: sysflags |= O_RDWR; break; case O_WRONLY_LINUX: sysflags |= O_WRONLY; break; default: LOGF("O_TMPFILE must O_WRONLY or O_RDWR"); return einval(); } supported = O_ACCMODE_LINUX | O_CLOEXEC_LINUX | O_EXCL_LINUX | O_LARGEFILE_LINUX; if ((unsupported = oflags & ~supported)) { LOGF("O_TMPFILE unsupported flags %#x", unsupported); return einval(); } if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); unassert(!sigfillset(&ss)); unassert(!pthread_sigmask(SIG_BLOCK, &ss, &oldss)); if ((tmpdir = VfsOpen(GetDirFildes(dirfildes), LoadStr(m, pathaddr), O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) { if (tmpdir >= lim) { VfsClose(tmpdir); fildes = emfile(); } else { unassert(GetRandom(&rng, 8, 0) == 8); for (i = 0; i < 12; ++i) { name[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[rng % 36]; rng /= 36; } name[i] = 0; if ((fildes = VfsOpen(tmpdir, name, sysflags, mode)) != -1) { unassert(!VfsUnlink(tmpdir, name, 0)); unassert(VfsDup2(fildes, tmpdir) == tmpdir); fildes = tmpdir; if (oflags & O_CLOEXEC_LINUX) { unassert(!VfsFcntl(fildes, F_SETFD, FD_CLOEXEC)); } LOCK(&m->system->fds.lock); unassert(AddFd(&m->system->fds, fildes, oflags)); UNLOCK(&m->system->fds.lock); } else { unassert(!VfsClose(tmpdir)); } } } else { fildes = -1; } unassert(!pthread_sigmask(SIG_SETMASK, &oldss, 0)); return fildes; } int SysOpenat(struct Machine *m, i32 dirfildes, i64 pathaddr, i32 oflags, i32 mode) { int lim; int fildes; int sysflags; struct Fd *fd; const char *path; #ifndef O_TMPFILE #ifndef DISABLE_NONPOSIX if ((oflags & O_TMPFILE_LINUX) == O_TMPFILE_LINUX) { return SysTmpfile(m, dirfildes, pathaddr, oflags & ~O_TMPFILE_LINUX, mode); } #endif #endif if ((sysflags = XlatOpenFlags(oflags)) == -1) return -1; if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); if (!(path = LoadStr(m, pathaddr))) return -1; RESTARTABLE(fildes = VfsOpen(GetDirFildes(dirfildes), path, sysflags, mode)); if (fildes != -1) { if (fildes >= lim) { close(fildes); fildes = emfile(); } else { LOCK(&m->system->fds.lock); unassert(fd = AddFd(&m->system->fds, fildes, sysflags)); fd->path = JoinPath(GetDirFildesPath(m->system, dirfildes), path); UNLOCK(&m->system->fds.lock); } } else { #ifdef __FreeBSD__ // Address FreeBSD divergence from IEEE Std 1003.1-2008 (POSIX.1) // in the case when O_NOFOLLOW is used, but fails due to symlink. if (errno == EMLINK) { errno = ELOOP; } #endif #ifdef __NetBSD__ // Address NetBSD divergence from IEEE Std 1003.1-2008 (POSIX.1) // in the case when O_NOFOLLOW is used but fails due to symlink. if (errno == EFTYPE) { errno = ELOOP; } #endif } return fildes; } ================================================ FILE: blink/overlays.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/overlays.h" #include #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/debug.h" #include "blink/errno.h" #include "blink/fspath.h" #include "blink/likely.h" #include "blink/log.h" #include "blink/syscall.h" #include "blink/thompike.h" #include "blink/util.h" #ifndef DISABLE_OVERLAYS #define UNREACHABLE "(unreachable)" static char **g_overlays; static void FreeStrings(char **ss) { size_t i; if (!ss) return; for (i = 0; ss[i]; ++i) { free(ss[i]); } free(ss); } static char **SplitString(const char *s, int c) { size_t n = 0; const char *t; char *e, **g, **r = 0; while (s) { if ((t = strchr(s, c))) { e = strndup(s, t - s); } else { e = strdup(s); } if (!e || !(g = (char **)realloc(r, (n + 2) * sizeof(*r)))) { free(e); FreeStrings(r); return 0; } g[n++] = e; g[n] = 0; s = t ? t + 1 : 0; r = g; } return r; } static void FreeOverlays(void) { FreeStrings(g_overlays); g_overlays = 0; } // if the user only specified a single overlay, then we treat it as // chroot would unless of course the specified root is the real one static bool IsRestrictedRoot(char **paths) { return !paths[1] && paths[0][0]; } int SetOverlays(const char *config, bool cd_into_chroot) { size_t i, j; static int once; bool has_real_root; char *path, *path2, **paths; if (!config) return efault(); if (!(paths = SplitString(config, ':'))) { return -1; } // normalize absolute paths at startup and // remove non-existent paths has_real_root = false; i = j = 0; do { path = paths[i++]; if (path) { if (!path[0] || (path[0] == '/' && !path[1])) { path[0] = 0; has_real_root = true; } else { path2 = ExpandUser(path); free(path); path = path2; path2 = (char *)malloc(PATH_MAX + 1); if (!realpath(path, path2)) { free(path); continue; } free(path); path = path2; } } paths[j++] = path; } while (path); if (!paths[0]) { LOGF("blink overlays '%s' didn't have a path that exists", config); FreeStrings(paths); return einval(); } if (!has_real_root && paths[1]) { LOGF("if multiple overlays are specified, " "one of them must be empty string"); FreeStrings(paths); return einval(); } if (cd_into_chroot && IsRestrictedRoot(paths)) { if (chdir(paths[0])) { LOGF("failed to cd into blink overlay: %s", DescribeHostErrno(errno)); FreeStrings(paths); return -1; } } if (!once) { atexit(FreeOverlays); once = 1; } FreeOverlays(); g_overlays = paths; return 0; } // if we get these failures when opening a temporary dirfd of a user // supplied overlay path, then it's definitely not a user error, and // therefore not safe to continue. static bool IsUnrecoverableErrno(void) { return errno == EINTR || errno == EMFILE || errno == ENFILE; } char *OverlaysGetcwd(char *output, size_t size) { size_t n, m; char *cwd, buf[PATH_MAX]; if (!(cwd = (getcwd)(buf, sizeof(buf)))) return 0; n = strlen(cwd); if (IsRestrictedRoot(g_overlays)) { m = strlen(g_overlays[0]); if (n == m && !memcmp(cwd, g_overlays[0], n)) { cwd[0] = '/'; cwd[1] = 0; } else if (n > m && !memcmp(cwd, g_overlays[0], m) && cwd[m] == '/') { cwd += m; } else if (strlen(UNREACHABLE) + n + 1 < sizeof(buf)) { memmove(cwd + strlen(UNREACHABLE), cwd, n + 1); memcpy(cwd, UNREACHABLE, strlen(UNREACHABLE)); } else { return 0; } n = strlen(cwd); } if (n + 1 > size) return 0; memcpy(output, cwd, n + 1); return output; } static int Chdir(const char *path) { return chdir(path); } int OverlaysChdir(const char *path) { size_t n, m; char buf[PATH_MAX]; if (!path) return efault(); if (!path[0]) return enoent(); if (IsRestrictedRoot(g_overlays) && path[0] == '/') { if (!path[1]) { return Chdir(g_overlays[0]); } else { n = strlen(g_overlays[0]); m = strlen(path); if (n + m + 1 > sizeof(buf)) { errno = ENAMETOOLONG; return -1; } memcpy(buf, g_overlays[0], n); memcpy(buf + n, path, m); buf[n + m] = 0; return Chdir(buf); } } return Chdir(path); } int OverlaysOpen(int dirfd, const char *path, int flags, int mode) { int fd; size_t i; int err = -1; if (!path) return efault(); if (!*path) return enoent(); if (path[0] != '/' && path[0]) { return openat(dirfd, path, flags, mode); } for (i = 0; g_overlays[i]; ++i) { if (!*g_overlays[i]) { if ((fd = open(path, flags, mode)) != -1) { return fd; } if (errno != ENOENT && errno != ENOTDIR) { return -1; } if (err == -1) { err = errno; } } else { dirfd = open(g_overlays[i], O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0); if (dirfd == -1) { if (IsUnrecoverableErrno()) { return -1; } else { LOGF("bad overlay %s: %s", g_overlays[i], DescribeHostErrno(errno)); continue; } } if ((fd = openat(dirfd, !path[1] ? "." : path + 1, flags, mode)) != -1) { unassert(dup2(fd, dirfd) == dirfd); if (flags & O_CLOEXEC) { unassert(!fcntl(dirfd, F_SETFD, FD_CLOEXEC)); } unassert(!close(fd)); return dirfd; } if (err == -1) { err = errno; } unassert(!close(dirfd)); if (errno != ENOENT && errno != ENOTDIR) { return -1; } } } unassert(err != -1); errno = err; return -1; } static ssize_t OverlaysGeneric(int dirfd, const char *path, void *args, ssize_t fgenericat(int, const char *, void *)) { _Static_assert(sizeof(ssize_t) >= sizeof(int), ""); size_t i; ssize_t rc; int err = -1; if (!path) return efault(); if (!*path) return enoent(); if (path[0] != '/' && path[0]) { return fgenericat(dirfd, path, args); } for (i = 0; g_overlays[i]; ++i) { if (!*g_overlays[i]) { if ((rc = fgenericat(AT_FDCWD, path, args)) != -1) { return rc; } if (err == -1) { err = errno; } if (err != ENOENT && err != ENOTDIR) { return -1; } } else { dirfd = open(g_overlays[i], O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0); if (dirfd == -1) { if (IsUnrecoverableErrno()) { return -1; } else { LOGF("bad overlay %s: %s", g_overlays[i], DescribeHostErrno(errno)); continue; } } if ((rc = fgenericat(dirfd, !path[1] ? "." : path + 1, args)) != -1) { unassert(!close(dirfd)); return rc; } if (err == -1) { err = errno; } unassert(!close(dirfd)); if (errno != ENOENT && errno != ENOTDIR) { return -1; } } } unassert(err != -1); errno = err; return -1; } //////////////////////////////////////////////////////////////////////////////// struct Stat { struct stat *st; int flags; }; static ssize_t Stat(int dirfd, const char *path, void *vargs) { struct Stat *args = (struct Stat *)vargs; return fstatat(dirfd, path, args->st, args->flags); } int OverlaysStat(int dirfd, const char *path, struct stat *st, int flags) { struct Stat args = {st, flags}; return OverlaysGeneric(dirfd, path, &args, Stat); } //////////////////////////////////////////////////////////////////////////////// struct Access { mode_t mode; int flags; }; static ssize_t Access(int dirfd, const char *path, void *vargs) { struct Access *args = (struct Access *)vargs; return faccessat(dirfd, path, args->mode, args->flags); } int OverlaysAccess(int dirfd, const char *path, mode_t mode, int flags) { struct Access args = {mode, flags}; return OverlaysGeneric(dirfd, path, &args, Access); } //////////////////////////////////////////////////////////////////////////////// struct Unlink { int flags; }; static ssize_t Unlink(int dirfd, const char *path, void *vargs) { struct Unlink *args = (struct Unlink *)vargs; return unlinkat(dirfd, path, args->flags); } int OverlaysUnlink(int dirfd, const char *path, int flags) { struct Unlink args = {flags}; return OverlaysGeneric(dirfd, path, &args, Unlink); } //////////////////////////////////////////////////////////////////////////////// struct Mkdir { mode_t mode; }; static ssize_t Mkdir(int dirfd, const char *path, void *vargs) { struct Mkdir *args = (struct Mkdir *)vargs; return mkdirat(dirfd, path, args->mode); } int OverlaysMkdir(int dirfd, const char *path, mode_t mode) { struct Mkdir args = {mode}; return OverlaysGeneric(dirfd, path, &args, Mkdir); } //////////////////////////////////////////////////////////////////////////////// struct Mkfifo { mode_t mode; }; static ssize_t Mkfifo(int dirfd, const char *path, void *vargs) { struct Mkfifo *args = (struct Mkfifo *)vargs; return mkfifoat(dirfd, path, args->mode); } int OverlaysMkfifo(int dirfd, const char *path, mode_t mode) { struct Mkfifo args = {mode}; return OverlaysGeneric(dirfd, path, &args, Mkfifo); } //////////////////////////////////////////////////////////////////////////////// struct Chmod { mode_t mode; int flags; }; static ssize_t Chmod(int dirfd, const char *path, void *vargs) { struct Chmod *args = (struct Chmod *)vargs; return fchmodat(dirfd, path, args->mode, args->flags); } int OverlaysChmod(int dirfd, const char *path, mode_t mode, int flags) { struct Chmod args = {mode, flags}; return OverlaysGeneric(dirfd, path, &args, Chmod); } //////////////////////////////////////////////////////////////////////////////// struct Chown { uid_t uid; gid_t gid; int flags; }; static ssize_t Chown(int dirfd, const char *path, void *vargs) { struct Chown *args = (struct Chown *)vargs; return fchownat(dirfd, path, args->uid, args->gid, args->flags); } int OverlaysChown(int dirfd, const char *path, uid_t uid, gid_t gid, int flags) { struct Chown args = {uid, gid, flags}; return OverlaysGeneric(dirfd, path, &args, Chown); } //////////////////////////////////////////////////////////////////////////////// struct Symlink { const char *target; }; static ssize_t Symlink(int dirfd, const char *path, void *vargs) { struct Symlink *args = (struct Symlink *)vargs; return symlinkat(args->target, dirfd, path); } int OverlaysSymlink(const char *target, int dirfd, const char *path) { struct Symlink args = {target}; return OverlaysGeneric(dirfd, path, &args, Symlink); } //////////////////////////////////////////////////////////////////////////////// struct Readlink { char *buf; size_t size; }; static ssize_t Readlink(int dirfd, const char *path, void *vargs) { struct Readlink *args = (struct Readlink *)vargs; return readlinkat(dirfd, path, args->buf, args->size); } ssize_t OverlaysReadlink(int dirfd, const char *path, char *buf, size_t size) { struct Readlink args = {buf, size}; return OverlaysGeneric(dirfd, path, &args, Readlink); } //////////////////////////////////////////////////////////////////////////////// struct Utime { const struct timespec *times; int flags; }; static ssize_t Utime(int dirfd, const char *path, void *vargs) { struct Utime *args = (struct Utime *)vargs; return utimensat(dirfd, path, args->times, args->flags); } int OverlaysUtime(int dirfd, const char *path, const struct timespec times[2], int flags) { struct Utime args = {times, flags}; return OverlaysGeneric(dirfd, path, &args, Utime); } //////////////////////////////////////////////////////////////////////////////// static ssize_t OverlaysGeneric2(int srcdirfd, const char *srcpath, int dstdirfd, const char *dstpath, void *args, ssize_t fgenericat(int, const char *, int, const char *, void *)) { ssize_t rc; int err = -1; ssize_t i, j; const char *sp, *dp; int srccloseme, dstcloseme; if (!srcpath || !dstpath) return efault(); if (!*srcpath || !*dstpath) return enoent(); for (j = 0; j >= 0 && g_overlays[j]; ++j) { if (srcpath[0] != '/' && srcpath[0]) { j = -2; sp = srcpath; srccloseme = -1; } else if (!*g_overlays[j]) { srcdirfd = AT_FDCWD; srccloseme = -1; sp = srcpath; } else { sp = !srcpath[1] ? "." : srcpath + 1; srccloseme = srcdirfd = open(g_overlays[j], O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0); if (srcdirfd == -1) { if (IsUnrecoverableErrno()) { return -1; } else { LOGF("bad overlay %s: %s", g_overlays[j], DescribeHostErrno(errno)); continue; } } } for (i = 0; i >= 0 && g_overlays[i]; ++i) { if (dstpath[0] != '/' && dstpath[0]) { i = -2; dp = dstpath; dstcloseme = -1; } else if (!*g_overlays[i]) { dstdirfd = AT_FDCWD; dstcloseme = -1; dp = dstpath; } else { dp = !dstpath[1] ? "." : dstpath + 1; dstcloseme = dstdirfd = open(g_overlays[i], O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0); if (dstdirfd == -1) { if (IsUnrecoverableErrno()) { if (srccloseme != -1) close(srccloseme); return -1; } else { LOGF("bad overlay %s: %s", g_overlays[i], DescribeHostErrno(errno)); continue; } } } if ((rc = fgenericat(srcdirfd, sp, dstdirfd, dp, args)) != -1) { if (dstcloseme != -1) close(dstcloseme); if (srccloseme != -1) close(srccloseme); return rc; } if (err == -1) { err = errno; } if (dstcloseme != -1) close(dstcloseme); if (errno != ENOENT && errno != ENOTDIR) { if (srccloseme != -1) close(srccloseme); return -1; } } if (srccloseme != -1) close(srccloseme); } unassert(err != -1); errno = err; return -1; } //////////////////////////////////////////////////////////////////////////////// static ssize_t Rename(int srcdirfd, const char *srcpath, int dstdirfd, const char *dstpath, void *vargs) { return renameat(srcdirfd, srcpath, dstdirfd, dstpath); } int OverlaysRename(int srcdirfd, const char *srcpath, int dstdirfd, const char *dstpath) { return OverlaysGeneric2(srcdirfd, srcpath, dstdirfd, dstpath, 0, Rename); } //////////////////////////////////////////////////////////////////////////////// struct Link { int flags; }; static ssize_t Link(int srcdirfd, const char *srcpath, int dstdirfd, const char *dstpath, void *vargs) { struct Link *args = (struct Link *)vargs; return linkat(srcdirfd, srcpath, dstdirfd, dstpath, args->flags); } int OverlaysLink(int srcdirfd, const char *srcpath, int dstdirfd, const char *dstpath, int flags) { struct Link args = {flags}; return OverlaysGeneric2(srcdirfd, srcpath, dstdirfd, dstpath, &args, Link); } #endif /* DISABLE_OVERLAYS */ ================================================ FILE: blink/overlays.h ================================================ #ifndef BLINK_OVERLAYS_H_ #define BLINK_OVERLAYS_H_ #include #include #include #include #define DEFAULT_OVERLAYS ":o" int OverlaysChdir(const char *); int SetOverlays(const char *, bool); char *OverlaysGetcwd(char *, size_t); int OverlaysUnlink(int, const char *, int); int OverlaysMkdir(int, const char *, mode_t); int OverlaysMkfifo(int, const char *, mode_t); int OverlaysOpen(int, const char *, int, int); int OverlaysChmod(int, const char *, mode_t, int); int OverlaysAccess(int, const char *, mode_t, int); int OverlaysSymlink(const char *, int, const char *); int OverlaysStat(int, const char *, struct stat *, int); int OverlaysChown(int, const char *, uid_t, gid_t, int); int OverlaysRename(int, const char *, int, const char *); ssize_t OverlaysReadlink(int, const char *, char *, size_t); int OverlaysLink(int, const char *, int, const char *, int); int OverlaysUtime(int, const char *, const struct timespec[2], int); #endif /* BLINK_OVERLAYS_H_ */ ================================================ FILE: blink/panel.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/panel.h" #include #include #include "blink/assert.h" #include "blink/bitscan.h" #include "blink/buffer.h" #include "blink/builtin.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/types.h" #include "blink/util.h" static int tpdecode(const char *s, wint_t *out) { u32 wc, cb, need, msb, j, i = 0; if ((wc = s[i++] & 255) == -1) return -1; while ((wc & 0300) == 0200) { if ((wc = s[i++] & 255) == -1) return -1; } if (!(0 <= wc && wc <= 0x7F)) { msb = wc < 252 ? bsr(~wc & 0xff) : 1; need = 7 - msb; wc &= ((1u << msb) - 1) | 0003; for (j = 1; j < need; ++j) { if ((cb = s[i++] & 255) == -1) return -1; if ((cb & 0300) == 0200) { wc = wc << 6 | (cb & 077); } else { if (out) *out = 0xFFFD; return -1; } } } if (out) *out = wc; return i; } /** * Renders panel div flex boxen inside terminal display for tui. * * You can use all the UNICODE and ANSI escape sequences you want. * * @param pn is number of panels * @param p is panel list in logically sorted order * @param tyn is terminal height in cells * @param txn is terminal width in cells * @param size optionally receives length of result * @return ANSI codes, or null w/ errno */ char *RenderPanels(long pn, struct Panel *p, long tyn, long txn, size_t *size) { wint_t wc; struct Buffer b, *l; int x, y, i, j, width; enum { kUtf8, kAnsi, kAnsiCsi } s; memset(&b, 0, sizeof(b)); AppendStr(&b, "\033[H"); for (y = 0; y < tyn; ++y) { if (y) AppendFmt(&b, "\033[%dH", y + 1); for (x = i = 0; i < pn; ++i) { if (p[i].top <= y && y < p[i].bottom) { j = 0; s = kUtf8; l = &p[i].lines[y - p[i].top]; while (x + 8 <= p[i].left) { char t[8] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; AppendData(&b, t, 8); x += 8; } while (x < p[i].left) { AppendChar(&b, ' '); x += 1; } while (x < p[i].right || j < l->i) { wc = '\0'; width = 0; if (j < l->i) { wc = l->p[j]; switch (s) { case kUtf8: switch (wc & 255) { case 033: s = kAnsi; ++j; break; default: j += abs(tpdecode(l->p + j, &wc)); if (x < p[i].right) { width = wcwidth(wc); width = MAX(1, width); } else { wc = 0; } break; } break; case kAnsi: switch (wc & 255) { case '[': s = kAnsiCsi; ++j; break; case '@': case ']': case '^': case '_': case '\\': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': s = kUtf8; ++j; break; default: s = kUtf8; continue; } break; case kAnsiCsi: switch (wc & 255) { case ':': case ';': case '<': case '=': case '>': case '?': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ++j; break; case '`': case '~': case '^': case '@': case '[': case ']': case '{': case '}': case '_': case '|': case '\\': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': s = kUtf8; ++j; break; default: s = kUtf8; continue; } break; default: __builtin_unreachable(); } if (x > p[i].right) { break; } } else if (x < p[i].right) { wc = ' '; width = 1; } if (wc) { x += width; AppendWide(&b, wc); } } } } } unassert(b.p = (char *)realloc(b.p, b.i + 1)); if (size) *size = b.i; return b.p; } ================================================ FILE: blink/panel.h ================================================ #ifndef BLINK_PANEL_H_ #define BLINK_PANEL_H_ #include #include #include "blink/buffer.h" struct Panel { int top; int bottom; int left; int right; struct Buffer *lines; int n; }; char *RenderPanels(long, struct Panel *, long, long, size_t *); void PrintMessageBox(int, const char *, long, long); #endif /* BLINK_PANEL_H_ */ ================================================ FILE: blink/path.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/debug.h" #include "blink/dis.h" #include "blink/high.h" #include "blink/jit.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/overlays.h" #include "blink/rde.h" #include "blink/stats.h" #include "blink/vfs.h" #define APPEND(...) o += snprintf(b + o, o > n ? 0 : n - o, __VA_ARGS__) #ifdef HAVE_JIT void (*AddPath_StartOp_Hook)(P); #if LOG_COD static int g_cod; static struct Dis g_dis; #endif static void StartPath(struct Machine *m, i64 pc) { JIX_LOGF("%" PRIx64 ":%" PRIx64 " ", GetPc(m), pc); } static void DebugOp(struct Machine *m, i64 expected_ip) { if (m->ip != expected_ip) { ERRF("IP was %" PRIx64 " but it should have been %" PRIx64, m->ip, expected_ip); } unassert(m->ip == expected_ip); } static void StartOp(struct Machine *m, i64 pc) { JIX_LOGF("%" PRIx64 ":%" PRIx64 " ", GetPc(m), pc); JIX_LOGF("%" PRIx64 ":%" PRIx64 " %s", GetPc(m), pc, DescribeOp(m, pc)); unassert(!IsMakingPath(m)); } static void EndOp(struct Machine *m, i64 pc) { JIX_LOGF("%" PRIx64 ":%" PRIx64 " ", GetPc(m), pc); m->oplen = 0; if (m->stashaddr) { CommitStash(m); } } static void EndPath(struct Machine *m, i64 pc) { JIX_LOGF("%" PRIx64 ":%" PRIx64 " %s", GetPc(m), GetPc(m), DescribeOp(m, GetPc(m))); JIX_LOGF("%" PRIx64 ":%" PRIx64 " ", GetPc(m), GetPc(m)); } void FuseOp(struct Machine *m, i64 pc) { JIX_LOGF("%" PRIx64 ":%" PRIx64 " %s", GetPc(m), pc, DescribeOp(m, pc)); JIX_LOGF("%" PRIx64 ":%" PRIx64 " ", GetPc(m), pc); } #ifdef HAVE_JIT #if defined(__x86_64__) static const u8 kEnter[] = { 0x55, // push %rbp 0x48, 0x89, 0345, // mov %rsp,%rbp #ifdef __CYGWIN__ // 0x48, 0x83, 0354, 0x40, // sub $0x40,%rsp 0x48, 0x89, 0175, 0xc8, // mov %rdi,-0x38(%rbp) 0x48, 0x89, 0165, 0xd0, // mov %rsi,-0x30(%rbp) #else // 0x48, 0x83, 0354, 0x30, // sub $0x30,%rsp #endif // 0x48, 0x89, 0135, 0xd8, // mov %rbx,-0x28(%rbp) 0x4c, 0x89, 0145, 0xe0, // mov %r12,-0x20(%rbp) 0x4c, 0x89, 0155, 0xe8, // mov %r13,-0x18(%rbp) 0x4c, 0x89, 0165, 0xf0, // mov %r14,-0x10(%rbp) 0x4c, 0x89, 0175, 0xf8, // mov %r15,-0x08(%rbp) #ifdef __CYGWIN__ // 0x48, 0x89, 0313, // mov %rcx,%rbx #else // 0x48, 0x89, 0373, // mov %rdi,%rbx #endif }; static const u8 kLeave[] = { 0x4c, 0x8b, 0175, 0xf8, // mov -0x08(%rbp),%r15 0x4c, 0x8b, 0165, 0xf0, // mov -0x10(%rbp),%r14 0x4c, 0x8b, 0155, 0xe8, // mov -0x18(%rbp),%r13 0x4c, 0x8b, 0145, 0xe0, // mov -0x20(%rbp),%r12 0x48, 0x8b, 0135, 0xd8, // mov -0x28(%rbp),%rbx #ifdef __CYGWIN__ 0x48, 0x8b, 0165, 0xd0, // mov -0x30(%rbp),%rsi 0x48, 0x8b, 0175, 0xc8, // mov -0x38(%rbp),%rdi 0x48, 0x83, 0304, 0x40, // add $0x40,%rsp #else 0x48, 0x83, 0304, 0x30, // add $0x30,%rsp #endif 0x5d, // pop %rbp }; #elif defined(__aarch64__) static const u32 kEnter[] = { 0xa9bc7bfd, // stp x29, x30, [sp, #-64]! 0x910003fd, // mov x29, sp 0xa90153f3, // stp x19, x20, [sp, #16] 0xa9025bf5, // stp x21, x22, [sp, #32] 0xa90363f7, // stp x23, x24, [sp, #48] 0xaa0003f3, // mov x19, x0 }; static const u32 kLeave[] = { 0xa94153f3, // ldp x19, x20, [sp, #16] 0xa9425bf5, // ldp x21, x22, [sp, #32] 0xa94363f7, // ldp x23, x24, [sp, #48] 0xa8c47bfd, // ldp x29, x30, [sp], #64 }; #endif /* __x86_64__ */ #endif /* HAVE_JIT */ long GetPrologueSize(void) { #ifdef HAVE_JIT return sizeof(kEnter); #else return 0; #endif } void(SetupCod)(struct Machine *m) { #if LOG_COD m->system->dis = &g_dis; LoadDebugSymbols(m->system); DisLoadElf(&g_dis, &m->system->elf); g_cod = VfsOpen(AT_FDCWD_LINUX, "/tmp/blink.s", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); g_cod = VfsFcntl(g_cod, F_DUPFD_CLOEXEC, kMinBlinkFd); #endif } void(LogCodOp)(struct Machine *m, const char *s) { #if LOG_COD // FlushCod(m->path.jb); WriteCod("/\t%s\n", s); #endif } void(WriteCod)(const char *fmt, ...) { #if LOG_COD int n; va_list va; char buf[256]; if (!g_cod) return; va_start(va, fmt); n = vsnprintf(buf, sizeof(buf), fmt, va); va_end(va); write(g_cod, buf, MIN(n, sizeof(buf))); #endif } void BeginCod(struct Machine *m, i64 pc) { #if LOG_COD char b[256]; char spec[64]; int i, o = 0, n = sizeof(b); if (!g_cod) return; DISABLE_HIGHLIGHT_BEGIN; APPEND("/\t"); unassert(!GetInstruction(m, pc, g_dis.xedd)); DisInst(&g_dis, b + o, DisSpec(g_dis.xedd, spec)); o = strlen(b); APPEND(" #"); for (i = 0; i < g_dis.xedd->length; ++i) { APPEND(" %02x", g_dis.xedd->bytes[i]); } APPEND(" @ %" PRIx64, m->ip); APPEND("\n"); write(g_cod, b, MIN(o, n)); DISABLE_HIGHLIGHT_END; #endif } void FlushCod(struct JitBlock *jb) { #if LOG_COD char b[256]; char spec[64]; if (!g_cod) return; if (jb->index == jb->blocksize + 1) { WriteCod("/\tOOM!\n"); jb->cod = jb->index; return; } DISABLE_HIGHLIGHT_BEGIN; for (; jb->cod < jb->index; jb->cod += g_dis.xedd->length) { unassert(!DecodeInstruction(g_dis.xedd, jb->addr + jb->cod, jb->index - jb->cod, XED_MODE_LONG)); g_dis.addr = (uintptr_t)jb->addr + jb->cod; DisInst(&g_dis, b, DisSpec(g_dis.xedd, spec)); WriteCod("\t%s\n", b); } DISABLE_HIGHLIGHT_END; #endif } static bool IsPure(u64 rde) { switch (Mopcode(rde)) { case 0x004: // OpAluAlIbAdd case 0x005: // OpAluRaxIvds case 0x00C: // OpAluAlIbOr case 0x00D: // OpAluRaxIvds case 0x014: // OpAluAlIbAdc case 0x015: // OpAluRaxIvds case 0x01C: // OpAluAlIbSbb case 0x01D: // OpAluRaxIvds case 0x024: // OpAluAlIbAnd case 0x025: // OpAluRaxIvds case 0x02C: // OpAluAlIbSub case 0x02D: // OpAluRaxIvds case 0x034: // OpAluAlIbXor case 0x035: // OpAluRaxIvds case 0x03C: // OpCmpAlIb case 0x03D: // OpCmpRaxIvds case 0x090: // OpNop case 0x091: // OpXchgZvqp case 0x092: // OpXchgZvqp case 0x093: // OpXchgZvqp case 0x094: // OpXchgZvqp case 0x095: // OpXchgZvqp case 0x096: // OpXchgZvqp case 0x097: // OpXchgZvqp case 0x098: // OpSax case 0x099: // OpConvert case 0x09E: // OpSahf case 0x09F: // OpLahf case 0x0A1: // OpMovRaxOvqp case 0x0A3: // OpMovOvqpRax case 0x0A8: // OpTestAlIb case 0x0A9: // OpTestRaxIvds case 0x0B0: // OpMovZbIb case 0x0B1: // OpMovZbIb case 0x0B2: // OpMovZbIb case 0x0B3: // OpMovZbIb case 0x0B4: // OpMovZbIb case 0x0B5: // OpMovZbIb case 0x0B6: // OpMovZbIb case 0x0B7: // OpMovZbIb case 0x0B8: // OpMovZvqpIvqp case 0x0B9: // OpMovZvqpIvqp case 0x0BA: // OpMovZvqpIvqp case 0x0BB: // OpMovZvqpIvqp case 0x0BC: // OpMovZvqpIvqp case 0x0BD: // OpMovZvqpIvqp case 0x0BE: // OpMovZvqpIvqp case 0x0BF: // OpMovZvqpIvqp case 0x0D6: // OpSalc case 0x0F5: // OpCmc case 0x0F8: // OpClc case 0x0F9: // OpStc case 0x11F: // OpNopEv case 0x150: // OpMovmskpsd case 0x1D7: // OpPmovmskbGdqpNqUdq case 0x1C8: // OpBswapZvqp case 0x1C9: // OpBswapZvqp case 0x1CA: // OpBswapZvqp case 0x1CB: // OpBswapZvqp case 0x1CC: // OpBswapZvqp case 0x1CD: // OpBswapZvqp case 0x1CE: // OpBswapZvqp case 0x1CF: // OpBswapZvqp case 0x050: // OpPushZvq case 0x051: // OpPushZvq case 0x052: // OpPushZvq case 0x053: // OpPushZvq case 0x054: // OpPushZvq case 0x055: // OpPushZvq case 0x056: // OpPushZvq case 0x057: // OpPushZvq case 0x058: // OpPopZvq case 0x059: // OpPopZvq case 0x05A: // OpPopZvq case 0x05B: // OpPopZvq case 0x05C: // OpPopZvq case 0x05D: // OpPopZvq case 0x05E: // OpPopZvq case 0x05F: // OpPopZvq return true; case 0x000: // OpAlub case 0x001: // OpAluw case 0x002: // OpAlubFlip case 0x003: // OpAluwFlip case 0x008: // OpAlub case 0x009: // OpAluw case 0x00A: // OpAlubFlip case 0x00B: // OpAluwFlip case 0x010: // OpAlub case 0x011: // OpAluw case 0x012: // OpAlubFlip case 0x013: // OpAluwFlip case 0x018: // OpAlub case 0x019: // OpAluw case 0x01A: // OpAlubFlip case 0x01B: // OpAluwFlip case 0x020: // OpAlub case 0x021: // OpAluw case 0x022: // OpAlubFlip case 0x023: // OpAluwFlip case 0x028: // OpAlub case 0x029: // OpAluw case 0x02A: // OpAlubFlip case 0x02B: // OpAluwFlip case 0x030: // OpAlub case 0x031: // OpAluw case 0x032: // OpAlubFlip case 0x033: // OpAluwFlip case 0x038: // OpAlubCmp case 0x039: // OpAluwCmp case 0x03A: // OpAlubFlipCmp case 0x03B: // OpAluwFlipCmp case 0x063: // OpMovsxdGdqpEd case 0x069: // OpImulGvqpEvqpImm case 0x06B: // OpImulGvqpEvqpImm case 0x080: // OpAlubiReg case 0x081: // OpAluwiReg case 0x082: // OpAlubiReg case 0x083: // OpAluwiReg case 0x084: // OpAlubTest case 0x085: // OpAluwTest case 0x086: // OpXchgGbEb case 0x087: // OpXchgGvqpEvqp case 0x088: // OpMovEbGb case 0x089: // OpMovEvqpGvqp case 0x08A: // OpMovGbEb case 0x08B: // OpMovGvqpEvqp case 0x0C0: // OpBsubiImm case 0x0C1: // OpBsuwiImm case 0x0C6: // OpMovEbIb case 0x0C7: // OpMovEvqpIvds case 0x0D0: // OpBsubi1 case 0x0D1: // OpBsuwi1 case 0x0D2: // OpBsubiCl case 0x0D3: // OpBsuwiCl case 0x0F6: // Op0f6 case 0x0F7: // Op0f7 case 0x140: // OpCmovo case 0x141: // OpCmovno case 0x142: // OpCmovb case 0x143: // OpCmovae case 0x144: // OpCmove case 0x145: // OpCmovne case 0x146: // OpCmovbe case 0x147: // OpCmova case 0x148: // OpCmovs case 0x149: // OpCmovns case 0x14A: // OpCmovp case 0x14B: // OpCmovnp case 0x14C: // OpCmovl case 0x14D: // OpCmovge case 0x14E: // OpCmovle case 0x14F: // OpCmovg case 0x190: // OpSeto case 0x191: // OpSetno case 0x192: // OpSetb case 0x193: // OpSetae case 0x194: // OpSete case 0x195: // OpSetne case 0x196: // OpSetbe case 0x197: // OpSeta case 0x198: // OpSets case 0x199: // OpSetns case 0x19A: // OpSetp case 0x19B: // OpSetnp case 0x19C: // OpSetl case 0x19D: // OpSetge case 0x19E: // OpSetle case 0x19F: // OpSetg case 0x1A3: // OpBit case 0x1A4: // OpDoubleShift case 0x1A5: // OpDoubleShift case 0x1AB: // OpBit case 0x1AC: // OpDoubleShift case 0x1AD: // OpDoubleShift case 0x1AF: // OpImulGvqpEvqp case 0x1B3: // OpBit case 0x1B6: // OpMovzbGvqpEb case 0x1B7: // OpMovzwGvqpEw case 0x1BA: // OpBit case 0x1BB: // OpBit case 0x1BC: // OpBsf case 0x1BD: // OpBsr case 0x1BE: // OpMovsbGvqpEb case 0x1BF: // OpMovswGvqpEw case 0x110: // sse moves case 0x111: // sse moves case 0x112: // sse moves case 0x113: // sse moves case 0x114: // unpcklpsd case 0x115: // unpckhpsd case 0x116: // sse moves case 0x117: // sse moves case 0x128: // sse moves case 0x129: // sse moves case 0x12A: // sse convs case 0x12B: // sse moves case 0x12C: // sse convs case 0x12D: // sse convs case 0x160: // OpSsePunpcklbw case 0x161: // OpSsePunpcklwd case 0x162: // OpSsePunpckldq case 0x163: // OpSsePacksswb case 0x164: // OpSsePcmpgtb case 0x165: // OpSsePcmpgtw case 0x166: // OpSsePcmpgtd case 0x167: // OpSsePackuswb case 0x168: // OpSsePunpckhbw case 0x169: // OpSsePunpckhwd case 0x16A: // OpSsePunpckhdq case 0x16B: // OpSsePackssdw case 0x16C: // OpSsePunpcklqdq case 0x16D: // OpSsePunpckhqdq case 0x16E: // OpMov0f6e case 0x16F: // OpMov0f6f case 0x170: // OpShuffle case 0x171: // Op171 case 0x172: // Op172 case 0x173: // Op173 case 0x174: // OpSsePcmpeqb case 0x175: // OpSsePcmpeqw case 0x176: // OpSsePcmpeqd case 0x17E: // OpMov0f7e case 0x17F: // OpMov0f7f case 0x1D1: // OpSsePsrlwv case 0x1D2: // OpSsePsrldv case 0x1D3: // OpSsePsrlqv case 0x1D4: // OpSsePaddq case 0x1D5: // OpSsePmullw case 0x1D8: // OpSsePsubusb case 0x1D9: // OpSsePsubusw case 0x1DA: // OpSsePminub case 0x1DB: // OpSsePand case 0x1DC: // OpSsePaddusb case 0x1DD: // OpSsePaddusw case 0x1DE: // OpSsePmaxub case 0x1DF: // OpSsePandn case 0x1E0: // OpSsePavgb case 0x1E1: // OpSsePsrawv case 0x1E2: // OpSsePsradv case 0x1E3: // OpSsePavgw case 0x1E4: // OpSsePmulhuw case 0x1E5: // OpSsePmulhw case 0x1E8: // OpSsePsubsb case 0x1E9: // OpSsePsubsw case 0x1EA: // OpSsePminsw case 0x1EB: // OpSsePor case 0x1EC: // OpSsePaddsb case 0x1ED: // OpSsePaddsw case 0x1EE: // OpSsePmaxsw case 0x1EF: // OpSsePxor case 0x1F1: // OpSsePsllwv case 0x1F2: // OpSsePslldv case 0x1F3: // OpSsePsllqv case 0x1F4: // OpSsePmuludq case 0x1F5: // OpSsePmaddwd case 0x1F6: // OpSsePsadbw case 0x1F8: // OpSsePsubb case 0x1F9: // OpSsePsubw case 0x1FA: // OpSsePsubd case 0x1FB: // OpSsePsubq case 0x1FC: // OpSsePaddb case 0x1FD: // OpSsePaddw case 0x1FE: // OpSsePaddd case 0x200: // OpSsePshufb case 0x201: // OpSsePhaddw case 0x202: // OpSsePhaddd case 0x203: // OpSsePhaddsw case 0x204: // OpSsePmaddubsw case 0x205: // OpSsePhsubw case 0x206: // OpSsePhsubd case 0x207: // OpSsePhsubsw case 0x208: // OpSsePsignb case 0x209: // OpSsePsignw case 0x20A: // OpSsePsignd case 0x20B: // OpSsePmulhrsw case 0x2F6: // adcx, adox, mulx case 0x344: // pclmulqdq return IsModrmRegister(rde); case 0x08D: // OpLeaGvqpM return !IsRipRelative(rde); case 0x0FF: return IsModrmRegister(rde) && // (ModrmReg(rde) == 0 || // inc ModrmReg(rde) == 1); // dec default: return false; } } static bool MustUpdateIp(P) { u64 next; if (!IsPure(rde)) return true; next = m->ip + Oplength(rde); if (GetJitHook(&m->system->jit, next)) return true; return false; } static void InitPaths(struct System *s) { #ifdef HAVE_JIT struct JitBlock *jb; if (!s->ender) { unassert((jb = StartJit(&s->jit, 0))); WriteCod("\nJit_%p:\n", jb->addr + jb->index); s->ender = GetJitPc(jb); #if LOG_JIX AppendJitMovReg(jb, kJitArg0, kJitSav0); AppendJitCall(jb, (void *)EndPath); #endif AppendJit(jb, kLeave, sizeof(kLeave)); AppendJitRet(jb); FlushCod(jb); unassert(FinishJit(&s->jit, jb)); } #endif } bool CreatePath(P) { #ifdef HAVE_JIT bool res; i64 pc, jpc; unassert(!IsMakingPath(m)); InitPaths(m->system); if (m->path.skip > 0) { --m->path.skip; return false; } if ((pc = GetPc(m))) { if ((m->path.jb = StartJit(&m->system->jit, pc))) { JIP_LOGF("starting new path jit_pc:%" PRIxPTR " at pc:%" PRIx64, GetJitPc(m->path.jb), pc); FlushCod(m->path.jb); jpc = (uintptr_t)m->path.jb->addr + m->path.jb->index; (void)jpc; AppendJit(m->path.jb, kEnter, sizeof(kEnter)); #if LOG_JIX Jitter(A, "a1i" // arg1 = ip "q" // arg0 = machine "c" // call function (StartPath) "q", // arg0 = machine GetPc(m), StartPath); #endif WriteCod("\nJit_%" PRIx64 "_%" PRIx64 ":\n", pc, jpc); FlushCod(m->path.jb); m->path.start = pc; m->path.elements = 0; res = true; } else { res = false; } } else { res = false; } return res; #else return false; #endif } void CompletePath(P) { unassert(IsMakingPath(m)); FlushSkew(A); AppendJitJump(m->path.jb, (void *)m->system->ender); FinishPath(m); } void FinishPath(struct Machine *m) { unassert(IsMakingPath(m)); FlushCod(m->path.jb); STATISTIC(path_longest_bytes = MAX(path_longest_bytes, m->path.jb->index - m->path.jb->start)); STATISTIC(path_longest = MAX(path_longest, m->path.elements)); STATISTIC(AVERAGE(path_average_elements, m->path.elements)); STATISTIC(AVERAGE(path_average_bytes, m->path.jb->index - m->path.jb->start)); if (FinishJit(&m->system->jit, m->path.jb)) { STATISTIC(++path_count); JIP_LOGF("staged path to %" PRIx64, m->path.start); } else { JIP_LOGF("path starting at %" PRIx64 " couldn't be installed", m->path.start); } m->path.jb = 0; } void AbandonPath(struct Machine *m) { WriteCod("/\tABANDONED\n"); unassert(IsMakingPath(m)); JIP_LOGF("abandoning path jit_pc:%" PRIxPTR " which started at pc:%" PRIx64, GetJitPc(m->path.jb), m->path.start); AbandonJit(&m->system->jit, m->path.jb); m->path.skew = 0; m->path.jb = 0; } void FlushSkew(P) { unassert(IsMakingPath(m)); if (m->path.skew) { JIP_LOGF("adding %" PRId64 " to ip", m->path.skew); Jitter(A, "a1i" // arg1 = skew "q" // arg0 = machine "m", // arg0 = machine m->path.skew, AdvanceIp); m->path.skew = 0; } } void AddPath_StartOp(P) { #if LOG_CPU Jitter(A, "qmq", LogCpu); #endif BeginCod(m, GetPc(m)); #ifndef NDEBUG if (FLAG_statistics) { Jitter(A, "a0i" // arg0 = &instructions_jitted "m", // call micro-op (CountOp) &instructions_jitted, CountOp); } #endif if (AddPath_StartOp_Hook) { AddPath_StartOp_Hook(A); } #if LOG_JIX || defined(DEBUG) Jitter(A, "a1i" // arg1 = m->ip "q" // arg0 = machine "c", // call function (DebugOp) m->ip - m->path.skew, DebugOp); #endif #if LOG_JIX Jitter(A, "a1i" // arg1 = pc "q" // arg0 = machine "c", // call function (StartOp) m->ip, StartOp); #endif if (MustUpdateIp(A)) { if (!m->path.skew) { JIP_LOGF("adding %" PRId64 " to ip", Oplength(rde)); Jitter(A, "a1i" // arg1 = Oplength(rde) "q" // arg0 = machine "m", // call micro-op (AddIp) Oplength(rde), AddIp); } else { JIP_LOGF("adding %" PRId64 "+%" PRId64 " to ip", m->path.skew, Oplength(rde)); Jitter(A, "a2i" // arg1 = program counter delta "a1i" // arg1 = instruction length "q" // arg0 = machine "m", // call micro-op (SkewIp) m->path.skew + Oplength(rde), Oplength(rde), SkewIp); m->path.skew = 0; } } else { m->path.skew += Oplength(rde); } AppendJitMovReg(m->path.jb, kJitArg0, kJitSav0); m->reserving = false; } void AddPath_EndOp(P) { _Static_assert(offsetof(struct Machine, stashaddr) < 128, ""); if (m->reserving) { WriteCod("/\tflush reserve\n"); } #if !LOG_JIX && defined(__x86_64__) if (m->reserving) { AppendJitMovReg(m->path.jb, kJitArg0, kJitSav0); u8 sa = offsetof(struct Machine, stashaddr); u8 code[] = { // cmpq $0x0,0x18(%rdi) 0x48 | (kJitArg0 > 7 ? kAmdRexb : 0), 0x83, 0170 | (kJitArg0 & 7), sa, 0x00, // jz +5 0x74, 0x05, }; AppendJit(m->path.jb, code, sizeof(code)); AppendJitCall(m->path.jb, (void *)(uintptr_t)CommitStash); } #elif !LOG_JIX && defined(__aarch64__) if (m->reserving) { AppendJitMovReg(m->path.jb, kJitArg0, kJitSav0); u32 sa = offsetof(struct Machine, stashaddr); u32 code[] = { 0xf9400001 | (sa / 8) << 10, // ldr x1, [x0, #stashaddr] 0xb4000001 | 2 << 5, // cbz x1, +2 }; AppendJit(m->path.jb, code, sizeof(code)); AppendJitCall(m->path.jb, (void *)(uintptr_t)CommitStash); } #else Jitter(A, "a1i" // arg1 = pc "q" // arg0 = machine "c", // call function (EndOp) m->ip, EndOp); #endif FlushCod(m->path.jb); } bool AddPath(P) { unassert(IsMakingPath(m)); Jitter(A, "a3i" // arg2 = uimm0 "a2i" // arg2 = disp "a1i" // arg1 = rde "c", // call function uimm0, disp, rde, GetOp(Mopcode(rde))); return true; } #endif /* HAVE_JIT */ ================================================ FILE: blink/pipe.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/fds.h" #include "blink/log.h" #include "blink/ndelay.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/vfs.h" #include "blink/xlat.h" int SysPipe2(struct Machine *m, i64 pipefds_addr, i32 flags) { int rc; int lim; int fds[2]; int oflags; int supported; u8 fds_linux[2][4]; supported = O_CLOEXEC_LINUX | O_NDELAY_LINUX; if (flags & ~supported) { LOGF("%s() unsupported flags: %d", "pipe2", flags & ~supported); return einval(); } if (!IsValidMemory(m, pipefds_addr, sizeof(fds_linux), PROT_WRITE)) { return efault(); } if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); #ifdef HAVE_PIPE2 if ((rc = VfsPipe2(fds, (oflags = XlatOpenFlags(flags)))) != -1) { #else if (flags) LOCK(&m->system->exec_lock); if (VfsPipe(fds) != -1) { oflags = 0; if (flags & O_CLOEXEC_LINUX) { oflags |= O_CLOEXEC; unassert(!VfsFcntl(fds[0], F_SETFD, FD_CLOEXEC)); unassert(!VfsFcntl(fds[1], F_SETFD, FD_CLOEXEC)); } if (flags & O_NDELAY_LINUX) { oflags |= O_NDELAY; unassert(!VfsFcntl(fds[0], F_SETFL, O_NDELAY)); unassert(!VfsFcntl(fds[1], F_SETFL, O_NDELAY)); } #endif if (fds[0] >= lim || fds[1] >= lim) { close(fds[0]); close(fds[1]); rc = emfile(); } else { LOCK(&m->system->fds.lock); unassert(AddFd(&m->system->fds, fds[0], O_RDONLY | oflags)); unassert(AddFd(&m->system->fds, fds[1], O_WRONLY | oflags)); UNLOCK(&m->system->fds.lock); Write32(fds_linux[0], fds[0]); Write32(fds_linux[1], fds[1]); unassert(!CopyToUserWrite(m, pipefds_addr, fds_linux, sizeof(fds_linux))); rc = 0; } } else { rc = -1; } #ifndef HAVE_PIPE2 if (flags) UNLOCK(&m->system->exec_lock); #endif return rc; } ================================================ FILE: blink/pml4t.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/pml4t.h" #include #include "blink/bus.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/x86.h" static void AppendContiguousMemoryRange(struct ContiguousMemoryRanges *ranges, i64 a, i64 b) { ranges->p = (struct ContiguousMemoryRange *)realloc( ranges->p, ++ranges->i * sizeof(*ranges->p)); ranges->p[ranges->i - 1].a = a; ranges->p[ranges->i - 1].b = b; } static void FindContiguousMemoryRangesImpl( struct Machine *m, struct ContiguousMemoryRanges *ranges, i64 addr, unsigned level, u64 pt, i64 a, i64 b) { u64 entry; i64 i, page; for (i = a; i < b; ++i) { entry = Load64(GetPageAddress(m->system, pt, level == 39) + i * 8); if (!(entry & PAGE_V)) continue; page = (addr | i << level) << 16 >> 16; if (level == 12) { if (ranges->i && page == ranges->p[ranges->i - 1].b) { ranges->p[ranges->i - 1].b += 4096; } else { AppendContiguousMemoryRange(ranges, page, page + 4096); } } else { FindContiguousMemoryRangesImpl(m, ranges, page, level - 9, entry, 0, 512); } } } int FindContiguousMemoryRanges(struct Machine *m, struct ContiguousMemoryRanges *ranges) { u64 cr3; ranges->i = 0; if (m->mode.omode == XED_MODE_LONG) { cr3 = m->system->cr3; FindContiguousMemoryRangesImpl(m, ranges, 0, 39, cr3, 256, 512); FindContiguousMemoryRangesImpl(m, ranges, 0, 39, cr3, 0, 256); } else { AppendContiguousMemoryRange(ranges, 0, kRealSize); } return 0; } ================================================ FILE: blink/pml4t.h ================================================ #ifndef BLINK_PML4T_H_ #define BLINK_PML4T_H_ #include "blink/machine.h" struct ContiguousMemoryRange { i64 a; i64 b; }; struct ContiguousMemoryRanges { unsigned i, n; struct ContiguousMemoryRange *p; }; int FindContiguousMemoryRanges(struct Machine *, struct ContiguousMemoryRanges *); #endif /* BLINK_PML4T_H_ */ ================================================ FILE: blink/pml4tfmt.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include "blink/assert.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flag.h" #include "blink/high.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/pml4t.h" #include "blink/rde.h" #include "blink/thread.h" #include "blink/util.h" #include "blink/x86.h" #define INTERESTING_FLAGS (PAGE_U | PAGE_RW | PAGE_XD | PAGE_FILE) #define BYTES 16384 #define APPEND(...) \ u->o += snprintf(u->b + u->o, u->o > BYTES ? 0 : BYTES - u->o, __VA_ARGS__) struct MapMaker { bool t; int o; int count; int committed; long lines; char *b; i64 start; u64 flags; struct FileMap *fm; }; static bool IsStackRead(long mop) { switch (mop) { case 0x007: // OpPopSeg case 0x00F: // OpPopSeg case 0x017: // OpPopSeg case 0x01F: // OpPopSeg case 0x058: // OpPopZvq case 0x059: // OpPopZvq case 0x05A: // OpPopZvq case 0x05B: // OpPopZvq case 0x05C: // OpPopZvq case 0x05D: // OpPopZvq case 0x05E: // OpPopZvq case 0x05F: // OpPopZvq case 0x061: // OpPopa case 0x08F: // OpPopEvq case 0x09D: // OpPopf case 0x1A1: // OpPopSeg case 0x1A9: // OpPopSeg case 0x0C2: // OpRetIw case 0x0C3: // OpRet case 0x0CA: // OpRetf case 0x0CB: // OpRetf case 0x0C9: // OpLeave return true; default: return false; } } static bool IsStackWrite(long mop) { switch (mop) { case 0x006: // OpPushSeg case 0x00E: // OpPushSeg case 0x016: // OpPushSeg case 0x01E: // OpPushSeg case 0x050: // OpPushZvq case 0x051: // OpPushZvq case 0x052: // OpPushZvq case 0x053: // OpPushZvq case 0x054: // OpPushZvq case 0x055: // OpPushZvq case 0x056: // OpPushZvq case 0x057: // OpPushZvq case 0x060: // OpPusha case 0x068: // OpPushImm case 0x06A: // OpPushImm case 0x09C: // OpPushf case 0x1A0: // OpPushSeg case 0x1A8: // OpPushSeg case 0x0C9: // OpLeave case 0x09A: // OpCallf case 0x0E8: // OpCallJvds return true; default: return false; } } static i64 MakeAddress(u16 a[4]) { u64 x; x = 0; x |= a[0]; x <<= 9; x |= a[1]; x <<= 9; x |= a[2]; x <<= 9; x |= a[3]; x <<= 12; return x; } static void FormatStartPage(struct Machine *m, struct MapMaker *u, i64 start) { u->t = true; u->start = start; u->count = 0; u->committed = 0; u->fm = GetFileMap(m->system, start); } static void FormatEndPage(struct Machine *m, struct MapMaker *u, i64 end) { int i; char size[16]; bool isreading, iswriting, isexecuting, isfault; u->t = false; if (u->lines++) APPEND("\n"); isexecuting = m->xedd && MAX(u->start, m->ip) < MIN(m->ip + Oplength(m->xedd->op.rde), end); isreading = MAX(u->start, m->readaddr) < MIN(m->readaddr + m->readsize, end) || (m->xedd && IsStackRead(Mopcode(m->xedd->op.rde)) && MAX(u->start, Read64(m->sp)) < MIN(Read64(m->sp) - 8, end)); iswriting = MAX(u->start, m->writeaddr) < MIN(m->writeaddr + m->writesize, end) || (m->xedd && IsStackWrite(Mopcode(m->xedd->op.rde)) && MAX(u->start, Read64(m->sp)) < MIN(Read64(m->sp) + 8, end)); isfault = MAX(u->start, m->faultaddr) < MIN(m->faultaddr + 1, end); if (g_high.enabled) { if (isexecuting) APPEND("\033[7m"); if (isreading) APPEND("\033[1m"); if (iswriting) APPEND("\033[31m"); } APPEND("%012" PRIx64 "-%012" PRIx64, u->start, end - 1); if (g_high.enabled && (isreading || iswriting || isexecuting)) { APPEND("\033[0m"); } FormatSize(size, end - u->start, 1024); APPEND("%c%5s ", isfault ? '*' : ' ', size); if (FLAG_nolinear) { APPEND("%3d%% ", (int)ceil((double)u->committed / u->count * 100)); } i = 0; if (u->flags & PAGE_U) { APPEND("r"); ++i; } if (u->flags & PAGE_RW) { APPEND("w"); ++i; } if (~u->flags & PAGE_XD) { APPEND("x"); ++i; } while (i++ < 4) { APPEND(" "); } if (u->fm) { APPEND("%s", u->fm->path); } } static void FormatPdeOrPte(struct Machine *m, struct MapMaker *u, u64 entry, u16 a[4], int n) { i64 addr; addr = MakeAddress(a); if (u->t && u->flags != (entry & INTERESTING_FLAGS)) { FormatEndPage(m, u, addr); } if (!u->t) { FormatStartPage(m, u, addr); u->flags = entry & INTERESTING_FLAGS; } u->count += n; if (~entry & PAGE_RSRV) { u->committed += n; } } static u8 *GetPt(struct Machine *m, u64 entry, bool is_cr3) { return GetPageAddress(m->system, entry, is_cr3); } char *FormatPml4t(struct Machine *m) { _Thread_local static char b[BYTES]; if (m->metal) // TODO(jart): fix pml4t viz in metal mode return b; u8 *pd[4]; u64 entry; u16 i, a[4]; struct MapMaker u = {.b = b}; u16 range[][2] = {{256, 512}, {0, 256}}; b[0] = 0; if (m->mode.omode != XED_MODE_LONG) return b; unassert(m->system->cr3); pd[0] = GetPt(m, m->system->cr3, true); for (i = 0; i < ARRAYLEN(range); ++i) { a[0] = range[i][0]; do { a[1] = a[2] = a[3] = 0; entry = LoadPte(pd[0] + a[0] * 8); if (!(entry & PAGE_V)) { if (u.t) FormatEndPage(m, &u, MakeAddress(a)); } else if (entry & PAGE_PS) { FormatPdeOrPte(m, &u, entry, a, 1 << 27); } else { pd[1] = GetPt(m, entry, false); do { a[2] = a[3] = 0; entry = LoadPte(pd[1] + a[1] * 8); if (!(entry & PAGE_V)) { if (u.t) FormatEndPage(m, &u, MakeAddress(a)); } else if (entry & PAGE_PS) { FormatPdeOrPte(m, &u, entry, a, 1 << 18); } else { pd[2] = GetPt(m, entry, false); do { a[3] = 0; entry = LoadPte(pd[2] + a[2] * 8); if (!(entry & PAGE_V)) { if (u.t) FormatEndPage(m, &u, MakeAddress(a)); } else if (entry & PAGE_PS) { FormatPdeOrPte(m, &u, entry, a, 1 << 9); } else { pd[3] = GetPt(m, entry, false); do { entry = LoadPte(pd[3] + a[3] * 8); if (~entry & PAGE_V) { if (u.t) FormatEndPage(m, &u, MakeAddress(a)); } else { FormatPdeOrPte(m, &u, entry, a, 1); } } while (++a[3] != 512); } } while (++a[2] != 512); } } while (++a[1] != 512); } } while (++a[0] != range[i][1]); } if (u.t) { FormatEndPage(m, &u, 0x800000000000); } return b; } ================================================ FILE: blink/popcount.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bitscan.h" int(popcount)(u64 x) { x = x - ((x >> 1) & 0x5555555555555555); x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333); x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; x = (x + (x >> 32)) & 0xffffffff; x = x + (x >> 16); x = (x + (x >> 8)) & 0x7f; return x; } ================================================ FILE: blink/ppc.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/machine.h" // @asyncsignalsafe int FixPpcSignal(struct Machine *m, int sig, siginfo_t *si) { u64 pte; // let's help qemu-ppc64le pass readonly_test if (HasLinearMapping() && sig == SIGSEGV && si->si_code == SEGV_MAPERR) { ConvertHostToGuestAddress(m->system, si->si_addr, &pte); if ((pte & PAGE_V) && ((pte & (PAGE_U | PAGE_RW)) != (PAGE_U | PAGE_RW) || (pte & (PAGE_U | PAGE_RW | PAGE_XD)) == (PAGE_U | PAGE_RW))) { si->si_code = SEGV_ACCERR; } } return sig; } ================================================ FILE: blink/preadv.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/preadv.h" #include #include #include #include "blink/errno.h" #include "blink/iovs.h" #include "blink/limits.h" #include "blink/macros.h" // preadv() and pwritev() need MacOS 11+ c. 2020 ssize_t preadv_(int fd, const struct iovec *iov, int iovcnt, off_t offset) { int i; char *p; ssize_t rc; size_t j, n, m, t; if (offset < 0 || iovcnt <= 0 || iovcnt > GetIovMax()) { return einval(); } for (n = 0, i = 0; i < iovcnt; ++i) { t = n + iov[i].iov_len; if (t < n || n > NUMERIC_MAX(ssize_t)) { return einval(); } n = t; } if (!(p = (char *)malloc(n))) { return enomem(); } if ((rc = pread(fd, p, n, offset)) != -1) { for (j = 0, i = 0; i < iovcnt && j < rc; ++i, j += m) { m = MIN(iov[i].iov_len, rc - j); memcpy(iov[i].iov_base, p + j, m); } } free(p); return rc; } ssize_t pwritev_(int fd, const struct iovec *iov, int iovcnt, off_t offset) { int i; char *p; ssize_t rc; size_t j, n, m, t; if (offset < 0 || iovcnt <= 0 || iovcnt > GetIovMax()) { return einval(); } for (n = 0, i = 0; i < iovcnt; ++i) { t = n + iov[i].iov_len; if (t < n || n > NUMERIC_MAX(ssize_t)) { return einval(); } n = t; } if (!(p = (char *)malloc(n))) { return enomem(); } for (j = 0, i = 0; i < iovcnt && j < n; ++i, j += m) { m = MIN(iov[i].iov_len, n - j); memcpy(p + j, iov[i].iov_base, m); } rc = pwrite(fd, p, n, offset); free(p); return rc; } ================================================ FILE: blink/preadv.h ================================================ #ifndef BLINK_PREADV_H_ #define BLINK_PREADV_H_ #include #include #include "blink/builtin.h" ssize_t preadv_(int, const struct iovec *, int, off_t); ssize_t pwritev_(int, const struct iovec *, int, off_t); #ifndef HAVE_PREADV #ifdef preadv #undef preadv #endif #ifdef pwritev #undef pwritev #endif #define preadv preadv_ #define pwritev pwritev_ #endif #endif /* BLINK_PREADV_H_ */ ================================================ FILE: blink/procfs.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Trung Nguyen │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/procfs.h" #include #include #include #include "blink/atomic.h" #include "blink/errno.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/timespec.h" #include "blink/vfs.h" #ifdef __EMSCRIPTEN__ #include #endif #ifdef __CYGWIN__ #include #include #endif #if defined(__APPLE__) || defined(__NetBSD__) #define st_atim st_atimespec #define st_ctim st_ctimespec #define st_mtim st_mtimespec #endif #ifndef DISABLE_VFS #define PROCFS_NAME_MAX 16 #define PROCFS_READ_LEN 4096 #define PROCFS_DELETED " (deleted)" struct ProcfsInfo { u64 ino; u32 mode; u32 uid; u32 gid; u32 type; char name[PROCFS_NAME_MAX]; struct timespec time; union { _Atomic(struct ProcfsOpenFile *) openfile; _Atomic(struct ProcfsOpenDir *) opendir; }; union { int (*readdir)(struct VfsInfo *, struct dirent *); ssize_t (*readlink)(struct VfsInfo *, char **); int (*read)(struct VfsInfo *, struct ProcfsOpenFile *); }; }; struct ProcfsOpenFile { pthread_mutex_t_ lock; size_t index; off_t offset; int openflags; size_t readbufstart; size_t readbufend; char readbuf[PROCFS_READ_LEN]; }; struct ProcfsOpenDir { pthread_mutex_t_ lock; size_t index; }; struct ProcfsDevice { struct timespec mounttime; }; enum { PROCFS_NULL_INO, PROCFS_ROOT_INO, PROCFS_FILESYSTEMS_INO, PROCFS_MEMINFO_INO, PROCFS_MOUNTS_INO, PROCFS_SELF_INO, PROCFS_SYS_INO, PROCFS_UPTIME_INO, PROCFS_FIRST_PID_INO }; enum { PROCFS_ROOT_TYPE, PROCFS_MEMINFO_TYPE, PROCFS_FILESYSTEMS_TYPE, PROCFS_MOUNTS_TYPE, PROCFS_SELF_TYPE, PROCFS_SYS_TYPE, PROCFS_UPTIME_TYPE, PROCFS_PIDDIR_TYPE, PROCFS_PIDDIR_EXE_TYPE, PROCFS_PIDDIR_CWD_TYPE, PROCFS_PIDDIR_ROOT_TYPE, PROCFS_PIDDIR_MOUNTS_TYPE, PROCFS_PIDDIR_FDDIR_TYPE, PROCFS_PIDDIR_LAST_TYPE = PROCFS_PIDDIR_FDDIR_TYPE }; static int ProcfsRootReaddir(struct VfsInfo *, struct dirent *); static ssize_t ProcfsSelfReadlink(struct VfsInfo *, char **); static ssize_t ProcfsToSelfReadlink(struct VfsInfo *, char **); static int ProcfsMeminfoRead(struct VfsInfo *, struct ProcfsOpenFile *); static int ProcfsUptimeRead(struct VfsInfo *, struct ProcfsOpenFile *); static int ProcfsFilesystemsRead(struct VfsInfo *, struct ProcfsOpenFile *); static int ProcfsPiddirReaddir(struct VfsInfo *, struct dirent *); static ssize_t ProcfsPiddirExeReadlink(struct VfsInfo *, char **); static ssize_t ProcfsPiddirCwdReadlink(struct VfsInfo *, char **); static ssize_t ProcfsPiddirRootReadlink(struct VfsInfo *, char **); static int ProcfsPiddirMountsRead(struct VfsInfo *, struct ProcfsOpenFile *); static struct ProcfsInfo g_defaultinfos[] = { [PROCFS_ROOT_INO] = {PROCFS_ROOT_INO, S_IFDIR | 0555, 0, 0, PROCFS_ROOT_TYPE, "", .readdir = ProcfsRootReaddir}, [PROCFS_FILESYSTEMS_INO] = {PROCFS_FILESYSTEMS_INO, S_IFREG | 0444, 0, 0, PROCFS_FILESYSTEMS_TYPE, "filesystems", .read = ProcfsFilesystemsRead}, [PROCFS_MEMINFO_INO] = {PROCFS_MEMINFO_INO, S_IFREG | 0444, 0, 0, PROCFS_MEMINFO_TYPE, "meminfo", .read = ProcfsMeminfoRead}, [PROCFS_MOUNTS_INO] = {PROCFS_MOUNTS_INO, S_IFLNK | 0777, 0, 0, PROCFS_MOUNTS_TYPE, "mounts", .readlink = ProcfsToSelfReadlink}, [PROCFS_SELF_INO] = {PROCFS_SELF_INO, S_IFLNK | 0777, 0, 0, PROCFS_SELF_TYPE, "self", .readlink = ProcfsSelfReadlink}, [PROCFS_SYS_INO] = {PROCFS_SYS_INO, S_IFDIR | 0555, 0, 0, PROCFS_SYS_TYPE, "sys"}, [PROCFS_UPTIME_INO] = {PROCFS_UPTIME_INO, S_IFREG | 0444, 0, 0, PROCFS_UPTIME_TYPE, "uptime", .read = ProcfsUptimeRead}, }; static struct ProcfsInfo g_piddirinfos[] = { [PROCFS_PIDDIR_TYPE - PROCFS_PIDDIR_TYPE] = {0, S_IFDIR | 0555, 0, 0, PROCFS_PIDDIR_TYPE, "", .readdir = ProcfsPiddirReaddir}, [PROCFS_PIDDIR_EXE_TYPE - PROCFS_PIDDIR_TYPE] = {0, S_IFLNK | 0777, 0, 0, PROCFS_PIDDIR_EXE_TYPE, "exe", .readlink = ProcfsPiddirExeReadlink}, [PROCFS_PIDDIR_CWD_TYPE - PROCFS_PIDDIR_TYPE] = {0, S_IFLNK | 0777, 0, 0, PROCFS_PIDDIR_CWD_TYPE, "cwd", .readlink = ProcfsPiddirCwdReadlink}, [PROCFS_PIDDIR_ROOT_TYPE - PROCFS_PIDDIR_TYPE] = {0, S_IFLNK | 0777, 0, 0, PROCFS_PIDDIR_ROOT_TYPE, "root", .readlink = ProcfsPiddirRootReadlink}, [PROCFS_PIDDIR_MOUNTS_TYPE - PROCFS_PIDDIR_TYPE] = {0, S_IFREG | 0444, 0, 0, PROCFS_PIDDIR_MOUNTS_TYPE, "mounts", .read = ProcfsPiddirMountsRead}, [PROCFS_PIDDIR_FDDIR_TYPE - PROCFS_PIDDIR_TYPE] = {0, S_IFDIR | 0555, 0, 0, PROCFS_PIDDIR_FDDIR_TYPE, "fd"}, }; //////////////////////////////////////////////////////////////////////////////// static int ProcfsCreateInfo(struct ProcfsInfo **info) { *info = malloc(sizeof(struct ProcfsInfo)); if (*info == NULL) { return enomem(); } (*info)->ino = 0; (*info)->mode = 0; (*info)->type = 0; (*info)->name[0] = '\0'; (*info)->openfile = NULL; return 0; } static int ProcfsCreateDefaultInfo(struct ProcfsInfo **info, struct ProcfsDevice *device, u64 ino) { *info = malloc(sizeof(struct ProcfsInfo)); if (*info == NULL) { return enomem(); } **info = g_defaultinfos[ino]; (*info)->time = device->mounttime; return 0; } static int ProcfsCreatePiddirInfo(struct ProcfsInfo **info, struct ProcfsInfo *parent, i32 pid, u32 type) { *info = malloc(sizeof(struct ProcfsInfo)); if (*info == NULL) { return enomem(); } if (parent == NULL) { **info = g_piddirinfos[0]; // TODO(trungnt): This should be dynamically allocated when we support // more processes. (*info)->ino = PROCFS_FIRST_PID_INO; sprintf((*info)->name, "%d", pid); // TODO(trungnt): On Linux, the UID and GID of these files // are set to the ones of the user who created the process. (*info)->uid = getuid(); (*info)->gid = getgid(); (*info)->time = GetTime(); } else { **info = g_piddirinfos[type - PROCFS_PIDDIR_TYPE]; (*info)->ino = parent->ino + (type - PROCFS_PIDDIR_TYPE); (*info)->uid = parent->uid; (*info)->gid = parent->gid; (*info)->time = GetTime(); } return 0; } static int ProcfsFreeInfo(void *info) { if (info == NULL) { return 0; } struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info; if (S_ISDIR(procinfo->mode)) { free(procinfo->opendir); } else if (S_ISREG(procinfo->mode)) { free(procinfo->openfile); } free(info); return 0; } static int ProcfsFreeDevice(void *device) { free(device); return 0; } //////////////////////////////////////////////////////////////////////////////// static int ProcfsInit(const char *source, u64 flags, const void *data, struct VfsDevice **device, struct VfsMount **mount) { struct ProcfsDevice *procdevice = NULL; struct ProcfsInfo *procinfo = NULL; procdevice = malloc(sizeof(struct ProcfsDevice)); if (procdevice == NULL) { return enomem(); } procdevice->mounttime = GetTime(); *device = NULL; if (VfsCreateDevice(device) == -1) { goto cleananddie; } (*device)->data = procdevice; (*device)->ops = &g_procfs.ops; *mount = malloc(sizeof(struct VfsMount)); if (*mount == NULL) { goto cleananddie; } if (ProcfsCreateDefaultInfo(&procinfo, procdevice, PROCFS_ROOT_INO) == -1) { goto cleananddie; } if (VfsCreateInfo(&(*mount)->root) == -1) { goto cleananddie; } unassert(!VfsAcquireDevice(*device, &(*mount)->root->device)); (*mount)->root->data = procinfo; (*mount)->root->mode = S_IFDIR; (*mount)->root->ino = 1; // Weak reference. (*device)->root = (*mount)->root; VFS_LOGF("Mounted a procfs device"); return 0; cleananddie: if (*device) { unassert(!VfsFreeDevice(*device)); } else { free(procdevice); } if (*mount) { if ((*mount)->root) { unassert(!VfsFreeInfo((*mount)->root)); } else { unassert(!ProcfsFreeInfo(procinfo)); } free(*mount); } return -1; } //////////////////////////////////////////////////////////////////////////////// static int ProcfsReadmountentry(struct VfsDevice *device, char **spec, char **type, char **mntops) { *spec = strdup("proc"); if (*spec == NULL) { return enomem(); } *type = strdup("proc"); if (*type == NULL) { free(*spec); return enomem(); } *mntops = NULL; return 0; } //////////////////////////////////////////////////////////////////////////////// static int ProcfsFinddir(struct VfsInfo *parent, const char *name, struct VfsInfo **output) { struct ProcfsInfo *procparent = (struct ProcfsInfo *)parent->data; struct ProcfsInfo *procoutput = NULL; int i, pid; VFS_LOGF("ProcfsFinddir(parent=%p (%s), name=\"%s\", output=%p)", parent, parent->name, name, output); if (strcmp(name, ".") == 0) { unassert(!VfsAcquireInfo(parent, output)); return 0; } *output = NULL; switch (procparent->type) { case PROCFS_ROOT_TYPE: for (i = PROCFS_ROOT_INO + 1; i < PROCFS_FIRST_PID_INO; ++i) { if (!strcmp(name, g_defaultinfos[i].name)) { if (ProcfsCreateDefaultInfo( &procoutput, (struct ProcfsDevice *)parent->device->data, i) == -1) { goto cleananddie; } break; } } if (procoutput == NULL) { pid = -1; sscanf(name, "%d", &pid); if (pid == getpid()) { if (ProcfsCreatePiddirInfo(&procoutput, NULL, pid, PROCFS_PIDDIR_ROOT_TYPE) == -1) { goto cleananddie; } } } // TODO(trungnt): PID-specific directories of other processes. break; case PROCFS_PIDDIR_TYPE: for (i = 1; i <= PROCFS_PIDDIR_LAST_TYPE - PROCFS_PIDDIR_TYPE; ++i) { if (!strcmp(name, g_piddirinfos[i].name)) { if (ProcfsCreatePiddirInfo(&procoutput, procparent, -1, i + PROCFS_PIDDIR_TYPE) == -1) { goto cleananddie; } break; } } break; } if (procoutput == NULL) { enoent(); goto cleananddie; } if (VfsCreateInfo(output) == -1) { goto cleananddie; } (*output)->data = procoutput; (*output)->ino = procoutput->ino; (*output)->mode = procoutput->mode; unassert(!VfsAcquireDevice(parent->device, &(*output)->device)); unassert(!VfsAcquireInfo(parent, &(*output)->parent)); (*output)->name = strdup(procoutput->name); if ((*output)->name == NULL) { goto cleananddie; } (*output)->namelen = strlen((*output)->name); return 0; cleananddie: if (*output) { unassert(!VfsFreeInfo(*output)); } else { unassert(!ProcfsFreeInfo(procoutput)); } return -1; } //////////////////////////////////////////////////////////////////////////////// static ssize_t ProcfsReadlink(struct VfsInfo *info, char **output) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; VFS_LOGF("ProcfsReadlink(info=%p (%s), output=%p)", info, info->name, output); if (!S_ISLNK(procinfo->mode)) { return einval(); } if (!procinfo->readlink) { return eperm(); } return procinfo->readlink(info, output); } //////////////////////////////////////////////////////////////////////////////// static int ProcfsAccessImpl(struct ProcfsInfo *procinfo, mode_t mode) { uid_t uid; gid_t gid; int ret = 0; if (procinfo->ino < PROCFS_FIRST_PID_INO) { // Get fresher info as some files might have been chmod/chown'ed. procinfo = &g_defaultinfos[procinfo->ino]; } if (mode != F_OK) { uid = getuid(); // This implementation is incomplete as a user can be in multiple groups. gid = getgid(); if (mode & R_OK) { if (uid == 0) { if (!(procinfo->mode & (S_IRUSR | S_IRGRP | S_IROTH))) { ret = eacces(); } } else if (uid == procinfo->uid) { if (!(procinfo->mode & S_IRUSR)) { ret = eacces(); } } else if (gid == procinfo->gid) { if (!(procinfo->mode & S_IRGRP)) { ret = eacces(); } } else if (!(procinfo->mode & S_IROTH)) { ret = eacces(); } } if (mode & W_OK) { if (uid == 0) { if (!(procinfo->mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { ret = eacces(); } } else if (uid == procinfo->uid) { if (!(procinfo->mode & S_IWUSR)) { ret = eacces(); } } else if (gid == procinfo->gid) { if (!(procinfo->mode & S_IWGRP)) { ret = eacces(); } } else if (!(procinfo->mode & S_IWOTH)) { ret = eacces(); } } if (mode & X_OK) { if (uid == 0) { if (!(procinfo->mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { ret = eacces(); } } else if (uid == procinfo->uid) { if (!(procinfo->mode & S_IXUSR)) { ret = eacces(); } } else if (gid == procinfo->gid) { if (!(procinfo->mode & S_IXGRP)) { ret = eacces(); } } else if (!(procinfo->mode & S_IXOTH)) { ret = eacces(); } } } return ret; } static int ProcfsAccess(struct VfsInfo *parent, const char *name, mode_t mode, int flags) { struct VfsInfo *info = NULL; struct ProcfsInfo *procinfo; int ret = 0; if (ProcfsFinddir(parent, name, &info) == -1) { return -1; } procinfo = (struct ProcfsInfo *)info->data; ret = ProcfsAccessImpl(procinfo, mode); unassert(!VfsFreeInfo(info)); return ret; } //////////////////////////////////////////////////////////////////////////////// static int ProcfsOpen(struct VfsInfo *parent, const char *name, int flags, int mode, struct VfsInfo **output) { struct ProcfsInfo *procoutput = NULL; if (ProcfsFinddir(parent, name, output) == -1) { return -1; } procoutput = (struct ProcfsInfo *)(*output)->data; if (S_ISDIR(procoutput->mode)) { procoutput->opendir = malloc(sizeof(struct ProcfsOpenDir)); if (procoutput->opendir == NULL) { enomem(); goto cleananddie; } procoutput->opendir->index = 0; unassert(!pthread_mutex_init(&procoutput->opendir->lock, NULL)); } else if (S_ISREG(procoutput->mode)) { if (flags & O_RDWR || flags & O_RDONLY) { if (ProcfsAccessImpl(procoutput, R_OK) == -1) { goto cleananddie; } } if (flags & O_RDWR || flags & O_WRONLY) { if (ProcfsAccessImpl(procoutput, W_OK) == -1) { goto cleananddie; } } procoutput->openfile = malloc(sizeof(struct ProcfsOpenFile)); if (procoutput->openfile == NULL) { enomem(); goto cleananddie; } procoutput->openfile->offset = 0; procoutput->openfile->index = 0; procoutput->openfile->openflags = flags; procoutput->openfile->readbufstart = procoutput->openfile->readbufend = 0; unassert(!pthread_mutex_init(&procoutput->openfile->lock, NULL)); } else { einval(); goto cleananddie; } return 0; cleananddie: if (procoutput) { if (S_ISDIR(procoutput->mode)) { free(procoutput->opendir); procoutput->opendir = NULL; } else if (S_ISREG(procoutput->mode)) { free(procoutput->openfile); procoutput->openfile = NULL; } } unassert(!VfsFreeInfo(*output)); return -1; } static int ProcfsClose(struct VfsInfo *info) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; void *opendata; if (S_ISDIR(procinfo->mode)) { opendata = atomic_exchange(&procinfo->opendir, NULL); } else if (S_ISREG(procinfo->mode)) { opendata = atomic_exchange(&procinfo->openfile, NULL); } else { return 0; } LOCK((pthread_mutex_t_ *)opendata); UNLOCK((pthread_mutex_t_ *)opendata); unassert(!pthread_mutex_destroy((pthread_mutex_t_ *)opendata)); free(opendata); return 0; } //////////////////////////////////////////////////////////////////////////////// static int ProcfsStatImpl(struct VfsDevice *device, struct ProcfsInfo *info, struct stat *st) { st->st_dev = device->dev; st->st_ino = info->ino; st->st_mode = info->mode; st->st_nlink = 1; if (info->ino < PROCFS_FIRST_PID_INO) { st->st_uid = g_defaultinfos[info->type].uid; st->st_gid = g_defaultinfos[info->type].gid; } else { st->st_uid = info->uid; st->st_gid = info->gid; } st->st_uid = info->uid; st->st_gid = info->gid; st->st_rdev = 0; st->st_size = 0; st->st_blksize = PROCFS_READ_LEN; st->st_blocks = 0; st->st_atim = st->st_mtim = st->st_ctim = info->time; return 0; } static int ProcfsStat(struct VfsInfo *parent, const char *name, struct stat *st, int flags) { struct VfsInfo *info; int ret; if (ProcfsFinddir(parent, name, &info) == -1) { return -1; } ret = ProcfsStatImpl(parent->device, (struct ProcfsInfo *)info->data, st); unassert(!VfsFreeInfo(info)); return ret; } static int ProcfsFstat(struct VfsInfo *parent, struct stat *st) { return ProcfsStatImpl(parent->device, (struct ProcfsInfo *)parent->data, st); } //////////////////////////////////////////////////////////////////////////////// // On Linux, it is actually possible to chmod/chown some files in procfs. // It is NOT possible to do so for files in pid-specific directories. // We try to emulate it here, but this emulation suffers from the same // limitations as the mount tables at the time of writing: It does not // propagate to sibling and parent processes. static int ProcfsFchmod(struct VfsInfo *info, mode_t mode) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; if (procinfo->ino >= PROCFS_FIRST_PID_INO) { return eperm(); } else { procinfo->mode = (procinfo->mode & ~07777) | (mode & 07777); g_defaultinfos[procinfo->type].mode = procinfo->mode; return 0; } } static int ProcfsChmod(struct VfsInfo *parent, const char *name, mode_t mode, int flags) { struct VfsInfo *info; int ret; // When we reach here all necessary symlink dereferences have already been // conducted. if (ProcfsFinddir(parent, name, &info) == -1) { return -1; } ret = ProcfsFchmod(info, mode); unassert(!VfsFreeInfo(info)); return ret; } static int ProcfsFchown(struct VfsInfo *info, uid_t uid, gid_t gid) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; if (procinfo->ino >= PROCFS_FIRST_PID_INO) { return eperm(); } else { if (uid != -1) { procinfo->uid = uid; g_defaultinfos[procinfo->type].uid = uid; } if (gid != -1) { procinfo->gid = gid; g_defaultinfos[procinfo->type].gid = gid; } return 0; } } static int ProcfsChown(struct VfsInfo *parent, const char *name, uid_t uid, gid_t gid, int flags) { struct VfsInfo *info; int ret; if (ProcfsFinddir(parent, name, &info) == -1) { return -1; } ret = ProcfsFchown(info, uid, gid); unassert(!VfsFreeInfo(info)); return ret; } //////////////////////////////////////////////////////////////////////////////// static ssize_t ProcfsReadImpl(struct VfsInfo *info, void *buf, size_t len, off_t off, bool copy) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; struct ProcfsOpenFile tmpopenfile = *(procinfo->openfile); ssize_t ret = 0; size_t bytestoread = 0; if (off != -1) { tmpopenfile.readbufstart = tmpopenfile.readbufend = 0; tmpopenfile.index = 0; tmpopenfile.offset = 0; } while ((off > 0 || len > 0) && tmpopenfile.readbufend <= sizeof(tmpopenfile.readbuf)) { // All bytes from the buffer has been consumed. if (tmpopenfile.readbufstart == tmpopenfile.readbufend) { if (!procinfo->read) { ret = eperm(); break; } if (procinfo->read(info, &tmpopenfile) == -1) { ret = -1; break; } } if (off > 0) { bytestoread = MIN(off, tmpopenfile.readbufend - tmpopenfile.readbufstart); tmpopenfile.readbufstart += bytestoread; tmpopenfile.offset += bytestoread; off -= bytestoread; } else { bytestoread = MIN(len, tmpopenfile.readbufend - tmpopenfile.readbufstart); memcpy(buf, tmpopenfile.readbuf + tmpopenfile.readbufstart, bytestoread); tmpopenfile.readbufstart += bytestoread; tmpopenfile.offset += bytestoread; buf = (void *)((char *)buf + bytestoread); len -= bytestoread; ret += bytestoread; } } if (copy || (off == -1 && ret != -1)) { *(procinfo->openfile) = tmpopenfile; } return ret; } static ssize_t ProcfsPreadv(struct VfsInfo *info, const struct iovec *iov, int iovcnt, off_t off) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; size_t len = 0; ssize_t ret; if (!S_ISREG(procinfo->mode) || procinfo->openfile == NULL) { return einval(); } if (off < 0) return einval(); LOCK(&procinfo->openfile->lock); for (int i = 0; i < iovcnt; ++i) { len += iov[i].iov_len; if (len > SSIZE_MAX) return einval(); } len = 0; for (int i = 0; i < iovcnt; ++i) { ret = ProcfsReadImpl(info, iov[i].iov_base, iov[i].iov_len, off, false); if (ret == -1) { if (len == 0) len = -1; break; } len += ret; off += ret; procinfo->openfile->offset += ret; if (ret < iov[i].iov_len) { break; } } UNLOCK(&procinfo->openfile->lock); return len; } static ssize_t ProcfsReadv(struct VfsInfo *info, const struct iovec *iov, int iovcnt) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; size_t len = 0; ssize_t ret; if (!S_ISREG(procinfo->mode) || procinfo->openfile == NULL) { return einval(); } LOCK(&procinfo->openfile->lock); for (int i = 0; i < iovcnt; ++i) { len += iov[i].iov_len; if (len > SSIZE_MAX) return einval(); } len = 0; for (int i = 0; i < iovcnt; ++i) { ret = ProcfsReadImpl(info, iov[i].iov_base, iov[i].iov_len, -1, false); if (ret == -1) { if (len == 0) len = -1; break; } len += ret; if (ret < iov[i].iov_len) { break; } } UNLOCK(&procinfo->openfile->lock); return len; } static ssize_t ProcfsPread(struct VfsInfo *info, void *buf, size_t len, off_t off) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; ssize_t ret; if (!S_ISREG(procinfo->mode) || procinfo->openfile == NULL) { return einval(); } if (off < 0) return einval(); LOCK(&procinfo->openfile->lock); ret = ProcfsReadImpl(info, buf, len, off, false); UNLOCK(&procinfo->openfile->lock); return ret; } static ssize_t ProcfsRead(struct VfsInfo *info, void *buf, size_t len) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; ssize_t ret; if (!S_ISREG(procinfo->mode) || procinfo->openfile == NULL) { return einval(); } LOCK(&procinfo->openfile->lock); ret = ProcfsReadImpl(info, buf, len, -1, false); UNLOCK(&procinfo->openfile->lock); return ret; } static ssize_t ProcfsWrite(struct VfsInfo *, const void *, size_t); static ssize_t ProcfsPwrite(struct VfsInfo *, const void *, size_t, off_t); static ssize_t ProcfsWritev(struct VfsInfo *, const struct iovec *, int); static ssize_t ProcfsPwritev(struct VfsInfo *, const struct iovec *, int, off_t); //////////////////////////////////////////////////////////////////////////////// static off_t ProcfsSeekImpl(struct VfsInfo *info, off_t off, int whence) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; off_t newoff = 0; if (S_ISDIR(procinfo->mode)) { if (procinfo->opendir == NULL) { return einval(); } switch (whence) { case SEEK_SET: if (off < 0) return einval(); procinfo->opendir->index = off; break; case SEEK_CUR: if (off < 0 && -off > procinfo->opendir->index) return einval(); procinfo->opendir->index += off; break; case SEEK_END: return einval(); } return procinfo->opendir->index; } else if (S_ISREG(procinfo->mode)) { if (procinfo->openfile == NULL) { return einval(); } switch (whence) { case SEEK_SET: newoff = off; break; case SEEK_CUR: newoff = procinfo->openfile->offset + off; break; case SEEK_END: return einval(); } if (newoff < 0) { return einval(); } if (procinfo->openfile->readbufend <= sizeof(procinfo->openfile->readbuf) && procinfo->openfile->offset / PROCFS_READ_LEN == newoff / PROCFS_READ_LEN) { // We're still in the cached region. procinfo->openfile->readbufstart += newoff - procinfo->openfile->offset; procinfo->openfile->offset = newoff; } else { if ((procinfo->openfile->offset / PROCFS_READ_LEN > newoff / PROCFS_READ_LEN) || (procinfo->openfile->readbufend > sizeof(procinfo->openfile->readbuf))) { // Reset the file if it has already ended or we're going back before the // buffer. procinfo->openfile->index = 0; procinfo->openfile->offset = 0; procinfo->openfile->readbufstart = procinfo->openfile->readbufend = 0; } ProcfsReadImpl(info, NULL, 0, newoff - procinfo->openfile->offset, true); procinfo->openfile->offset = newoff; } return procinfo->openfile->offset; } else { return einval(); } return einval(); } static off_t ProcfsSeek(struct VfsInfo *info, off_t off, int whence) { off_t ret; struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; LOCK(&procinfo->openfile->lock); ret = ProcfsSeekImpl(info, off, whence); UNLOCK(&procinfo->openfile->lock); return ret; } //////////////////////////////////////////////////////////////////////////////// static int ProcfsDup(struct VfsInfo *info, struct VfsInfo **newinfo) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data, *newprocinfo; u32 openflags = 0; *newinfo = NULL; if (S_ISREG(info->mode)) { openflags = procinfo->openfile->openflags & ~(O_CREAT | O_EXCL | O_TRUNC); } else if (S_ISDIR(info->mode)) { openflags = O_DIRECTORY; } else { return einval(); } if (ProcfsOpen(info->parent, info->name, openflags, 0, newinfo) == -1) { return -1; } newprocinfo = (struct ProcfsInfo *)(*newinfo)->data; if (S_ISDIR(info->mode)) { memcpy(newprocinfo->opendir, procinfo->opendir, sizeof(*newprocinfo->opendir)); } else if (S_ISREG(info->mode)) { memcpy(newprocinfo->openfile, procinfo->openfile, sizeof(*newprocinfo->openfile)); } unassert(!pthread_mutex_init((pthread_mutex_t *)newprocinfo->openfile, NULL)); return 0; } #ifdef HAVE_DUP3 static int ProcfsDup3(struct VfsInfo *info, struct VfsInfo **newinfo, int wut) { // O_CLOEXEC is already handled by the syscall layer. return ProcfsDup(info, newinfo); } #endif //////////////////////////////////////////////////////////////////////////////// static int ProcfsOpendir(struct VfsInfo *info, struct VfsInfo **output) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; if (!S_ISDIR(procinfo->mode) && !procinfo->opendir) { return einval(); } unassert(!VfsAcquireInfo(info, output)); return 0; } static void ProcfsSeekdir(struct VfsInfo *info, long offset) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; if (!S_ISDIR(procinfo->mode) && !procinfo->opendir) { einval(); return; } procinfo->opendir->index = offset; } #ifdef HAVE_SEEKDIR static long ProcfsTelldir(struct VfsInfo *info) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; if (!S_ISDIR(procinfo->mode) && !procinfo->opendir) { return einval(); } return procinfo->opendir->index; } #endif static struct dirent *ProcfsReaddir(struct VfsInfo *info) { static _Thread_local char buf[sizeof(struct dirent) + VFS_NAME_MAX]; struct dirent *de = (struct dirent *)buf; struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; if (!S_ISDIR(procinfo->mode) && !procinfo->opendir) { einval(); return NULL; } if (procinfo->readdir) { if (procinfo->readdir(info, de) == -1) { return NULL; } return de; } return NULL; } static void ProcfsRewinddir(struct VfsInfo *info) { ProcfsSeekdir(info, 0); } static int ProcfsClosedir(struct VfsInfo *info) { unassert(!VfsFreeInfo(info)); return ProcfsClose(info); } //////////////////////////////////////////////////////////////////////////////// static int ProcfsUtime(struct VfsInfo *info, const char *name, const struct timespec times[2], int flags) { return einval(); } static int ProcfsFutime(struct VfsInfo *info, const struct timespec times[2]) { return einval(); } //////////////////////////////////////////////////////////////////////////////// struct VfsInfo *g_selfexeinfo = NULL; int ProcfsRegisterExe(i32 pid, const char *path) { struct VfsInfo *newinfo, *tmp; unassert(pid == getpid()); unassert(!VfsTraverse(path, &newinfo, true)); tmp = g_selfexeinfo; g_selfexeinfo = newinfo; unassert(!VfsFreeInfo(tmp)); return 0; } //////////////////////////////////////////////////////////////////////////////// static int ProcfsInfoToDirent(struct ProcfsInfo *info, struct dirent *de) { de->d_ino = info->ino; #ifdef DT_UNKNOWN if (S_ISDIR(info->mode)) { de->d_type = DT_DIR; } else if (S_ISREG(info->mode)) { de->d_type = DT_REG; } else if (S_ISLNK(info->mode)) { de->d_type = DT_LNK; } else { de->d_type = DT_UNKNOWN; } #endif strcpy(de->d_name, info->name); return 0; } static int ProcfsRootReaddir(struct VfsInfo *info, struct dirent *de) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; struct ProcfsOpenDir *dir = procinfo->opendir; int ret = 0; LOCK(&dir->lock); // The index value reserves two numbers for .. and . // The PROCFS_*_INO on the other hand uses the first two numbers // for the NULL node and the ROOT node. if (dir->index == 0) { de->d_ino = info->parent->ino; #ifdef DT_DIR de->d_type = DT_DIR; #endif strcpy(de->d_name, ".."); ret = 0; } else if (dir->index == 1) { de->d_ino = info->ino; #ifdef DT_DIR de->d_type = DT_DIR; #endif strcpy(de->d_name, "."); ret = 0; } else if (dir->index >= PROCFS_FIRST_PID_INO) { if (dir->index == PROCFS_FIRST_PID_INO) { // In the limited version, there's only one PID visible here. // For the complete implementation, we have to query the PID table. de->d_ino = PROCFS_FIRST_PID_INO; #ifdef DT_DIR de->d_type = DT_DIR; #endif sprintf(de->d_name, "%d", getpid()); } else { // TODO(trungnt): PID-specific directories for other processes ret = enoent(); } } else { if (ProcfsInfoToDirent(&g_defaultinfos[dir->index], de) == -1) { ret = -1; } ret = 0; } ++dir->index; UNLOCK(&dir->lock); return ret; } static int ProcfsPiddirReaddir(struct VfsInfo *info, struct dirent *de) { struct ProcfsInfo *procinfo = (struct ProcfsInfo *)info->data; struct ProcfsOpenDir *dir = procinfo->opendir; int ret = 0; LOCK(&dir->lock); if (dir->index == 0) { de->d_ino = info->parent->ino; #ifdef DT_DIR de->d_type = DT_DIR; #endif strcpy(de->d_name, ".."); ret = 0; } else if (dir->index == 1) { de->d_ino = info->ino; #ifdef DT_DIR de->d_type = DT_DIR; #endif strcpy(de->d_name, "."); ret = 0; } else if ((dir->index - 1) > (PROCFS_PIDDIR_LAST_TYPE - PROCFS_PIDDIR_TYPE)) { ret = enoent(); } else { if (ProcfsInfoToDirent(&g_piddirinfos[dir->index - 1], de) == -1) { ret = -1; } ret = 0; } ++dir->index; UNLOCK(&dir->lock); return ret; } //////////////////////////////////////////////////////////////////////////////// static ssize_t ProcfsSelfReadlink(struct VfsInfo *info, char **buf) { *buf = malloc(16); if (!*buf) { return enomem(); } snprintf(*buf, 16, "%d", getpid()); return strlen(*buf); } static ssize_t ProcfsToSelfReadlink(struct VfsInfo *info, char **buf) { size_t len = strlen(info->name) + sizeof("self/"); *buf = malloc(len); if (!*buf) { return enomem(); } strcpy(*buf, "self/"); strcpy(*buf + sizeof("self/") - 1, info->name); return len - 1; } static ssize_t ProcfsPiddirExeReadlink(struct VfsInfo *info, char **buf) { ssize_t len; char *tmp; struct stat st; VFS_LOGF("ProcfsPiddirExeReadlink(%p (%s), %p)", info, info->name, buf); if ((len = VfsPathBuildFull(g_selfexeinfo, NULL, buf)) == -1) { return -1; } if (VfsStat(AT_FDCWD, *buf, &st, 0) == -1) { len += sizeof(PROCFS_DELETED) - 1; tmp = realloc(*buf, len + 1); if (!tmp) { free(*buf); return enomem(); } *buf = tmp; memcpy(*buf + len, PROCFS_DELETED, sizeof(PROCFS_DELETED)); } return len; } static ssize_t ProcfsPiddirCwdReadlink(struct VfsInfo *info, char **buf) { return VfsPathBuildFull(g_cwdinfo, NULL, buf); } static ssize_t ProcfsPiddirRootReadlink(struct VfsInfo *info, char **buf) { return VfsPathBuildFull(g_rootinfo, g_actualrootinfo, buf); } //////////////////////////////////////////////////////////////////////////////// static int ProcfsMeminfoRead(struct VfsInfo *info, struct ProcfsOpenFile *openfile) { #ifdef __linux__ int fd = open("/proc/meminfo", O_RDONLY); ssize_t bytesread; int ret = 0; if (fd == -1) { return -1; } if ((bytesread = pread(fd, openfile->readbuf, sizeof(openfile->readbuf), openfile->index)) == -1) { ret = -1; } close(fd); if (ret != -1) { if (bytesread != 0) { openfile->index += bytesread; openfile->readbufstart = 0; openfile->readbufend = bytesread; } else { openfile->readbufstart = sizeof(openfile->readbuf) + 1; openfile->readbufend = sizeof(openfile->readbuf) + 1; } } return ret; #else u64 memtotal = 0, memfree = 0; if (openfile->index > 0) { openfile->readbufstart = sizeof(openfile->readbuf) + 1; openfile->readbufend = sizeof(openfile->readbuf) + 1; return 0; } #if defined(__CYGWIN__) MEMORYSTATUSEX memstat; memstat.dwLength = sizeof(memstat); if (!GlobalMemoryStatusEx(&memstat)) { return -1; } memtotal = memstat.ullTotalPhys; memfree = memstat.ullAvailPhys; #elif defined(__EMSCRIPTEN__) // WASM is 32-bit so on a RAM-efficient browser running on a // device with a lot of RAM, we can reach the 4GB limit. memtotal = 4 * 1024 * 1024; memfree = memtotal - EM_ASM_INT(return HEAP8.length); #endif openfile->readbufstart = 0; openfile->readbufend = snprintf(openfile->readbuf, sizeof(openfile->readbuf), "MemTotal: %llu kB\nMemFree: %llu kB\n", (unsigned long long)(memtotal / 1024), (unsigned long long)(memfree / 1024)); openfile->index = 1; return 0; #endif } static int ProcfsUptimeRead(struct VfsInfo *info, struct ProcfsOpenFile *openfile) { double uptime = 0, idletime = 0; int ret = 0; if (openfile->index > 0) { openfile->readbufstart = sizeof(openfile->readbuf) + 1; openfile->readbufend = sizeof(openfile->readbuf) + 1; return 0; } #ifdef __linux__ FILE *fp = fopen("/proc/uptime", "r"); if (!fp) { return -1; } if (!fp) { return -1; } if (fscanf(fp, "%lf %lf", &uptime, &idletime) != 2) { ret = -1; } fclose(fp); #elif defined(__CYGWIN__) SYSTEM_PERFORMANCE_INFORMATION spi; SYSTEM_TIMEOFDAY_INFORMATION sti; if (!NT_SUCCESS(NtQuerySystemInformation(SystemPerformanceInformation, &spi, sizeof(spi), NULL))) { ret = -1; } else if (!NT_SUCCESS(NtQuerySystemInformation(SystemTimeOfDayInformation, &sti, sizeof(sti), NULL))) { ret = -1; } else { uptime = (sti.CurrentTime.QuadPart - sti.BootTime.QuadPart) / 10000000.0; idletime = spi.IdleTime.QuadPart / 10000000.0; } #elif defined(__EMSCRIPTEN__) uptime = EM_ASM_DOUBLE(return performance.now() / 1000); #endif if (ret != -1) { openfile->readbufstart = 0; openfile->readbufend = snprintf(openfile->readbuf, sizeof(openfile->readbuf), "%lf %lf\n", uptime, idletime); openfile->index = 1; } return ret; } static int ProcfsFilesystemsRead(struct VfsInfo *info, struct ProcfsOpenFile *openfile) { size_t byteswritten = 0; size_t bytesleft = sizeof(openfile->readbuf); size_t ret; struct Dll *e = NULL; int i; if (openfile->readbufend > sizeof(openfile->readbuf)) { return 0; } LOCK(&g_vfs.lock); for (i = 0, e = dll_first(g_vfs.systems); e; e = dll_next(g_vfs.systems, e), ++i) { struct VfsSystem *system = VFS_SYSTEM_CONTAINER(e); if (i < openfile->index) continue; ret = snprintf(openfile->readbuf + byteswritten, bytesleft, "%-8s%s\n", system->nodev ? "nodev" : "", system->name); if (ret > bytesleft) { break; } byteswritten += ret; bytesleft -= ret; ++openfile->index; } UNLOCK(&g_vfs.lock); if (e == NULL && byteswritten == 0) { openfile->readbufstart = sizeof(openfile->readbuf) + 1; openfile->readbufend = sizeof(openfile->readbuf) + 1; } else { openfile->readbufstart = 0; openfile->readbufend = byteswritten; } return 0; } static int ProcfsMountsStringEscape(char **str) { size_t len, len1; char *tmp; for (len = 0, len1 = 0; (*str)[len]; ++len) { len1 += ((*str)[len] == ' ') || ((*str)[len] == '\t'); } if (len1) { len1 = len + len1 * 3; tmp = realloc((*str), len1 + 1); if (!tmp) { return enomem(); } (*str) = tmp; tmp = NULL; (*str)[len1] = '\0'; for (; len > 0; --len) { if ((*str)[len - 1] == ' ') { (*str)[len1 - 1] = '0'; (*str)[len1 - 2] = '4'; (*str)[len1 - 3] = '0'; (*str)[len1 - 4] = '\\'; len1 -= 4; } else if ((*str)[len - 1] == '\t') { (*str)[len1 - 1] = '1'; (*str)[len1 - 2] = '1'; (*str)[len1 - 3] = '0'; (*str)[len1 - 4] = '\\'; len1 -= 4; } else { (*str)[len1 - 1] = (*str)[len - 1]; --len1; } } } return 0; } static int ProcfsPiddirMountsRead(struct VfsInfo *info, struct ProcfsOpenFile *openfile) { size_t byteswritten = 0; size_t bytesleft = sizeof(openfile->readbuf); size_t ret, len, len1; struct Dll *e = NULL; char *spec, *file, *vfstype, *mntops, *mntops1, *tmp; int freq = 0, passno = 0; int i; if (openfile->readbufend > sizeof(openfile->readbuf)) { return 0; } LOCK(&g_vfs.lock); for (i = 0, e = dll_first(g_vfs.devices); e; e = dll_next(g_vfs.devices, e), ++i) { struct VfsDevice *device = VFS_DEVICE_CONTAINER(e); if (i < openfile->index) continue; spec = file = vfstype = mntops = mntops1 = tmp = NULL; ret = 0; // Probably the root device. if (device->root == NULL) { goto cleanandcontinue; } if (VfsPathBuildFull(device->root, NULL, &file) == -1) { goto cleanandcontinue; } mntops = strdup("defaults"); if (!mntops) { goto cleanandcontinue; } if (!device->ops->Readmountentry || device->ops->Readmountentry(device, &spec, &vfstype, &mntops1) == -1) { goto cleanandcontinue; } if (mntops1) { len = strlen(mntops); len1 = strlen(mntops1); tmp = realloc(mntops, len + 1 + len1 + 1); if (!tmp) { goto cleanandcontinue; } mntops = tmp; tmp = NULL; mntops[len] = ','; memcpy(mntops + len + 1, mntops1, len1 + 1); } if (spec) { if (ProcfsMountsStringEscape(&spec) == -1) { goto cleanandcontinue; } } if (file) { if (ProcfsMountsStringEscape(&file) == -1) { goto cleanandcontinue; } } ret = snprintf(openfile->readbuf + byteswritten, bytesleft, "%s %s %s %s %d %d\n", spec, file, vfstype, mntops, freq, passno); cleanandcontinue: free(spec); free(file); free(vfstype); free(mntops); free(mntops1); free(tmp); if (ret > bytesleft) { break; } byteswritten += ret; bytesleft -= ret; ++openfile->index; } UNLOCK(&g_vfs.lock); if (e == NULL && byteswritten == 0) { openfile->readbufstart = sizeof(openfile->readbuf) + 1; openfile->readbufend = sizeof(openfile->readbuf) + 1; } else { openfile->readbufstart = 0; openfile->readbufend = byteswritten; } return 0; } //////////////////////////////////////////////////////////////////////////////// struct VfsSystem g_procfs = {.name = "proc", .nodev = true, .ops = { .Init = ProcfsInit, .Freeinfo = ProcfsFreeInfo, .Freedevice = ProcfsFreeDevice, .Readmountentry = ProcfsReadmountentry, .Finddir = ProcfsFinddir, .Readlink = ProcfsReadlink, .Mkdir = NULL, .Mkfifo = NULL, .Open = ProcfsOpen, .Access = ProcfsAccess, .Stat = ProcfsStat, .Fstat = ProcfsFstat, .Chmod = ProcfsChmod, .Fchmod = ProcfsFchmod, .Chown = ProcfsChown, .Fchown = ProcfsFchown, .Ftruncate = NULL, .Close = ProcfsClose, .Link = NULL, .Unlink = NULL, .Read = ProcfsRead, //.Write = ProcfsWrite, .Pread = ProcfsPread, //.Pwrite = ProcfsPwrite, .Readv = ProcfsReadv, //.Writev = ProcfsWritev, .Preadv = ProcfsPreadv, //.Pwritev = ProcfsPwritev, .Seek = ProcfsSeek, .Fsync = NULL, .Fdatasync = NULL, .Flock = NULL, .Dup = ProcfsDup, #ifdef HAVE_DUP3 .Dup3 = ProcfsDup3, #endif .Poll = NULL, .Opendir = ProcfsOpendir, #ifdef HAVE_SEEKDIR .Seekdir = ProcfsSeekdir, .Telldir = ProcfsTelldir, #endif .Readdir = ProcfsReaddir, .Rewinddir = ProcfsRewinddir, .Closedir = ProcfsClosedir, .Bind = NULL, .Connect = NULL, .Connectunix = NULL, .Accept = NULL, .Listen = NULL, .Shutdown = NULL, .Recvmsg = NULL, .Sendmsg = NULL, .Recvmsgunix = NULL, .Sendmsgunix = NULL, .Getsockopt = NULL, .Setsockopt = NULL, .Getsockname = NULL, .Getpeername = NULL, .Rename = NULL, .Utime = ProcfsUtime, .Futime = ProcfsFutime, .Symlink = NULL, .Mmap = NULL, .Munmap = NULL, .Mprotect = NULL, .Msync = NULL, .Pipe = NULL, #ifdef HAVE_PIPE2 .Pipe2 = NULL, #endif .Socket = NULL, .Socketpair = NULL, .Tcgetattr = NULL, .Tcsetattr = NULL, .Tcflush = NULL, .Tcdrain = NULL, .Tcsendbreak = NULL, .Tcflow = NULL, .Tcgetsid = NULL, .Tcgetpgrp = NULL, .Tcsetpgrp = NULL, #ifdef HAVE_SOCKATMARK .Sockatmark = NULL, #endif .Fexecve = NULL, }}; #endif /* DISABLE_VFS */ ================================================ FILE: blink/procfs.h ================================================ #ifndef BLINK_PROCFS_H_ #define BLINK_PROCFS_H_ #include "blink/vfs.h" extern struct VfsSystem g_procfs; int ProcfsRegisterExe(i32 pid, const char *path); #endif // BLINK_PROCFS_H_ ================================================ FILE: blink/prog.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/log.h" char *g_progname; ================================================ FILE: blink/pte32.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/thread.h" /** * @fileoverview page table ops for 32-bit hosts */ pthread_mutex_t_ g_ptelock = PTHREAD_MUTEX_INITIALIZER_; u64 LoadPte32_(const u8 *pte) { u64 res; LOCK(&g_ptelock); res = Read64(pte); UNLOCK(&g_ptelock); return res; } void StorePte32_(u8 *pte, u64 val) { LOCK(&g_ptelock); Write64(pte, val); UNLOCK(&g_ptelock); } bool CasPte32_(u8 *pte, u64 oldval, u64 newval) { bool res; LOCK(&g_ptelock); if (Read64(pte) == oldval) { Write64(pte, newval); res = true; } else { res = false; } UNLOCK(&g_ptelock); return res; } ================================================ FILE: blink/pty.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/pty.h" #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/macros.h" #include "blink/thompike.h" #include "blink/util.h" #ifdef IUTF8 #define CURSOR L'▂' #else #define CURSOR '_' #endif /** * @fileoverview Pseudoteletypewriter * * \t TAB * \a BELL * \177 BACKSPACE * \r CURSOR START * \b CURSOR LEFT OR CURSOR REWIND * \n CURSOR DOWN AND START IF OPOST * \f CURSOR DOWN AND START IF OPOST * \v CURSOR DOWN AND START OR \e[H\e[J * \eE CURSOR DOWN AND START * \eD CURSOR DOWN * \eM CURSOR UP * \ec FULL RESET * \e7 SAVE CURSOR POSITION * \e8 RESTORE CURSOR POSITION * \e(0 DEC SPECIAL GRAPHICS * \e(B USAS X3.4-1967 * \e#5 SINGLE WIDTH * \e#6 DOUBLE WIDTH * \e#8 SO MANY E * \eZ → \e/Z REPORT IDENTITY * \e[𝑛A CURSOR UP [CLAMPED] * \e[𝑛B CURSOR DOWN [CLAMPED] * \e[𝑛C CURSOR RIGHT [CLAMPED] * \e[𝑛D CURSOR LEFT [CLAMPED] * \e[𝑦;𝑥H SET CURSOR POSITION [CLAMPED] * \e[𝑥G SET CURSOR COLUMN [CLAMPED] * \e[𝑦d SET CURSOR ROW [CLAMPED] * \e[𝑛E CURSOR DOWN AND START [CLAMPED] * \e[𝑛F CURSOR UP AND START [CLAMPED] * \e[𝑛S SCROLL UP * \e[𝑛T SCROLL DOWN * \e[𝑛@ INSERT CELLS * \e[𝑛P DELETE CELLS * \e[𝑛L INSERT LINES * \e[𝑛M DELETE LINES * \e[J ERASE DISPLAY FORWARDS * \e[1J ERASE DISPLAY BACKWARDS * \e[2J ERASE DISPLAY * \e[K ERASE LINE FORWARD * \e[1K ERASE LINE BACKWARD * \e[2K ERASE LINE * \e[𝑛X ERASE CELLS * \e[0m RESET * \e[1m BOLD * \e[2m FAINT * \e[3m ITALIC * \e[4m UNDER * \e[5m BLINK * \e[7m INVERT * \e[8m CONCEAL * \e[9m STRIKE * \e[20m FRAKTUR * \e[21m DUNDER * \e[22m RESET BOLD & FAINT * \e[23m RESET ITALIC & FRAKTUR * \e[24m RESET UNDER & DUNDER * \e[25m RESET BLINK * \e[27m RESET INVERT * \e[28m RESET CONCEAL * \e[29m RESET STRIKE * \e[39m RESET FOREGROUND * \e[49m RESET BACKGROUND * \e[30m BLACK FOREGROUND * \e[31m RED FOREGROUND * \e[32m GREEN FOREGROUND * \e[33m YELLOW FOREGROUND * \e[34m BLUE FOREGROUND * \e[35m MAGENTA FOREGROUND * \e[36m CYAN FOREGROUND * \e[37m WHITE FOREGROUND * \e[40m BLACK BACKGROUND * \e[41m RED BACKGROUND * \e[42m GREEN BACKGROUND * \e[44m YELLOW BACKGROUND * \e[44m BLUE BACKGROUND * \e[45m MAGENTA BACKGROUND * \e[46m CYAN BACKGROUND * \e[47m WHITE BACKGROUND * \e[90m BRIGHT BLACK FOREGROUND * \e[91m BRIGHT RED FOREGROUND * \e[92m BRIGHT GREEN FOREGROUND * \e[93m BRIGHT YELLOW FOREGROUND * \e[94m BRIGHT BLUE FOREGROUND * \e[95m BRIGHT MAGENTA FOREGROUND * \e[96m BRIGHT CYAN FOREGROUND * \e[97m BRIGHT WHITE FOREGROUND * \e[100m BRIGHT BLACK BACKGROUND * \e[101m BRIGHT RED BACKGROUND * \e[102m BRIGHT GREEN BACKGROUND * \e[103m BRIGHT YELLOW BACKGROUND * \e[104m BRIGHT BLUE BACKGROUND * \e[105m BRIGHT MAGENTA BACKGROUND * \e[106m BRIGHT CYAN BACKGROUND * \e[107m BRIGHT WHITE BACKGROUND * \e[38;5;𝑥m XTERM256 FOREGROUND * \e[48;5;𝑥m XTERM256 BACKGROUND * \e[38;2;𝑟;𝑔;𝑏m RGB FOREGROUND * \e[48;2;𝑟;𝑔;𝑏m RGB BACKGROUND * \e[?25h SHOW CURSOR * \e[?25l HIDE CURSOR * \e[s SAVE CURSOR POSITION * \e[u RESTORE CURSOR POSITION * \e[?5h ... \e[?5l REVERSE VIDEO EPILEPSY * \e[0q RESET LEDS * \e[1q TURN ON FIRST LED * \e[2q TURN ON SECOND LED * \e[3q TURN ON THIRD LED * \e[4q TURN ON FOURTH LED * \e[c → \e[?1;0c REPORT DEVICE TYPE * \e[5n → \e[0n REPORT DEVICE STATUS * \e[6n → \e[𝑦;𝑥R REPORT CURSOR POSITION * \e7\e[9979;9979H\e[6n\e8 → \e[𝑦;𝑥R REPORT DISPLAY DIMENSIONS * * @see https://vt100.net/docs/vt220-rm/chapter4.html * @see https://invisible-island.net/xterm/ * @see ANSI X3.64-1979 * @see ISO/IEC 6429 * @see FIPS-86 * @see ECMA-48 */ struct Pty *NewPty(void) { struct Pty *pty; if ((pty = (struct Pty *)calloc(1, sizeof(*pty)))) { PtyResize(pty, 25, 80); PtyFullReset(pty); PtyErase(pty, 0, pty->yn * pty->xn); } return pty; } static void FreePtyPlanes(struct Pty *pty) { free(pty->wcs); free(pty->fgs); free(pty->bgs); free(pty->prs); } void FreePty(struct Pty *pty) { if (pty) { FreePtyPlanes(pty); free(pty); } } static wchar_t *GetXlatAscii(void) { unsigned i; static bool once; static wchar_t xlat[128]; if (!once) { for (i = 0; i < 128; ++i) { xlat[i] = i; } once = true; } return xlat; } static wchar_t *GetXlatLineDrawing(void) { unsigned i; static bool once; static wchar_t xlat[128]; if (!once) { for (i = 0; i < 128; ++i) { if (0x5F <= i && i <= 0x7E) { xlat[i] = L" ◆▒␉␌␍␊°±␤␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥π≠£·"[i - 0x5F]; } else { xlat[i] = i; } } once = true; } return xlat; } static void XlatAlphabet(wchar_t xlat[128], int a, int b) { unsigned i; for (i = 0; i < 128; ++i) { if ('a' <= i && i <= 'z') { xlat[i] = i - 'a' + a; } else if ('A' <= i && i <= 'Z') { xlat[i] = i - 'A' + b; } else { xlat[i] = i; } } } static wchar_t *GetXlatItalic(void) { static bool once; static wchar_t xlat[128]; if (!once) { #if WCHAR_MAX > 0x10000 XlatAlphabet(xlat, L'𝑎', L'𝐴'); #else XlatAlphabet(xlat, L'a', L'A'); #endif once = true; } return xlat; } static wchar_t *GetXlatBoldItalic(void) { static bool once; static wchar_t xlat[128]; if (!once) { #if WCHAR_MAX > 0x10000 XlatAlphabet(xlat, L'𝒂', L'𝑨'); #else XlatAlphabet(xlat, L'a', L'A'); #endif once = true; } return xlat; } static wchar_t *GetXlatBoldFraktur(void) { static bool once; static wchar_t xlat[128]; if (!once) { #if WCHAR_MAX > 0x10000 XlatAlphabet(xlat, L'𝖆', L'𝕬'); #else XlatAlphabet(xlat, L'a', L'A'); #endif once = true; } return xlat; } static wchar_t *GetXlatFraktur(void) { unsigned i; static bool once; static wchar_t xlat[128]; if (!once) { #if WCHAR_MAX > 0x10000 for (i = 0; i < ARRAYLEN(xlat); ++i) { if ('A' <= i && i <= 'Z') { xlat[i] = L"𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ"[i - 'A']; } else if ('a' <= i && i <= 'z') { xlat[i] = i - 'a' + L'𝔞'; } else { xlat[i] = i; } } #else XlatAlphabet(xlat, L'a', L'A'); #endif once = true; } return xlat; } static wchar_t *GetXlatDoubleWidth(void) { unsigned i; static bool once; static wchar_t xlat[128]; if (!once) { for (i = 0; i < ARRAYLEN(xlat); ++i) { if ('!' <= i && i <= '~') { xlat[i] = -(i - '!' + L'!'); } else { xlat[i] = i; } } once = true; } return xlat; } static wchar_t *GetXlatSgr(struct Pty *pty) { switch (!!(pty->pr & kPtyFraktur) << 2 | !!(pty->pr & kPtyItalic) << 1 | !!(pty->pr & kPtyBold) << 0) { case 4: case 6: return GetXlatFraktur(); case 5: case 7: return GetXlatBoldFraktur(); case 3: return GetXlatBoldItalic(); case 2: return GetXlatItalic(); default: return GetXlatAscii(); } } static void PtySetXlat(struct Pty *pty, wchar_t *xlat) { pty->xlat = xlat; pty->pr &= ~(kPtyItalic | kPtyFraktur); } static void PtySetCodepage(struct Pty *pty, char id) { switch (id) { default: case 'B': PtySetXlat(pty, GetXlatAscii()); break; case '0': PtySetXlat(pty, GetXlatLineDrawing()); break; } } static u32 *u32set(u32 *p, u32 c, size_t n) { size_t i; for (i = 0; i < n; ++i) { p[i] = c; } return p; } void PtyErase(struct Pty *pty, long dst, long n) { unassert(dst + n <= pty->yn * pty->xn); u32set(pty->wcs + dst, ' ', n); u32set(pty->prs + dst, 0, n); } void PtyMemmove(struct Pty *pty, long dst, long src, long n) { unassert(src + n <= pty->yn * pty->xn); unassert(dst + n <= pty->yn * pty->xn); memmove(pty->wcs + dst, pty->wcs + src, n * 4); memmove(pty->fgs + dst, pty->fgs + src, n * 4); memmove(pty->bgs + dst, pty->bgs + src, n * 4); memmove(pty->prs + dst, pty->prs + src, n * 4); } void PtyFullReset(struct Pty *pty) { pty->y = 0; pty->x = 0; pty->pr = 0; pty->u8 = 0; pty->n8 = 0; pty->conf = 0; pty->save = 0; pty->esc.i = 0; pty->input.i = 0; pty->state = kPtyAscii; pty->xlat = GetXlatAscii(); PtyErase(pty, 0, pty->yn * pty->xn); } void PtySetY(struct Pty *pty, int y) { pty->conf &= ~kPtyRedzone; pty->y = MAX(0, MIN(pty->yn - 1, y)); } void PtySetX(struct Pty *pty, int x) { pty->conf &= ~kPtyRedzone; pty->x = MAX(0, MIN(pty->xn - 1, x)); } void PtyResize(struct Pty *pty, int yn, int xn) { unsigned y, ym, xm, y0; u32 *wcs, *fgs, *bgs, *prs; if (xn < 80) xn = 80; if (yn < 25) yn = 25; if (xn == pty->xn && yn == pty->yn) return; wcs = (u32 *)calloc(yn * xn, 4); fgs = (u32 *)calloc(yn * xn, 4); bgs = (u32 *)calloc(yn * xn, 4); prs = (u32 *)calloc(yn * xn, 4); y0 = yn > pty->y + 1 ? 0 : pty->y + 1 - yn; ym = MIN(yn, pty->yn) + y0; xm = MIN(xn, pty->xn); for (y = y0; y < ym; ++y) { memcpy(wcs + y * xn, pty->wcs + y * pty->xn, xm * 4); memcpy(fgs + y * xn, pty->fgs + y * pty->xn, xm * 4); memcpy(bgs + y * xn, pty->bgs + y * pty->xn, xm * 4); memcpy(prs + y * xn, pty->prs + y * pty->xn, xm * 4); } FreePtyPlanes(pty); pty->wcs = wcs; pty->fgs = fgs; pty->bgs = bgs; pty->prs = prs; pty->yn = yn; pty->xn = xn; PtySetY(pty, pty->y); PtySetX(pty, pty->x); } static void PtyConcatInput(struct Pty *pty, const char *data, size_t n) { AppendData(&pty->input, data, n); } static void PtyScroll(struct Pty *pty) { PtyMemmove(pty, 0, pty->xn, pty->xn * (pty->yn - 1)); PtyErase(pty, pty->xn * (pty->yn - 1), pty->xn); } static void PtyReverse(struct Pty *pty) { PtyMemmove(pty, pty->xn, 0, pty->xn * (pty->yn - 1)); PtyErase(pty, 0, pty->xn); } static void PtyIndex(struct Pty *pty) { if (pty->y < pty->yn - 1) { ++pty->y; } else { PtyScroll(pty); } } static void PtyReverseIndex(struct Pty *pty) { if (pty->y) { --pty->y; } else { PtyReverse(pty); } } static void PtyCarriageReturn(struct Pty *pty) { PtySetX(pty, 0); } static void PtyNewline(struct Pty *pty) { PtyIndex(pty); if (!(pty->conf & kPtyNoopost)) { PtyCarriageReturn(pty); } } static void PtyAdvance(struct Pty *pty) { unassert(pty->xn - 1 == pty->x); unassert(pty->conf & kPtyRedzone); pty->conf &= ~kPtyRedzone; pty->x = 0; if (pty->y < pty->yn - 1) { ++pty->y; } else { PtyScroll(pty); } } static void PtyWriteGlyph(struct Pty *pty, wint_t wc, int w) { u32 i; unassert(!(0x00 <= wc && wc <= 0x1F)); unassert(!(0x7F <= wc && wc <= 0x9F)); if (w < 1) wc = ' ', w = 1; if ((pty->conf & kPtyRedzone) || pty->x + w > pty->xn) { PtyAdvance(pty); } i = pty->y * pty->xn + pty->x; pty->wcs[i] = wc; if ((pty->prs[i] = pty->pr) & (kPtyFg | kPtyBg)) { pty->fgs[i] = pty->fg; pty->bgs[i] = pty->bg; } if ((pty->x += w) >= pty->xn) { pty->x = pty->xn - 1; pty->conf |= kPtyRedzone; } } static void PtyWriteTab(struct Pty *pty) { unsigned x, x2; if (pty->conf & kPtyRedzone) { PtyAdvance(pty); } x2 = MIN(pty->xn, ROUNDUP(pty->x + 1, 8)); for (x = pty->x; x < x2; ++x) { pty->wcs[pty->y * pty->xn + x] = ' '; } if (x2 < pty->xn) { pty->x = x2; } else { pty->x = pty->xn - 1; pty->conf |= kPtyRedzone; } } int PtyAtoi(const char *s, const char **e) { int i; for (i = 0; isdigit(*s); ++s) i *= 10, i += *s - '0'; if (e) *e = s; return i; } static int PtyGetMoveParam(struct Pty *pty) { int x = PtyAtoi(pty->esc.s, NULL); if (x < 1) x = 1; return x; } static void PtySetCursorPosition(struct Pty *pty) { int row, col; const char *s = pty->esc.s; row = PtyAtoi(s, &s); row = MAX(1, row); if (*s == ';') ++s; col = PtyAtoi(s, &s); col = MAX(1, col); PtySetY(pty, row - 1); PtySetX(pty, col - 1); } static void PtySetCursorRow(struct Pty *pty) { PtySetY(pty, PtyGetMoveParam(pty) - 1); } static void PtySetCursorColumn(struct Pty *pty) { PtySetX(pty, PtyGetMoveParam(pty) - 1); } static void PtyMoveCursor(struct Pty *pty, int dy, int dx) { int n = PtyGetMoveParam(pty); PtySetY(pty, pty->y + dy * n); PtySetX(pty, pty->x + dx * n); } static void PtyScrollUp(struct Pty *pty) { int n = PtyGetMoveParam(pty); while (n--) PtyScroll(pty); } static void PtyScrollDown(struct Pty *pty) { int n = PtyGetMoveParam(pty); while (n--) PtyReverse(pty); } static void PtySetCursorStatus(struct Pty *pty, bool status) { if (status) { pty->conf &= ~kPtyNocursor; } else { pty->conf |= kPtyNocursor; } } static void PtySetMode(struct Pty *pty, bool status) { const char *p = pty->esc.s; switch (*p++) { case '?': while (isdigit(*p)) { switch (PtyAtoi(p, &p)) { case 25: PtySetCursorStatus(pty, status); break; default: break; } if (*p == ';') { ++p; } } break; default: break; } } static void PtySaveCursorPosition(struct Pty *pty) { pty->save = (pty->y & 0x7FFF) | (pty->x & 0x7FFF) << 16; } static void PtyRestoreCursorPosition(struct Pty *pty) { PtySetY(pty, (pty->save & 0x00007FFF) >> 000); PtySetX(pty, (pty->save & 0x7FFF0000) >> 020); } static void PtyEraseDisplay(struct Pty *pty) { switch (PtyAtoi(pty->esc.s, NULL)) { case 0: PtyErase(pty, pty->y * pty->xn + pty->x, pty->yn * pty->xn - (pty->y * pty->xn + pty->x)); break; case 1: PtyErase(pty, 0, pty->y * pty->xn + pty->x); break; case 2: case 3: PtyErase(pty, 0, pty->yn * pty->xn); break; default: break; } } static void PtyEraseLine(struct Pty *pty) { switch (PtyAtoi(pty->esc.s, NULL)) { case 0: PtyErase(pty, pty->y * pty->xn + pty->x, pty->xn - pty->x); break; case 1: PtyErase(pty, pty->y * pty->xn, pty->x); break; case 2: PtyErase(pty, pty->y * pty->xn, pty->xn); break; default: break; } } static void PtyEraseCells(struct Pty *pty) { int i, n, x; i = pty->y * pty->xn + pty->x; n = pty->yn * pty->xn; x = PtyAtoi(pty->esc.s, NULL); x = MIN(MAX(x, 1), n - i); PtyErase(pty, i, x); } static int PtyArg1(struct Pty *pty) { int x = PtyAtoi(pty->esc.s, NULL); return MAX(1, x); } static void PtyInsertCells(struct Pty *pty) { int n = PtyArg1(pty); n = MIN(pty->xn - pty->x, n); PtyMemmove(pty, pty->y * pty->xn + pty->x + n, pty->y * pty->xn + pty->x, pty->xn - (pty->x + n)); PtyErase(pty, pty->y * pty->xn + pty->x, n); } static void PtyInsertLines(struct Pty *pty) { int n = PtyArg1(pty); n = MIN(pty->yn - pty->y, n); PtyMemmove(pty, (pty->y + n) * pty->xn, pty->y * pty->xn, (pty->yn - pty->y - n) * pty->xn); PtyErase(pty, pty->y * pty->xn, n * pty->xn); } static void PtyDeleteCells(struct Pty *pty) { int n = PtyArg1(pty); n = MIN(pty->xn - pty->x, n); PtyMemmove(pty, pty->y * pty->xn + pty->x, pty->y * pty->xn + pty->x + n, pty->xn - (pty->x + n)); PtyErase(pty, pty->y * pty->xn + pty->x, n); } static void PtyDeleteLines(struct Pty *pty) { int n = PtyArg1(pty); n = MIN(pty->yn - pty->y, n); PtyMemmove(pty, pty->y * pty->xn, (pty->y + n) * pty->xn, (pty->yn - pty->y - n) * pty->xn); PtyErase(pty, (pty->y + n) * pty->xn, n * pty->xn); } static void PtyReportDeviceStatus(struct Pty *pty) { PtyWriteInput(pty, "\033[0n", 4); } static void PtyReportPreferredVtType(struct Pty *pty) { PtyWriteInput(pty, "\033[?1;0c", 4); } static void PtyReportPreferredVtIdentity(struct Pty *pty) { PtyWriteInput(pty, "\033/Z", 4); } static void PtyBell(struct Pty *pty) { pty->conf |= kPtyBell; } static void PtyLed(struct Pty *pty) { switch (PtyAtoi(pty->esc.s, NULL)) { case 0: pty->conf &= ~kPtyLed1; pty->conf &= ~kPtyLed2; pty->conf &= ~kPtyLed3; pty->conf &= ~kPtyLed4; break; case 1: pty->conf |= kPtyLed1; break; case 2: pty->conf |= kPtyLed2; break; case 3: pty->conf |= kPtyLed3; break; case 4: pty->conf |= kPtyLed4; break; default: break; } } static void PtyReportCursorPosition(struct Pty *pty) { char buf[2 + 10 + 1 + 10 + 1]; PtyWriteInput(pty, buf, sprintf(buf, "\033[%d;%dR", (pty->y + 1) & 0x7fff, (pty->x + 1) & 0x7fff)); } static void PtyCsiN(struct Pty *pty) { switch (PtyAtoi(pty->esc.s, NULL)) { case 5: PtyReportDeviceStatus(pty); break; case 6: PtyReportCursorPosition(pty); break; default: break; } } static void PtySelectGraphicsRendition(struct Pty *pty) { char *p, c; unsigned x; u8 code[4]; enum Sgr { kSgr, kSgrFg = 010, kSgrFgTrue = 012, kSgrFgXterm = 015, kSgrBg = 020, kSgrBgTrue = 022, kSgrBgXterm = 025, } t; x = 0; t = kSgr; p = pty->esc.s; memset(code, 0, sizeof(code)); for (;;) { c = *p++; switch (c) { case '\0': return; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': x *= 10; x += c - '0'; break; case ';': case 'm': code[code[3]] = x; x = 0; switch (t) { case kSgr: switch (code[0]) { case 38: t = kSgrFg; break; case 48: t = kSgrBg; break; case 0: pty->pr = 0; pty->xlat = GetXlatSgr(pty); break; case 1: pty->pr |= kPtyBold; pty->xlat = GetXlatSgr(pty); break; case 2: pty->pr |= kPtyFaint; break; case 3: pty->pr |= kPtyItalic; pty->xlat = GetXlatSgr(pty); break; case 4: pty->pr |= kPtyUnder; break; case 5: pty->pr |= kPtyBlink; break; case 7: pty->pr |= kPtyFlip; break; case 8: pty->pr |= kPtyConceal; break; case 9: pty->pr |= kPtyStrike; break; case 20: pty->pr |= kPtyFraktur; pty->xlat = GetXlatSgr(pty); break; case 21: pty->pr |= kPtyUnder | kPtyDunder; break; case 22: pty->pr &= ~(kPtyFaint | kPtyBold); pty->xlat = GetXlatSgr(pty); break; case 23: pty->pr &= ~kPtyItalic; pty->xlat = GetXlatSgr(pty); break; case 24: pty->pr &= ~(kPtyUnder | kPtyDunder); break; case 25: pty->pr &= ~kPtyBlink; break; case 27: pty->pr &= ~kPtyFlip; break; case 28: pty->pr &= ~kPtyConceal; break; case 29: pty->pr &= ~kPtyStrike; break; case 39: pty->pr &= ~kPtyFg; break; case 49: pty->pr &= ~kPtyBg; break; case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: code[0] -= 90 - 30; code[0] += 8; /* fallthrough */ case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: pty->fg = code[0] - 30; pty->pr |= kPtyFg; pty->pr &= ~kPtyTrue; break; case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: code[0] -= 100 - 40; code[0] += 8; /* fallthrough */ case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: pty->bg = code[0] - 40; pty->pr |= kPtyBg; pty->pr &= ~kPtyTrue; break; default: break; } break; case kSgrFg: case kSgrBg: switch (code[0]) { case 2: case 5: t = (enum Sgr)((int)t + code[0]); break; default: t = kSgr; break; } break; case kSgrFgTrue: if (++code[3] == 3) { code[3] = 0; t = kSgr; pty->fg = Read32(code); pty->pr |= kPtyFg; pty->pr |= kPtyTrue; } break; case kSgrBgTrue: if (++code[3] == 3) { code[3] = 0; t = kSgr; pty->bg = Read32(code); pty->pr |= kPtyBg; pty->pr |= kPtyTrue; } break; case kSgrFgXterm: t = kSgr; pty->fg = code[0]; pty->pr |= kPtyFg; pty->pr &= ~kPtyTrue; break; case kSgrBgXterm: t = kSgr; pty->bg = code[0]; pty->pr |= kPtyBg; pty->pr &= ~kPtyTrue; break; default: Abort(); } break; default: break; } } } static void PtyCsi(struct Pty *pty) { switch (pty->esc.s[pty->esc.i - 1]) { case 'f': case 'H': PtySetCursorPosition(pty); break; case 'G': PtySetCursorColumn(pty); break; case 'd': PtySetCursorRow(pty); break; case 'F': pty->x = 0; /* fallthrough */ case 'A': PtyMoveCursor(pty, -1, +0); break; case 'E': pty->x = 0; /* fallthrough */ case 'B': PtyMoveCursor(pty, +1, +0); break; case 'C': PtyMoveCursor(pty, +0, +1); break; case 'D': PtyMoveCursor(pty, +0, -1); break; case 'S': PtyScrollUp(pty); break; case 'T': PtyScrollDown(pty); break; case '@': PtyInsertCells(pty); break; case 'P': PtyDeleteCells(pty); break; case 'L': PtyInsertLines(pty); break; case 'M': PtyDeleteLines(pty); break; case 'J': PtyEraseDisplay(pty); break; case 'K': PtyEraseLine(pty); break; case 'X': PtyEraseCells(pty); break; case 's': PtySaveCursorPosition(pty); break; case 'u': PtyRestoreCursorPosition(pty); break; case 'n': PtyCsiN(pty); break; case 'm': PtySelectGraphicsRendition(pty); break; case 'h': PtySetMode(pty, true); break; case 'l': PtySetMode(pty, false); break; case 'c': PtyReportPreferredVtType(pty); break; case 'q': PtyLed(pty); break; default: break; } } static void PtyScreenAlignmentDisplay(struct Pty *pty) { u32set(pty->wcs, 'E', pty->yn * pty->xn); } static void PtyEscHash(struct Pty *pty) { switch (pty->esc.s[1]) { case '5': PtySetXlat(pty, GetXlatAscii()); break; case '6': PtySetXlat(pty, GetXlatDoubleWidth()); break; case '8': PtyScreenAlignmentDisplay(pty); break; default: break; } } static void PtyEsc(struct Pty *pty) { switch (pty->esc.s[0]) { case 'c': PtyFullReset(pty); break; case '7': PtySaveCursorPosition(pty); break; case '8': PtyRestoreCursorPosition(pty); break; case 'E': pty->x = 0; case 'D': PtyIndex(pty); break; case 'M': PtyReverseIndex(pty); break; case 'Z': PtyReportPreferredVtIdentity(pty); break; case '(': PtySetCodepage(pty, pty->esc.s[1]); break; case '#': PtyEscHash(pty); break; default: break; } } static void PtyCntrl(struct Pty *pty, int c01) { switch (c01) { case '\a': PtyBell(pty); break; case 0205: case '\f': case '\v': case '\n': PtyNewline(pty); break; case '\r': PtyCarriageReturn(pty); break; case '\t': PtyWriteTab(pty); break; case '\b': case 0177: pty->x = MAX(0, pty->x - 1); break; case 033: pty->state = kPtyEsc; pty->esc.i = 0; break; case 0204: PtyIndex(pty); break; case 0215: PtyReverseIndex(pty); break; case 0233: pty->state = kPtyCsi; break; default: break; } } static void PtyEscAppend(struct Pty *pty, char c) { pty->esc.i = MIN(pty->esc.i + 1, ARRAYLEN(pty->esc.s) - 1); pty->esc.s[pty->esc.i - 1] = c; pty->esc.s[pty->esc.i - 0] = 0; } ssize_t PtyWrite(struct Pty *pty, const void *data, size_t n) { int i; wchar_t wc; const u8 *p; for (p = (const u8 *)data, i = 0; i < n; ++i) { switch (pty->state) { case kPtyAscii: if (0x00 <= p[i] && p[i] <= 0x7F) { if (0x20 <= p[i] && p[i] <= 0x7E) { if ((wc = pty->xlat[p[i]]) >= 0) { PtyWriteGlyph(pty, wc, 1); } else { PtyWriteGlyph(pty, -wc, 2); } } else { PtyCntrl(pty, p[i]); } } else if (!ThomPikeCont(p[i])) { pty->state = kPtyUtf8; pty->u8 = ThomPikeByte(p[i]); pty->n8 = ThomPikeLen(p[i]) - 1; } break; case kPtyUtf8: if (ThomPikeCont(p[i])) { pty->u8 = ThomPikeMerge(pty->u8, p[i]); if (--pty->n8) break; } wc = pty->u8; if ((0x00 <= wc && wc <= 0x1F) || (0x7F <= wc && wc <= 0x9F)) { PtyCntrl(pty, wc); } else { PtyWriteGlyph(pty, wc, wcwidth(wc)); } pty->state = kPtyAscii; pty->u8 = 0; --i; break; case kPtyEsc: if (p[i] == '[') { pty->state = kPtyCsi; } else if (0x30 <= p[i] && p[i] <= 0x7E) { PtyEscAppend(pty, p[i]); PtyEsc(pty); pty->state = kPtyAscii; } else if (0x20 <= p[i] && p[i] <= 0x2F) { PtyEscAppend(pty, p[i]); } else { pty->state = kPtyAscii; } break; case kPtyCsi: PtyEscAppend(pty, p[i]); switch (p[i]) { case ':': case ';': case '<': case '=': case '>': case '?': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case '`': case '~': case '^': case '@': case '[': case ']': case '{': case '}': case '_': case '|': case '\\': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': PtyCsi(pty); pty->state = kPtyAscii; break; default: pty->state = kPtyAscii; continue; } break; default: __builtin_unreachable(); } } return n; } ssize_t PtyWriteInput(struct Pty *pty, const void *data, size_t n) { int c; bool cr; char *p; const char *q; size_t i, j, m; q = (char *)data; p = pty->input.p; i = pty->input.i; m = pty->input.n; if (i + n * 2 + 1 > m) { m = MAX(m, 8); do m += m >> 1; while (i + n * 2 + 1 > m); if (!(p = (char *)realloc(p, m))) { return -1; } pty->input.p = p; pty->input.n = m; } // TODO(jart): Figure out how translation settings for these work. cr = i && p[i - 1] == '\r'; for (j = 0; j < n; ++j) { c = q[j] & 255; if (c == '\r') { cr = true; } else if (cr) { if (c != '\n') { p[i++] = '\n'; } cr = false; } p[i++] = c; } /* if (cr) { */ /* p[i++] = '\n'; */ /* } */ if (!(pty->conf & kPtyNoecho)) { PtyWrite(pty, p + pty->input.i, i - pty->input.i); } pty->input.i = i; return n; } ssize_t PtyRead(struct Pty *pty, void *buf, size_t size) { char *p; size_t n; n = MIN(size, pty->input.i); if (!(pty->conf & kPtyNocanon)) { if ((p = (char *)memchr(pty->input.p, '\n', n))) { n = MIN(n, pty->input.p - p + 1); } else { n = 0; } } memcpy(buf, pty->input.p, n); memcpy(pty->input.p, pty->input.p + n, pty->input.i - n); pty->input.i -= n; return n; } static char *PtyEncodeRgb(char *p, int rgb) { return p + sprintf(p, "2;%u;%u;%u", (rgb & 0x0000ff) >> 000, (rgb & 0x00ff00) >> 010, (rgb & 0xff0000) >> 020); } static char *PtyEncodeXterm256(char *p, int xt) { return p + sprintf(p, "5;%u", xt); } char *PtyEncodeStyle(char *p, u32 xr, u32 pr, u32 fg, u32 bg) { *p++ = 033; *p++ = '['; if (pr & (kPtyBold | kPtyFaint | kPtyFlip | kPtyUnder | kPtyDunder | kPtyBlink | kPtyStrike | kPtyFg | kPtyBg)) { if (xr & (kPtyBold | kPtyFaint)) { if ((xr & (kPtyBold | kPtyFaint)) ^ (pr & (kPtyBold | kPtyFaint))) { *p++ = '2'; *p++ = '2'; *p++ = ';'; } if (pr & kPtyBold) { *p++ = '1'; *p++ = ';'; } if (pr & kPtyFaint) { *p++ = '2'; *p++ = ';'; } } if (xr & (kPtyUnder | kPtyDunder)) { if ((xr & (kPtyUnder | kPtyDunder)) ^ (pr & (kPtyUnder | kPtyDunder))) { *p++ = '2'; *p++ = '4'; *p++ = ';'; } if (pr & kPtyUnder) { *p++ = '4'; *p++ = ';'; } if (pr & kPtyDunder) { *p++ = '2'; *p++ = '1'; *p++ = ';'; } } if (xr & (kPtyFlip | kPtyBlink | kPtyStrike)) { if (xr & kPtyFlip) { if (!(pr & kPtyFlip)) *p++ = '2'; *p++ = '7'; *p++ = ';'; } if (xr & kPtyBlink) { if (!(pr & kPtyBlink)) *p++ = '2'; *p++ = '5'; *p++ = ';'; } if (xr & kPtyStrike) { if (!(pr & kPtyStrike)) *p++ = '2'; *p++ = '9'; *p++ = ';'; } } if (xr & (kPtyFg | kPtyTrue)) { *p++ = '3'; if (pr & kPtyFg) { *p++ = '8'; *p++ = ';'; if (pr & kPtyTrue) { p = PtyEncodeRgb(p, fg); } else { p = PtyEncodeXterm256(p, fg); } } else { *p++ = '9'; } *p++ = ';'; } if (xr & (kPtyBg | kPtyTrue)) { *p++ = '4'; if (pr & kPtyBg) { *p++ = '8'; *p++ = ';'; if (pr & kPtyTrue) { p = PtyEncodeRgb(p, bg); } else { p = PtyEncodeXterm256(p, bg); } } else { *p++ = '9'; } *p++ = ';'; } unassert(';' == p[-1]); p[-1] = 'm'; } else { *p++ = '0'; *p++ = 'm'; } return p; } int PtyAppendLine(struct Pty *pty, struct Buffer *buf, unsigned y) { u64 u; char *p, *pb; u32 i, j, n, wc, np, xp, pr, fg, bg, ci; int w; if (y >= pty->yn) { errno = EINVAL; return -1; } n = buf->i + pty->xn * 60; /* torture character length */ if (n > buf->n) { if (!(p = (char *)realloc(buf->p, n))) return -1; buf->p = p; buf->n = n; } i = y * pty->xn; j = (y + 1) * pty->xn; pb = buf->p + buf->i; ci = !(pty->conf & kPtyNocursor) && y == pty->y ? i + pty->x : -1; for (pr = 0; i < j; i += w) { np = pty->prs[i]; if (!(np & kPtyConceal)) { wc = pty->wcs[i]; unassert(!(0x00 <= wc && wc <= 0x1F)); unassert(!(0x7F <= wc && wc <= 0x9F)); if (0x20 <= wc && wc <= 0x7E) { u = wc; w = 1; } else { u = tpenc(wc); w = wcwidth(wc); w = MAX(1, w); } } else { u = ' '; w = 1; } if (i == ci) { if (u != ' ') { np ^= kPtyFlip; } else { u = tpenc(CURSOR); if (pty->conf & kPtyBlinkcursor) { np |= kPtyBlink; } } } fg = bg = -1; xp = pr ^ np; if (np & (kPtyFg | kPtyBg)) { if (np & kPtyFg) { if (pty->fgs[i] != fg) xp |= kPtyFg; fg = pty->fgs[i]; } if (np & kPtyBg) { if (pty->bgs[i] != bg) xp |= kPtyBg; bg = pty->bgs[i]; } } p = pb; if (xp) { pr = np; p = PtyEncodeStyle(p, xp, pr, fg, bg); } do { *p++ = u & 0xFF; u >>= 8; } while (u); unassert(p - pb <= 60); pb = p; } unassert(pb - buf->p <= buf->n); buf->i = pb - buf->p; return 0; } ================================================ FILE: blink/pty.h ================================================ #ifndef BLINK_PTY_H_ #define BLINK_PTY_H_ #include "blink/buffer.h" #include "blink/types.h" #define kPtyFg 0x0001 #define kPtyBg 0x0002 #define kPtyBold 0x0004 #define kPtyFlip 0x0008 #define kPtyFaint 0x0010 #define kPtyUnder 0x0020 #define kPtyDunder 0x0040 #define kPtyTrue 0x0080 #define kPtyBlink 0x0100 #define kPtyItalic 0x0200 #define kPtyFraktur 0x0400 #define kPtyStrike 0x0800 #define kPtyConceal 0x1000 #define kPtyBell 0x001 #define kPtyRedzone 0x002 #define kPtyNocursor 0x004 #define kPtyBlinkcursor 0x008 #define kPtyNocanon 0x010 #define kPtyNoecho 0x020 #define kPtyNoopost 0x040 #define kPtyLed1 0x080 #define kPtyLed2 0x100 #define kPtyLed3 0x200 #define kPtyLed4 0x400 enum PtyState { kPtyAscii, kPtyUtf8, kPtyEsc, kPtyCsi, }; struct PtyEsc { unsigned i; char s[64]; }; struct Pty { int y; int x; int yn; int xn; u32 u8; u32 n8; u32 pr; u32 fg; u32 bg; u32 conf; u32 save; u32 *wcs; u32 *prs; u32 *fgs; u32 *bgs; wchar_t *xlat; enum PtyState state; struct PtyEsc esc; struct Buffer input; }; void FreePty(struct Pty *); struct Pty *NewPty(void); void PtyResize(struct Pty *, int, int); ssize_t PtyRead(struct Pty *, void *, size_t); ssize_t PtyWrite(struct Pty *, const void *, size_t); ssize_t PtyWriteInput(struct Pty *, const void *, size_t); int PtyAppendLine(struct Pty *, struct Buffer *, unsigned); void PtyFullReset(struct Pty *); void PtyMemmove(struct Pty *, long, long, long); void PtyErase(struct Pty *, long, long); void PtySetY(struct Pty *, int); void PtySetX(struct Pty *, int); #endif /* BLINK_PTY_H_ */ ================================================ FILE: blink/pun.h ================================================ #ifndef BLINK_PUN_H_ #define BLINK_PUN_H_ #include "blink/types.h" union FloatPun { float f; u32 i; }; union DoublePun { double f; u64 i; }; union FloatVectorPun { union FloatPun u[4]; float f[4]; }; union DoubleVectorPun { union DoublePun u[2]; double f[2]; }; #endif /* BLINK_PUN_H_ */ ================================================ FILE: blink/random.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/random.h" #include #include #include #include #include #include #include "blink/assert.h" #include "blink/errno.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/types.h" #include "blink/util.h" #ifdef HAVE_KERN_ARND #include #endif #ifdef HAVE_SYS_GETRANDOM #include #endif #ifdef HAVE_RTLGENRANDOM #include bool __stdcall SystemFunction036(void *, __LONG32); #endif #if !defined(HAVE_SYS_GETRANDOM) && \ (defined(HAVE_GETRANDOM) || defined(HAVE_SYS_GETENTROPY)) #include #endif #ifdef HAVE_DEV_URANDOM static ssize_t GetDevRandom(char *p, size_t n) { int fd; ssize_t rc; if ((fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) == -1) return -1; rc = read(fd, p, n); close(fd); return rc; } #endif #ifdef HAVE_KERN_ARND static ssize_t GetKernArnd(char *p, size_t n) { size_t m, i = 0; int cmd[2] = {CTL_KERN, KERN_ARND}; for (;;) { m = n - i; if (sysctl(cmd, 2, p + i, &m, 0, 0) != -1) { if ((i += m) == n) { return n; } } else { return i ? i : -1; } } } #endif static ssize_t GetWeakRandom(char *p, size_t n) { u64 word; size_t i, j; static bool once; static u64 state; if (!once) { LOGF("generating weak random data"); state = time(0); once = true; } for (i = 0; i < n;) { word = Vigna(&state); for (j = 0; j < 8 && i < n; ++i, ++j) { p[i] = word; word >>= 8; } } return n; } // "The user of getrandom() must always check the return value, to // determine whether either an error occurred or fewer bytes than // requested were returned. In the case where GRND_RANDOM is not // specified and buflen is less than or equal to 256, a return of fewer // bytes than requested should never happen, but the careful programmer // will check for this anyway!" -Quoth the Linux Programmer's Manual § // getrandom(). ssize_t GetRandom(void *p, size_t n, int flags) { #ifdef GRND_RANDOM _Static_assert(GRND_RANDOM == GRND_RANDOM_LINUX, ""); #endif #ifdef GRND_NONBLOCK _Static_assert(GRND_NONBLOCK == GRND_NONBLOCK_LINUX, ""); #endif #ifdef HAVE_SYS_GETRANDOM // we need to favor SYS_getrandom right now since our ./configure // script isn't smart enough to accommodate our bundled toolchain return syscall(SYS_getrandom, p, n, flags); #elif defined(HAVE_GETRANDOM) return getrandom(p, n, flags); #elif defined(HAVE_RTLGENRANDOM) return SystemFunction036(p, n) ? n : -1; #elif defined(HAVE_GETENTROPY) || defined(HAVE_SYS_GETENTROPY) return !getentropy((char *)p, MIN(256, n)) ? n : -1; #elif defined(HAVE_KERN_ARND) return GetKernArnd((char *)p, n); #elif defined(HAVE_DEV_URANDOM) return GetDevRandom((char *)p, n); #else return GetWeakRandom((char *)p, n); #endif } ================================================ FILE: blink/random.h ================================================ #ifndef BLINK_RANDOM_H_ #define BLINK_RANDOM_H_ #include ssize_t GetRandom(void *, size_t, int); #endif /* BLINK_RANDOM_H_ */ ================================================ FILE: blink/rde.h ================================================ #ifndef BLINK_RDE_H_ #define BLINK_RDE_H_ #define kRexbRmMask 000000003600 #define RexbRm(x) ((x & kRexbRmMask) >> 007) #define kRexrRegMask 000000000017 #define RexrReg(x) ((x & kRexrRegMask) >> 000) #define kOplengthMask 00007400000000000000000 #define Oplength(x) ((x & kOplengthMask) >> 065) #define kRegRexbSrmMask 00000170000 #define RexbSrm(x) ((x & kRegRexbSrmMask) >> 014) #define Rex(x) ((x & 000000000020) >> 004) #define Osz(x) ((x & 000000000040) >> 005) #define Asz(x) ((x & 000010000000) >> 025) #define Srm(x) ((x & 000000070000) >> 014) #define Rexr(x) ((x & 000000000010) >> 003) #define Rexw(x) ((x & 000000000100) >> 006) #define Rexx(x) ((x & 000000400000) >> 021) #define Rexb(x) ((x & 000000002000) >> 012) #define Sego(x) ((x & 000007000000) >> 022) #define Ymm(x) ((x & 010000000000) >> 036) #define RegLog2(x) ((x & 006000000000) >> 034) #define ModrmRm(x) ((x & 000000001600) >> 007) #define ModrmReg(x) ((x & 000000000007) >> 000) #define ModrmSrm(x) ((x & 000000070000) >> 014) #define ModrmMod(x) ((x & 000060000000) >> 026) #define RexRexr(x) ((x & 000000000037) >> 000) #define RexRexb(x) ((x & 000000007600) >> 007) #define RexRexbSrm(x) ((x & 000000370000) >> 014) #define Modrm(x) (ModrmMod(x) << 6 | ModrmReg(x) << 3 | ModrmRm(x)) #define SibBase(x) ((x & 00000000000340000000000) >> 040) #define SibIndex(x) ((x & 00000000003400000000000) >> 043) #define SibScale(x) ((x & 00000000014000000000000) >> 046) #define Opcode(x) ((x & 00000007760000000000000) >> 050) #define Opmap(x) ((x & 00000070000000000000000) >> 060) #define Mopcode(x) ((x & 00000077760000000000000) >> 050) #define Rep(x) ((x & 00000300000000000000000) >> 063) #define WordLog2(x) ((x & 00030000000000000000000) >> 071) #define Vreg(x) ((x & 01700000000000000000000) >> 074) #define Bite(x) (~ModrmSrm(x) & 1) #define RexbBase(x) (Rexb(x) << 3 | SibBase(x)) #define IsByteOp(x) (~Srm(rde) & 1) #define SibExists(x) (ModrmRm(x) == 4) #define IsModrmRegister(x) (ModrmMod(x) == 3) #define SibHasIndex(x) (SibIndex(x) != 4 || Rexx(x)) #define SibHasBase(x) (SibBase(x) != 5 || ModrmMod(x)) #define SibIsAbsolute(x) (!SibHasBase(x) && !SibHasIndex(x)) #define IsRipRelative(x) (Eamode(x) && ModrmRm(x) == 5 && !ModrmMod(x)) #endif /* BLINK_RDE_H_ */ ================================================ FILE: blink/rdrand.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/assert.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/random.h" #include "blink/thread.h" #include "blink/util.h" #define RESEED_INTERVAL 16 static struct Rdrand { pthread_mutex_t_ lock; u64 state; unsigned count; } g_rdrand = { .lock = PTHREAD_MUTEX_INITIALIZER_, }; static void OpRand(P, u64 x) { WriteRegister(rde, RegRexbRm(m, rde), x); m->flags = SetFlag(m->flags, FLAGS_CF, true); } void OpRdrand(P) { LOCK(&g_rdrand.lock); if (!(g_rdrand.count++ % RESEED_INTERVAL)) { unassert(GetRandom(&g_rdrand.state, 8, 0) == 8); } OpRand(A, Vigna(&g_rdrand.state)); UNLOCK(&g_rdrand.lock); } void OpRdseed(P) { u64 x; unassert(GetRandom(&x, 8, 0) == 8); OpRand(A, x); } ================================================ FILE: blink/readansi.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #ifdef __EMSCRIPTEN__ #include #endif #include "blink/builtin.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/thompike.h" #include "blink/util.h" #include "blink/vfs.h" ssize_t readansi(int fd, char *buf, size_t size) { u8 c; int rc, i, j; enum { kAscii, kUtf8, kEsc, kCsi, kSs } t; if (size) buf[0] = 0; for (j = i = 0, t = kAscii;;) { if (i + 2 >= size) { errno = ENOMEM; return -1; } if ((rc = VfsRead(fd, &c, 1)) != 1) { if (rc == -1 && errno == EINTR && i) { continue; } if (rc == -1 && errno == EAGAIN) { #ifdef __EMSCRIPTEN__ emscripten_sleep(50); #else struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; VfsPoll(&pfd, 1, 0); #endif continue; } return rc; } buf[i++] = c; buf[i] = 0; switch (t) { case kAscii: if (c < 0200) { if (c == 033) { t = kEsc; } else { return i; } } else if (c >= 0300) { t = kUtf8; j = ThomPikeLen(c) - 1; } break; case kUtf8: if (!--j) return i; break; case kEsc: switch (c) { case '[': t = kCsi; break; case 'N': case 'O': t = kSs; break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: break; default: return i; } break; case kCsi: switch (c) { case ':': case ';': case '<': case '=': case '>': case '?': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: return i; } break; case kSs: return i; default: __builtin_unreachable(); } } } ================================================ FILE: blink/realpath.c ================================================ /*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ │ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ ╚──────────────────────────────────────────────────────────────────────────────╝ │ │ │ Musl Libc │ │ Copyright © 2005-2014 Rich Felker, et al. │ │ │ │ Permission is hereby granted, free of charge, to any person obtaining │ │ a copy of this software and associated documentation files (the │ │ "Software"), to deal in the Software without restriction, including │ │ without limitation the rights to use, copy, modify, merge, publish, │ │ distribute, sublicense, and/or sell copies of the Software, and to │ │ permit persons to whom the Software is furnished to do so, subject to │ │ the following conditions: │ │ │ │ The above copyright notice and this permission notice shall be │ │ included in all copies or substantial portions of the Software. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ │ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ │ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ │ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ │ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ │ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ │ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ │ │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include "blink/limits.h" #include "blink/util.h" // clang-format off static size_t slash_len(const char *s) { const char *s0 = s; while (*s == '/') s++; return s-s0; } char *realpath_(const char *filename, char *resolved) { ssize_t k; char stack[PATH_MAX+1]; char output[PATH_MAX]; size_t p, q, l, l0, cnt=0, nup=0; int check_dir=0; if (!filename) { errno = EINVAL; return 0; } l = strnlen(filename, sizeof stack); if (!l) { errno = ENOENT; return 0; } if (l >= PATH_MAX) goto toolong; p = sizeof stack - l - 1; q = 0; memcpy(stack+p, filename, l+1); /* Main loop. Each iteration pops the next part from stack of * remaining path components and consumes any slashes that follow. * If not a link, it's moved to output; if a link, contents are * pushed to the stack. */ restart: for (; ; p+=slash_len(stack+p)) { /* If stack starts with /, the whole component is / or // * and the output state must be reset. */ if (stack[p] == '/') { check_dir=0; nup=0; q=0; output[q++] = '/'; p++; /* Initial // is special. */ if (stack[p] == '/' && stack[p+1] != '/') output[q++] = '/'; continue; } char *z = strchrnul(stack+p, '/'); l0 = l = z-(stack+p); if (!l && !check_dir) break; /* Skip any . component but preserve check_dir status. */ if (l==1 && stack[p]=='.') { p += l; continue; } /* Copy next component onto output at least temporarily, to * call readlink, but wait to advance output position until * determining it's not a link. */ if (q && output[q-1] != '/') { if (!p) goto toolong; stack[--p] = '/'; l++; } if (q+l >= PATH_MAX) goto toolong; memcpy(output+q, stack+p, l); output[q+l] = 0; p += l; int up = 0; if (l0==2 && stack[p-2]=='.' && stack[p-1]=='.') { up = 1; /* Any non-.. path components we could cancel start * after nup repetitions of the 3-byte string "../"; * if there are none, accumulate .. components to * later apply to cwd, if needed. */ if (q <= 3*nup) { nup++; q += l; continue; } /* When previous components are already known to be * directories, processing .. can skip readlink. */ if (!check_dir) goto skip_readlink; } k = readlink(output, stack, p); if (k==p) goto toolong; if (!k) { errno = ENOENT; return 0; } if (k<0) { if (errno != EINVAL) return 0; skip_readlink: check_dir = 0; if (up) { while(q && output[q-1]!='/') q--; if (q>1 && (q>2 || output[0]!='/')) q--; continue; } if (l0) q += l; check_dir = stack[p]; continue; } if (++cnt == GetSymloopMax()) { errno = ELOOP; return 0; } /* If link contents end in /, strip any slashes already on * stack to avoid /->// or //->/// or spurious toolong. */ if (stack[k-1]=='/') while (stack[p]=='/') p++; p -= k; memmove(stack+p, stack, k); /* Skip the stack advancement in case we have a new * absolute base path. */ goto restart; } output[q] = 0; if (output[0] != '/') { if (!getcwd(stack, sizeof stack)) return 0; l = strlen(stack); /* Cancel any initial .. components. */ p = 0; while (nup--) { while(l>1 && stack[l-1]!='/') l--; if (l>1) l--; p += 2; if (p= PATH_MAX) goto toolong; memmove(output + l, output + p, q - p + 1); memcpy(output, stack, l); q = l + q-p; } if (resolved) { return (char *)memcpy(resolved, output, q+1); } else return strdup(output); toolong: errno = ENAMETOOLONG; return 0; } ================================================ FILE: blink/reset.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/flags.h" #include "blink/machine.h" #include "blink/stats.h" #define LDBL 3 #define RINT 0 static void ResetFpu(struct Machine *m) { #ifndef DISABLE_X87 long i; for (i = 0; i < 8; ++i) { m->fpu.st[i] = -NAN; } m->fpu.sw = 0; m->fpu.tw = -1; #endif // We diverge from System V ABI here since we don't have long double // support yet. We only support double precision when using x87 fpu. // // 8087 FPU Control Word // IM: Invalid Operation ───────────────┐ // DM: Denormal Operand ───────────────┐│ // ZM: Zero Divide ───────────────────┐││ // OM: Overflow ─────────────────────┐│││ // UM: Underflow ───────────────────┐││││ // PM: Precision ──────────────────┐│││││ // PC: Precision Control ───────┐ ││││││ // {float,∅,double,long double}│ ││││││ // RC: Rounding Control ──────┐ │ ││││││ // {even, →-∞, →+∞, →0} │┌┤ ││││││ // ┌┤││ ││││││ // d││││rr││││││ // 0b0000000000000000000001001111111 m->fpu.cw = 0x027f; } static void ResetSse(struct Machine *m) { // SSE CONTROL AND STATUS REGISTER // IE: Invalid Operation Flag ──────────────┐ // DE: Denormal Flag ──────────────────────┐│ // ZE: Divide-by-Zero Flag ───────────────┐││ // OE: Overflow Flag ────────────────────┐│││ // UE: Underflow Flag ──────────────────┐││││ // PE: Precision Flag ─────────────────┐│││││ // DAZ: Denormals Are Zeros ──────────┐││││││ // IM: Invalid Operation Mask ───────┐│││││││ // DM: Denormal Operation Mask ─────┐││││││││ // ZM: Divide-by-Zero Mask ────────┐│││││││││ // OM: Overflow Mask ─────────────┐││││││││││ // UM: Underflow Mask ───────────┐│││││││││││ // PM: Precision Mask ──────────┐││││││││││││ // RC: Rounding Control ───────┐│││││││││││││ // {even, →-∞, →+∞, →0} ││││││││││││││ // ┌┤│││││││││││││ // ┌───────────────┐│││││││││││││││ // │ reserved ││││││││││││││││ // 0b00000000000000000001111110000000 m->mxcsr = 0x1f80; memset(m->xmm, 0, sizeof(m->xmm)); } void ResetCpu(struct Machine *m) { m->faultaddr = 0; m->opcache->stashsize = 0; m->stashaddr = 0; m->writeaddr = 0; m->readaddr = 0; m->writesize = 0; m->readsize = 0; m->flags = 0; m->flags = SetFlag(m->flags, FLAGS_VF, 1); m->flags = SetFlag(m->flags, FLAGS_IOPL, 3); memset(m->beg, 0, sizeof(m->beg)); memset(m->bofram, 0, sizeof(m->bofram)); memset(&m->freelist, 0, sizeof(m->freelist)); ResetSse(m); ResetFpu(m); } void ResetTlb(struct Machine *m) { STATISTIC(++tlb_resets); memset(m->tlb, 0, sizeof(m->tlb)); m->opcache->codevirt = 0; m->opcache->codehost = 0; } void ResetInstructionCache(struct Machine *m) { STATISTIC(++icache_resets); memset(m->opcache->icache, 0, sizeof(m->opcache->icache)); m->opcache->codevirt = 0; m->opcache->codehost = 0; } ================================================ FILE: blink/signal.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/signal.h" #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/bitscan.h" #include "blink/endian.h" #include "blink/ldbl.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/syscall.h" #include "blink/thread.h" #include "blink/util.h" #include "blink/xlat.h" struct SignalFrame { u8 ret[8]; struct siginfo_linux si; struct ucontext_linux uc; struct fpstate_linux fp; }; bool IsSignalIgnoredByDefault(int sig) { return sig == SIGURG_LINUX || // sig == SIGCONT_LINUX || // sig == SIGCHLD_LINUX || // sig == SIGWINCH_LINUX; } bool IsSignalSerious(int sig) { return sig == SIGFPE_LINUX || // sig == SIGILL_LINUX || // sig == SIGBUS_LINUX || // sig == SIGQUIT_LINUX || // sig == SIGTRAP_LINUX || // sig == SIGSEGV_LINUX || // sig == SIGSTOP_LINUX || // sig == SIGKILL_LINUX; } void DeliverSignal(struct Machine *m, int sig, int code) { u64 sp; struct SignalFrame sf; if (IsMakingPath(g_machine)) AbandonPath(g_machine); memset(&sf, 0, sizeof(sf)); // capture the current state of the machine Write32(sf.si.signo, sig); Write32(sf.si.code, code); if (sig == SIGILL_LINUX || // sig == SIGFPE_LINUX || // sig == SIGSEGV_LINUX || // sig == SIGBUS_LINUX || // sig == SIGTRAP_LINUX) { Write64(sf.si.addr, m->faultaddr); SYS_LOGF("delivering %s {.si_code = %d, .si_addr = %#" PRIx64 "}", DescribeSignal(sig), code, m->faultaddr); } else { SYS_LOGF("delivering %s, {.si_code = %d}", DescribeSignal(sig), code); if (sig == SIGTRAP_LINUX) { Write64(sf.uc.trapno, m->trapno); } } Write64(sf.uc.sigmask, m->sigmask); memcpy(sf.uc.r8, m->r8, 8); memcpy(sf.uc.r9, m->r9, 8); memcpy(sf.uc.r10, m->r10, 8); memcpy(sf.uc.r11, m->r11, 8); memcpy(sf.uc.r12, m->r12, 8); memcpy(sf.uc.r13, m->r13, 8); memcpy(sf.uc.r14, m->r14, 8); memcpy(sf.uc.r15, m->r15, 8); memcpy(sf.uc.rdi, m->di, 8); memcpy(sf.uc.rsi, m->si, 8); memcpy(sf.uc.rbp, m->bp, 8); memcpy(sf.uc.rbx, m->bx, 8); memcpy(sf.uc.rdx, m->dx, 8); memcpy(sf.uc.rax, m->ax, 8); memcpy(sf.uc.rcx, m->cx, 8); memcpy(sf.uc.rsp, m->sp, 8); Write64(sf.uc.rip, m->ip); Write64(sf.uc.eflags, m->flags); Write16(sf.fp.cwd, m->fpu.cw); #ifndef DISABLE_X87 Write16(sf.fp.swd, m->fpu.sw); Write16(sf.fp.ftw, m->fpu.tw); Write16(sf.fp.fop, m->fpu.op); Write64(sf.fp.rip, m->fpu.ip); Write64(sf.fp.rdp, m->fpu.dp); { int i; for (i = 0; i < 8; ++i) { SerializeLdbl(sf.fp.st[i], m->fpu.st[i]); } } #endif memcpy(sf.fp.xmm, m->xmm, sizeof(sf.fp.xmm)); // set the thread signal mask to the one specified by the signal // handler. by default, the signal being delivered will be added // within the mask unless the guest program specifies SA_NODEFER m->sigmask |= Read64(m->system->hands[sig - 1].mask); if (~Read64(m->system->hands[sig - 1].flags) & SA_NODEFER_LINUX) { m->sigmask |= (u64)1 << (sig - 1); } SIG_LOGF("sigmask deliver %" PRIx64, m->sigmask); // if the guest setup a sigaltstack() and the signal handler used // SA_ONSTACK then use that alternative stack for signal handling // otherwise use the current stack, and do not touch the red zone // because gcc assumes that it owns the 128 bytes underneath rsp. if ((Read64(m->system->hands[sig - 1].flags) & SA_ONSTACK_LINUX) && !(Read32(m->sigaltstack.flags) & SS_DISABLE_LINUX)) { sp = Read64(m->sigaltstack.sp) + Read64(m->sigaltstack.size); if (Read32(m->sigaltstack.flags) & SS_AUTODISARM_LINUX) { Write32(m->sigaltstack.flags, Read32(m->sigaltstack.flags) & ~SS_AUTODISARM_LINUX); } } else { sp = Read64(m->sp); sp -= kRedzoneSize; } // put signal and machine state on the stack. the guest may change // these values to edit the program's non-signal handler cpu state _Static_assert(!(sizeof(struct siginfo_linux) & 15), ""); _Static_assert(!(sizeof(struct fpstate_linux) & 15), ""); _Static_assert(!(sizeof(struct ucontext_linux) & 15), ""); _Static_assert((sizeof(struct SignalFrame) & 15) == 8, ""); sp = ROUNDDOWN(sp, 16); sp -= sizeof(sf); unassert((sp & 15) == 8); SIG_LOGF("restorer is %" PRIx64, Read64(m->system->hands[sig - 1].restorer)); memcpy(sf.ret, m->system->hands[sig - 1].restorer, 8); Write64(sf.uc.fpstate, sp + offsetof(struct SignalFrame, fp)); SIG_LOGF("delivering signal @ %" PRIx64, sp); if (CopyToUserWrite(m, sp, &sf, sizeof(sf)) == -1) { LOGF("stack overflow delivering signal"); TerminateSignal(m, SIGSEGV_LINUX, m->segvcode); } // finally, call the signal handler using the sigaction arguments Put64(m->sp, sp); Put64(m->di, sig); Put64(m->si, sp + offsetof(struct SignalFrame, si)); Put64(m->dx, sp + offsetof(struct SignalFrame, uc)); SIG_LOGF("handler is %" PRIx64, Read64(m->system->hands[sig - 1].handler)); m->ip = Read64(m->system->hands[sig - 1].handler); } void SigRestore(struct Machine *m) { struct SignalFrame sf; // when the guest returns from the signal handler, it'll call a // pointer to the sa_restorer trampoline which is assumed to be // // __restore_rt: // mov $15,%rax // syscall // // which doesn't change SP, thus we can restore the SignalFrame // and load any change that the guest made to the machine state SYS_LOGF("rt_sigreturn(%#" PRIx64 ")", Read64(m->sp) - 8); unassert(!CopyFromUserRead(m, &sf, Read64(m->sp) - 8, sizeof(sf))); m->ip = Read64(sf.uc.rip); m->flags = Read64(sf.uc.eflags); m->sigmask = Read64(sf.uc.sigmask); SIG_LOGF("sigmask restore %" PRIx64, m->sigmask); memcpy(m->r8, sf.uc.r8, 8); memcpy(m->r9, sf.uc.r9, 8); memcpy(m->r10, sf.uc.r10, 8); memcpy(m->r11, sf.uc.r11, 8); memcpy(m->r12, sf.uc.r12, 8); memcpy(m->r13, sf.uc.r13, 8); memcpy(m->r14, sf.uc.r14, 8); memcpy(m->r15, sf.uc.r15, 8); memcpy(m->di, sf.uc.rdi, 8); memcpy(m->si, sf.uc.rsi, 8); memcpy(m->bp, sf.uc.rbp, 8); memcpy(m->bx, sf.uc.rbx, 8); memcpy(m->dx, sf.uc.rdx, 8); memcpy(m->ax, sf.uc.rax, 8); memcpy(m->cx, sf.uc.rcx, 8); m->fpu.cw = Read16(sf.fp.cwd); memcpy(m->sp, sf.uc.rsp, 8); #ifndef DISABLE_X87 m->fpu.sw = Read16(sf.fp.swd); m->fpu.tw = Read16(sf.fp.ftw); m->fpu.op = Read16(sf.fp.fop); m->fpu.ip = Read64(sf.fp.rip); m->fpu.dp = Read64(sf.fp.rdp); { int i; for (i = 0; i < 8; ++i) { m->fpu.st[i] = DeserializeLdbl(sf.fp.st[i]); } } #endif memcpy(m->xmm, sf.fp.xmm, sizeof(sf.fp.xmm)); m->restored = true; atomic_store_explicit(&m->attention, true, memory_order_release); } static int ConsumeSignalImpl(struct Machine *m, int *delivered, bool *restart) { int sig; i64 handler; u64 signals; if (delivered) *delivered = 0; if (restart) *restart = true; // look for a pending signal that isn't currently masked while ((signals = m->signals & ~m->sigmask)) { sig = bsr(signals) + 1; m->signals &= ~((u64)1 << (sig - 1)); handler = Read64(m->system->hands[sig - 1].handler); if (handler == SIG_DFL_LINUX) { if (IsSignalIgnoredByDefault(sig)) { SYS_LOGF("ignoring %s", DescribeSignal(sig)); return 0; } else { SIG_LOGF("default action is to terminate upon signal %s", DescribeSignal(sig)); return sig; } } else if (handler == SIG_IGN_LINUX) { SYS_LOGF("explicitly ignoring %s", DescribeSignal(sig)); return 0; } if (delivered) { *delivered = sig; } if (restart) { *restart = !!(Read64(m->system->hands[sig - 1].flags) & SA_RESTART_LINUX); } DeliverSignal(m, sig, SI_KERNEL_LINUX); return 0; } return 0; } int ConsumeSignal(struct Machine *m, int *delivered, bool *restart) { int rc; if (m->metal) return 0; LOCK(&m->system->sig_lock); rc = ConsumeSignalImpl(m, delivered, restart); UNLOCK(&m->system->sig_lock); return rc; } void EnqueueSignal(struct Machine *m, int sig) { if (m && (1 <= sig && sig <= 64)) { m->signals |= 1ul << (sig - 1); if ((m->signals & ~m->sigmask)) { atomic_store_explicit(&m->attention, true, memory_order_release); } } } void CheckForSignals(struct Machine *m) { int sig; if (atomic_load_explicit(&m->killed, memory_order_acquire)) { SysExit(m, 0); #ifndef DISABLE_JIT } else if (m->selfmodifying) { FlushSmcQueue(m); m->selfmodifying = false; #endif } else if (m->signals & ~m->sigmask) { if ((sig = ConsumeSignal(m, 0, 0))) { TerminateSignal(m, sig, 0); } } else { atomic_store_explicit(&m->attention, false, memory_order_relaxed); } } ================================================ FILE: blink/signal.h ================================================ #ifndef BLINK_SIGNAL_H_ #define BLINK_SIGNAL_H_ #include "blink/machine.h" bool IsSignalSerious(int); bool IsSignalQueueable(int); void SigRestore(struct Machine *); bool IsSignalIgnoredByDefault(int); void OnSignal(int, siginfo_t *, void *); void EnqueueSignal(struct Machine *, int); void DeliverSignal(struct Machine *, int, int); void TerminateSignal(struct Machine *, int, int); int ConsumeSignal(struct Machine *, int *, bool *); void DeliverSignalToUser(struct Machine *, int, int); #endif /* BLINK_SIGNAL_H_ */ ================================================ FILE: blink/sigwinch.h ================================================ #ifndef BLINK_SIGWINCH_H_ #define BLINK_SIGWINCH_H_ #include #ifndef SIGWINCH // SIGWINCH has the same magic number on all platforms. Yet for some // reason, platforms are stubborn about defining it in their headers #define SIGWINCH 28 #endif #endif /* BLINK_SIGWINCH_H_ */ ================================================ FILE: blink/smc.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/assert.h" #include "blink/builtin.h" #include "blink/flag.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/stats.h" #include "blink/tunables.h" #include "blink/util.h" #include "blink/xlat.h" #ifndef DISABLE_JIT // @asyncsignalsafe static int ProtectHostPages(struct System *s, i64 vaddr, i64 size, int prot) { i64 a, b; unassert(HasLinearMapping()); a = ROUNDDOWN(vaddr, FLAG_pagesize); b = ROUNDUP(vaddr + size, FLAG_pagesize); return mprotect(ToHost(a), b - a, prot); } static int ProtectSelfModifyingCode(struct System *s, i64 vaddr, i64 size) { MEM_LOGF("ProtectSelfModifyingCode(%#" PRIx64 ", %#" PRIx64 ")", vaddr, size); return ProtectHostPages(s, vaddr, size, PROT_READ); } // @asyncsignalsafe static int UnprotectSelfModifyingCode(struct System *s, i64 vaddr, i64 size) { MEM_LOGF("UnprotectSelfModifyingCode(%#" PRIx64 ", %#" PRIx64 ")", vaddr, size); return ProtectHostPages(s, vaddr, size, PROT_READ | PROT_WRITE); } // @asyncsignalsafe bool IsPageInSmcQueue(struct Machine *m, i64 page) { int i; i64 tmp; page &= -4096; STATISTIC(++smc_checks); for (i = 0; i < kSmcQueueSize; ++i) { if ((tmp = m->smcqueue.p[i]) == page) { if (i) { m->smcqueue.p[i - 0] = m->smcqueue.p[i - 1]; m->smcqueue.p[i - 1] = tmp; } return true; } } return false; } // @asyncsignalsafe void AddPageToSmcQueue(struct Machine *m, i64 page) { int i; page &= -4096; for (i = 0; i < kSmcQueueSize; ++i) { if (!m->smcqueue.p[i]) { STATISTIC(++smc_enqueued); m->smcqueue.p[i] = page; m->selfmodifying = true; atomic_store_explicit(&m->attention, true, memory_order_release); return; } } ERRF("self-modifying code page queue exhausted"); Abort(); } void FlushSmcQueue(struct Machine *m) { int i; i64 page; unassert(m->selfmodifying); STATISTIC(++smc_flushes); for (i = 0; i < kSmcQueueSize; ++i) { if ((page = m->smcqueue.p[i])) { m->smcqueue.p[i] = 0; if (!IsJitDisabled(&m->system->jit)) { if (HasLinearMapping()) { unassert(!ProtectSelfModifyingCode(m->system, page, 1)); } ResetJitPage(&m->system->jit, page); } if (IsMakingPath(m) && (m->path.start & -4096) == (page & -4096)) { AbandonPath(m); } } } } i64 ProtectRwxMemory(struct System *s, i64 rc, i64 virt, i64 size, long pagesize, int prot) { i64 a, b; unassert(HasLinearMapping()); unassert(!IsJitDisabled(&s->jit)); if (rc == -1) return -1; if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) { a = ROUNDDOWN(virt, 4096); b = ROUNDUP(virt + size, 4096); // we can only do proper smc invalidation on the host page aligned // subset of the mmap()'d or mprotect()'d executable memory region a = ROUNDUP(a, pagesize); b = ROUNDDOWN(b, pagesize); if (b > a) { unassert(!ProtectSelfModifyingCode(s, a, b - a)); } } return rc; } // @asyncsignalsafe bool IsSelfModifyingCodeSegfault(struct Machine *m, const siginfo_t *si) { u64 pte; i64 vaddr; SIG_LOGF("IsSelfModifyingCodeSegfault()"); unassert(m->system->loaded); if (si->si_signo != SIGSEGV) return false; if (si->si_code != SEGV_ACCERR) return false; vaddr = ConvertHostToGuestAddress(m->system, si->si_addr, &pte); SIG_LOGF("ConvertHostToGuestAddress(%p) -> %#" PRIx64, si->si_addr, vaddr); if ((pte & (PAGE_V | PAGE_U | PAGE_RW | PAGE_XD)) != (PAGE_V | PAGE_U | PAGE_RW)) { return false; } STATISTIC(++smc_segfaults); if (UnprotectSelfModifyingCode(m->system, vaddr, 1)) { ERRF("failed to unprotect self modifying code"); return false; } if (!IsPageInSmcQueue(m, vaddr)) { AddPageToSmcQueue(m, vaddr); } return true; } #endif /* DISABLE_JIT */ ================================================ FILE: blink/sse.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/sse.h" #include #include "blink/case.h" #include "blink/endian.h" #include "blink/intrin.h" #include "blink/likely.h" #include "blink/machine.h" #include "blink/macros.h" static void MmxPaddusb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = MIN(255, x[i] + y[i]); } } static void MmxPsubusb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = MIN(255, MAX(0, x[i] - y[i])); } } static void MmxPsubsb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = MAX(-128, MIN(127, (i8)x[i] - (i8)y[i])); } } static void MmxPaddsb(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 8; ++i) { x[i] = MAX(-128, MIN(127, (i8)x[i] + (i8)y[i])); } } static void MmxPmulhrsw(u8 x[8], const u8 y[8]) { i16 a, b; unsigned i; for (i = 0; i < 4; ++i) { a = Get16(x + i * 2); b = Get16(y + i * 2); Put16(x + i * 2, (((a * b) >> 14) + 1) >> 1); } } static void MmxPmaddubsw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, MAX(-32768, MIN(32767, (x[i * 2 + 0] * (i8)y[i * 2 + 0] + x[i * 2 + 1] * (i8)y[i * 2 + 1])))); } } static void MmxPsraw(u8 x[8], unsigned k) { unsigned i; if (k > 15) k = 15; for (i = 0; i < 4; ++i) { Put16(x + i * 2, (i16)Get16(x + i * 2) >> k); } } static void MmxPsrad(u8 x[8], unsigned k) { unsigned i; if (k > 31) k = 31; for (i = 0; i < 2; ++i) { Put32(x + i * 4, (i32)Get32(x + i * 4) >> k); } } static void MmxPsrlw(u8 x[8], unsigned k) { unsigned i; if (k < 16) { for (i = 0; i < 4; ++i) { Put16(x + i * 2, Get16(x + i * 2) >> k); } } else { memset(x, 0, 8); } } static void MmxPsllw(u8 x[8], unsigned k) { unsigned i; if (k <= 15) { for (i = 0; i < 4; ++i) { Put16(x + i * 2, Get16(x + i * 2) << k); } } else { memset(x, 0, 8); } } static void MmxPsrld(u8 x[8], unsigned k) { unsigned i; if (k <= 31) { for (i = 0; i < 2; ++i) { Put32(x + i * 4, Get32(x + i * 4) >> k); } } else { memset(x, 0, 8); } } static void MmxPslld(u8 x[8], unsigned k) { unsigned i; if (k <= 31) { for (i = 0; i < 2; ++i) { Put32(x + i * 4, Get32(x + i * 4) << k); } } else { memset(x, 0, 8); } } static void MmxPsrlq(u8 x[8], unsigned k) { if (k <= 63) { Put64(x, Get64(x) >> k); } else { memset(x, 0, 8); } } static void MmxPsllq(u8 x[8], unsigned k) { if (k <= 63) { Put64(x, Get64(x) << k); } else { memset(x, 0, 8); } } static void MmxPslldq(u8 x[8], unsigned k) { u8 t[8]; unsigned i; if (k > 8) k = 8; for (i = 0; i < k; ++i) t[i] = 0; for (i = 0; i < 8 - k; ++i) t[k + i] = x[i]; memcpy(x, t, 8); } static void MmxPsrldq(u8 x[8], unsigned k) { u8 t[8]; if (k > 8) k = 8; memcpy(t, x + k, 8 - k); memset(t + (8 - k), 0, k); memcpy(x, t, 8); } static void MmxPalignr(u8 x[8], const u8 y[8], unsigned k) { u8 t[24]; memcpy(t, y, 8); memcpy(t + 8, x, 8); memset(t + 16, 0, 8); memcpy(x, t + MIN(k, 16), 8); } static void MmxPsubd(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 2; ++i) { Put32(x + i * 4, Get32(x + i * 4) - Get32(y + i * 4)); } } static void MmxPaddd(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 2; ++i) { Put32(x + i * 4, Get32(x + i * 4) + Get32(y + i * 4)); } } static void MmxPaddq(u8 x[8], const u8 y[8]) { Put64(x, Get64(x) + Get64(y)); } static void MmxPsubq(u8 x[8], const u8 y[8]) { Put64(x, Get64(x) - Get64(y)); } static void MmxPsubusw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, MIN(65535, MAX(0, Get16(x + i * 2) - Get16(y + i * 2)))); } } static void MmxPminsw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, MIN((i16)Get16(x + i * 2), (i16)Get16(y + i * 2))); } } static void MmxPmaxsw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, MAX((i16)Get16(x + i * 2), (i16)Get16(y + i * 2))); } } static void MmxPackuswb(u8 x[8], const u8 y[8]) { u8 t[8]; unsigned i; for (i = 0; i < 4; ++i) { t[i + 0] = MIN(255, MAX(0, (i16)Get16(x + i * 2))); } for (i = 0; i < 4; ++i) { t[i + 4] = MIN(255, MAX(0, (i16)Get16(y + i * 2))); } memcpy(x, t, 8); } static void MmxPacksswb(u8 x[8], const u8 y[8]) { unsigned i; u8 t[8]; for (i = 0; i < 4; ++i) { t[i + 0] = MAX(-128, MIN(127, (i16)Get16(x + i * 2))); } for (i = 0; i < 4; ++i) { t[i + 4] = MAX(-128, MIN(127, (i16)Get16(y + i * 2))); } memcpy(x, t, 8); } static void MmxPackssdw(u8 x[8], const u8 y[8]) { u8 t[8]; unsigned i; for (i = 0; i < 2; ++i) { Put16(t + i * 2 + 0, MAX(-32768, MIN(32767, (i32)Get32(x + i * 4)))); } for (i = 0; i < 2; ++i) { Put16(t + i * 2 + 4, MAX(-32768, MIN(32767, (i32)Get32(y + i * 4)))); } memcpy(x, t, 8); } static void MmxPcmpgtd(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 2; ++i) { Put32(x + i * 4, -((i32)Get32(x + i * 4) > (i32)Get32(y + i * 4))); } } static void MmxPcmpeqd(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 2; ++i) { Put32(x + i * 4, -(Get32(x + i * 4) == Get32(y + i * 4))); } } static void MmxPsrawv(u8 x[8], const u8 y[8]) { u64 k; unsigned i; k = Get64(y); if (k > 15) k = 15; for (i = 0; i < 4; ++i) { Put16(x + i * 2, (i16)Get16(x + i * 2) >> k); } } static void MmxPsradv(u8 x[8], const u8 y[8]) { u64 k; unsigned i; k = Get64(y); if (k > 31) k = 31; for (i = 0; i < 2; ++i) { Put32(x + i * 4, (i32)Get32(x + i * 4) >> k); } } static void MmxPsrlwv(u8 x[8], const u8 y[8]) { u64 k; unsigned i; k = Get64(y); if (k < 16) { for (i = 0; i < 4; ++i) { Put16(x + i * 2, Get16(x + i * 2) >> k); } } else { memset(x, 0, 8); } } static void MmxPsllwv(u8 x[8], const u8 y[8]) { u64 k; unsigned i; k = Get64(y); if (k < 16) { for (i = 0; i < 4; ++i) { Put16(x + i * 2, Get16(x + i * 2) << k); } } else { memset(x, 0, 8); } } static void MmxPsrldv(u8 x[8], const u8 y[8]) { u64 k; unsigned i; k = Get64(y); if (k < 32) { for (i = 0; i < 2; ++i) { Put32(x + i * 4, Get32(x + i * 4) >> k); } } else { memset(x, 0, 8); } } static void MmxPslldv(u8 x[8], const u8 y[8]) { u64 k; unsigned i; k = Get64(y); if (k < 32) { for (i = 0; i < 2; ++i) { Put32(x + i * 4, Get32(x + i * 4) << k); } } else { memset(x, 0, 8); } } static void MmxPsrlqv(u8 x[8], const u8 y[8]) { u64 k; k = Get64(y); if (k < 64) { Put64(x, Get64(x) >> k); } else { memset(x, 0, 8); } } static void MmxPsllqv(u8 x[8], const u8 y[8]) { u64 k; k = Get64(y); if (k < 64) { Put64(x, Get64(x) << k); } else { memset(x, 0, 8); } } static void MmxPsadbw(u8 x[8], const u8 y[8]) { unsigned i, s, t; for (s = i = 0; i < 4; ++i) { s += ABS(x[i] - y[i]); } for (t = 0; i < 8; ++i) { t += ABS(x[i] - y[i]); } Put32(x + 0, s); Put32(x + 4, t); } static void MmxPmaddwd(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 2; ++i) { Put32(x + i * 4, ((i16)Get16(x + i * 4 + 0) * (i16)Get16(y + i * 4 + 0) + (i16)Get16(x + i * 4 + 2) * (i16)Get16(y + i * 4 + 2))); } } static void MmxPmulhuw(u8 x[8], const u8 y[8]) { u32 v; unsigned i; for (i = 0; i < 4; ++i) { v = Get16(x + i * 2); v *= Get16(y + i * 2); v >>= 16; Put16(x + i * 2, v); } } static void MmxPmuludq(u8 x[8], const u8 y[8]) { Put64(x, (u64)Get32(x) * Get32(y)); } static void MmxPmulld(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 2; ++i) { Put32(x + i * 4, Get32(x + i * 4) * Get32(y + i * 4)); } } static void MmxPshufb(u8 x[8], const u8 y[8]) { unsigned i; u8 t[8]; for (i = 0; i < 8; ++i) { t[i] = (y[i] & 128) ? 0 : x[y[i] & 7]; } memcpy(x, t, 8); } static void MmxPsignb(u8 x[8], const u8 y[8]) { unsigned i; int v; for (i = 0; i < 8; ++i) { v = (i8)y[i]; if (!v) { x[i] = 0; } else if (v < 0) { x[i] = -(i8)x[i]; } } } static void MmxPsignw(u8 x[8], const u8 y[8]) { unsigned i; int v; for (i = 0; i < 4; ++i) { v = (i16)Get16(y + i * 2); if (!v) { Put16(x + i * 2, 0); } else if (v < 0) { Put16(x + i * 2, -(i16)Get16(x + i * 2)); } } } static void MmxPsignd(u8 x[8], const u8 y[8]) { unsigned i; i32 v; for (i = 0; i < 2; ++i) { v = Get32(y + i * 4); if (!v) { Put32(x + i * 4, 0); } else if (v < 0) { Put32(x + i * 4, -Get32(x + i * 4)); } } } static void MmxPabsw(u8 x[8], const u8 y[8]) { unsigned i; for (i = 0; i < 4; ++i) { Put16(x + i * 2, ABS((i16)Get16(y + i * 2))); } } static void MmxPabsd(u8 x[8], const u8 y[8]) { i32 v; unsigned i; for (i = 0; i < 2; ++i) { v = Get32(y + i * 4); Put32(x + i * 4, v >= 0 ? v : -(u32)v); } } static void MmxPhaddw(u8 x[8], const u8 y[8]) { u8 t[8]; Put16(t + 0 * 2, Get16(x + 0 * 2) + Get16(x + 1 * 2)); Put16(t + 1 * 2, Get16(x + 2 * 2) + Get16(x + 3 * 2)); Put16(t + 2 * 2, Get16(y + 0 * 2) + Get16(y + 1 * 2)); Put16(t + 3 * 2, Get16(y + 2 * 2) + Get16(y + 3 * 2)); memcpy(x, t, 8); } static void MmxPhsubw(u8 x[8], const u8 y[8]) { u8 t[8]; Put16(t + 0 * 2, Get16(x + 0 * 2) - Get16(x + 1 * 2)); Put16(t + 1 * 2, Get16(x + 2 * 2) - Get16(x + 3 * 2)); Put16(t + 2 * 2, Get16(y + 0 * 2) - Get16(y + 1 * 2)); Put16(t + 3 * 2, Get16(y + 2 * 2) - Get16(y + 3 * 2)); memcpy(x, t, 8); } static void MmxPhaddd(u8 x[8], const u8 y[8]) { u8 t[8]; Put32(t + 0 * 4, Get32(x + 0 * 4) + Get32(x + 1 * 4)); Put32(t + 1 * 4, Get32(y + 0 * 4) + Get32(y + 1 * 4)); memcpy(x, t, 8); } static void MmxPhsubd(u8 x[8], const u8 y[8]) { u8 t[8]; Put32(t + 0 * 4, Get32(x + 0 * 4) - Get32(x + 1 * 4)); Put32(t + 1 * 4, Get32(y + 0 * 4) - Get32(y + 1 * 4)); memcpy(x, t, 8); } static void MmxPunpcklbw(u8 x[8], const u8 y[8]) { x[7] = y[3]; x[6] = x[3]; x[5] = y[2]; x[4] = x[2]; x[3] = y[1]; x[2] = x[1]; x[1] = y[0]; x[0] = x[0]; } static void MmxPunpckhbw(u8 x[8], const u8 y[8]) { x[0] = x[4]; x[1] = y[4]; x[2] = x[5]; x[3] = y[5]; x[4] = x[6]; x[5] = y[6]; x[6] = x[7]; x[7] = y[7]; } static void MmxPunpcklwd(u8 x[8], const u8 y[8]) { x[6] = y[2]; x[7] = y[3]; x[4] = x[2]; x[5] = x[3]; x[2] = y[0]; x[3] = y[1]; x[0] = x[0]; x[1] = x[1]; } static void MmxPunpckldq(u8 x[8], const u8 y[8]) { x[4] = y[0]; x[5] = y[1]; x[6] = y[2]; x[7] = y[3]; x[0] = x[0]; x[1] = x[1]; x[2] = x[2]; x[3] = x[3]; } static void MmxPunpckhwd(u8 x[8], const u8 y[8]) { x[0] = x[4]; x[1] = x[5]; x[2] = y[4]; x[3] = y[5]; x[4] = x[6]; x[5] = x[7]; x[6] = y[6]; x[7] = y[7]; } static void MmxPunpckhdq(u8 x[8], const u8 y[8]) { x[0] = x[4]; x[1] = x[5]; x[2] = x[6]; x[3] = x[7]; x[4] = y[4]; x[5] = y[5]; x[6] = y[6]; x[7] = y[7]; } static void MmxPunpcklqdq(u8 x[8], const u8 y[8]) { } static void MmxPunpckhqdq(u8 x[8], const u8 y[8]) { } static void SsePslldq(u8 x[16], unsigned k) { u8 t[16]; unsigned i; if (k > 16) k = 16; for (i = 0; i < k; ++i) t[i] = 0; for (i = 0; i < 16 - k; ++i) t[k + i] = x[i]; memcpy(x, t, 16); } static void SsePsrldq(u8 x[16], unsigned k) { u8 t[16]; if (k > 16) k = 16; memcpy(t, x + k, 16 - k); memset(t + (16 - k), 0, k); memcpy(x, t, 16); } static void SsePalignr(u8 x[16], const u8 y[16], unsigned k) { u8 t[48]; memcpy(t, y, 16); memcpy(t + 16, x, 16); memset(t + 32, 0, 16); memcpy(x, t + MIN(k, 32), 16); } static void SsePsubd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psubd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; for (i = 0; i < 4; ++i) { Put32(x + i * 4, Get32(x + i * 4) - Get32(y + i * 4)); } #endif } static void SsePaddd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("paddd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; for (i = 0; i < 4; ++i) { Put32(x + i * 4, Get32(x + i * 4) + Get32(y + i * 4)); } #endif } static void SsePaddq(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("paddq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; for (i = 0; i < 2; ++i) { Put64(x + i * 8, Get64(x + i * 8) + Get64(y + i * 8)); } #endif } static void SsePsubq(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psubq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; for (i = 0; i < 2; ++i) { Put64(x + i * 8, Get64(x + i * 8) - Get64(y + i * 8)); } #endif } static void SsePackuswb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("packuswb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; u8 t[16]; for (i = 0; i < 8; ++i) { t[i + 0] = MIN(255, MAX(0, (i16)Get16(x + i * 2))); } for (i = 0; i < 8; ++i) { t[i + 8] = MIN(255, MAX(0, (i16)Get16(y + i * 2))); } memcpy(x, t, 16); #endif } static void SsePacksswb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("packsswb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; u8 t[16]; for (i = 0; i < 8; ++i) { t[i + 0] = MAX(-128, MIN(127, (i16)Get16(x + i * 2))); } for (i = 0; i < 8; ++i) { t[i + 8] = MAX(-128, MIN(127, (i16)Get16(y + i * 2))); } memcpy(x, t, 16); #endif } static void SsePackssdw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("packssdw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; u8 t[16]; for (i = 0; i < 4; ++i) { Put16(t + i * 2 + 0, MAX(-32768, MIN(32767, (i32)Get32(x + i * 4)))); } for (i = 0; i < 4; ++i) { Put16(t + i * 2 + 8, MAX(-32768, MIN(32767, (i32)Get32(y + i * 4)))); } memcpy(x, t, 16); #endif } static void SsePsadbw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psadbw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i, s, t; for (s = i = 0; i < 8; ++i) s += ABS(x[i] - y[i]); for (t = 0; i < 16; ++i) t += ABS(x[i] - y[i]); Put64(x + 0, s); Put64(x + 8, t); #endif } static void SsePmuludq(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmuludq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; for (i = 0; i < 2; ++i) { Put64(x + i * 8, (u64)Get32(x + i * 8) * Get32(y + i * 8)); } #endif } static void SsePshufb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pshufb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else u8 t[16]; unsigned i; for (i = 0; i < 16; ++i) { t[i] = (y[i] & 128) ? 0 : x[y[i] & 15]; } memcpy(x, t, 16); #endif } static void SsePhaddd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("phaddd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else u8 t[16]; Put32(t + 0 * 4, Get32(x + 0 * 4) + Get32(x + 1 * 4)); Put32(t + 1 * 4, Get32(x + 2 * 4) + Get32(x + 3 * 4)); Put32(t + 2 * 4, Get32(y + 0 * 4) + Get32(y + 1 * 4)); Put32(t + 3 * 4, Get32(y + 2 * 4) + Get32(y + 3 * 4)); memcpy(x, t, 16); #endif } static void SsePhsubd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("phsubd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else u8 t[16]; Put32(t + 0 * 4, Get32(x + 0 * 4) - Get32(x + 1 * 4)); Put32(t + 1 * 4, Get32(x + 2 * 4) - Get32(x + 3 * 4)); Put32(t + 2 * 4, Get32(y + 0 * 4) - Get32(y + 1 * 4)); Put32(t + 3 * 4, Get32(y + 2 * 4) - Get32(y + 3 * 4)); memcpy(x, t, 16); #endif } static void SsePhaddw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("phaddw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else u8 t[16]; Put16(t + 0 * 2, Get16(x + 0 * 2) + Get16(x + 1 * 2)); Put16(t + 1 * 2, Get16(x + 2 * 2) + Get16(x + 3 * 2)); Put16(t + 2 * 2, Get16(x + 4 * 2) + Get16(x + 5 * 2)); Put16(t + 3 * 2, Get16(x + 6 * 2) + Get16(x + 7 * 2)); Put16(t + 4 * 2, Get16(y + 0 * 2) + Get16(y + 1 * 2)); Put16(t + 5 * 2, Get16(y + 2 * 2) + Get16(y + 3 * 2)); Put16(t + 6 * 2, Get16(y + 4 * 2) + Get16(y + 5 * 2)); Put16(t + 7 * 2, Get16(y + 6 * 2) + Get16(y + 7 * 2)); memcpy(x, t, 16); #endif } static void SsePhsubw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("phsubw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else u8 t[16]; Put16(t + 0 * 2, Get16(x + 0 * 2) - Get16(x + 1 * 2)); Put16(t + 1 * 2, Get16(x + 2 * 2) - Get16(x + 3 * 2)); Put16(t + 2 * 2, Get16(x + 4 * 2) - Get16(x + 5 * 2)); Put16(t + 3 * 2, Get16(x + 6 * 2) - Get16(x + 7 * 2)); Put16(t + 4 * 2, Get16(y + 0 * 2) - Get16(y + 1 * 2)); Put16(t + 5 * 2, Get16(y + 2 * 2) - Get16(y + 3 * 2)); Put16(t + 6 * 2, Get16(y + 4 * 2) - Get16(y + 5 * 2)); Put16(t + 7 * 2, Get16(y + 6 * 2) - Get16(y + 7 * 2)); memcpy(x, t, 16); #endif } static void SsePunpcklbw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpcklbw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0xf] = y[0x7]; x[0xe] = x[0x7]; x[0xd] = y[0x6]; x[0xc] = x[0x6]; x[0xb] = y[0x5]; x[0xa] = x[0x5]; x[0x9] = y[0x4]; x[0x8] = x[0x4]; x[0x7] = y[0x3]; x[0x6] = x[0x3]; x[0x5] = y[0x2]; x[0x4] = x[0x2]; x[0x3] = y[0x1]; x[0x2] = x[0x1]; x[0x1] = y[0x0]; x[0x0] = x[0x0]; #endif } static void SsePunpckhbw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpckhbw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0x0] = x[0x8]; x[0x1] = y[0x8]; x[0x2] = x[0x9]; x[0x3] = y[0x9]; x[0x4] = x[0xa]; x[0x5] = y[0xa]; x[0x6] = x[0xb]; x[0x7] = y[0xb]; x[0x8] = x[0xc]; x[0x9] = y[0xc]; x[0xa] = x[0xd]; x[0xb] = y[0xd]; x[0xc] = x[0xe]; x[0xd] = y[0xe]; x[0xe] = x[0xf]; x[0xf] = y[0xf]; #endif } static void SsePunpcklwd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpcklwd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0xe] = y[0x6]; x[0xf] = y[0x7]; x[0xc] = x[0x6]; x[0xd] = x[0x7]; x[0xa] = y[0x4]; x[0xb] = y[0x5]; x[0x8] = x[0x4]; x[0x9] = x[0x5]; x[0x6] = y[0x2]; x[0x7] = y[0x3]; x[0x4] = x[0x2]; x[0x5] = x[0x3]; x[0x2] = y[0x0]; x[0x3] = y[0x1]; x[0x0] = x[0x0]; x[0x1] = x[0x1]; #endif } static void SsePunpckldq(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpckldq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0xc] = y[0x4]; x[0xd] = y[0x5]; x[0xe] = y[0x6]; x[0xf] = y[0x7]; x[0x8] = x[0x4]; x[0x9] = x[0x5]; x[0xa] = x[0x6]; x[0xb] = x[0x7]; x[0x4] = y[0x0]; x[0x5] = y[0x1]; x[0x6] = y[0x2]; x[0x7] = y[0x3]; x[0x0] = x[0x0]; x[0x1] = x[0x1]; x[0x2] = x[0x2]; x[0x3] = x[0x3]; #endif } static void SsePunpckhwd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpckhwd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0x0] = x[0x8]; x[0x1] = x[0x9]; x[0x2] = y[0x8]; x[0x3] = y[0x9]; x[0x4] = x[0xa]; x[0x5] = x[0xb]; x[0x6] = y[0xa]; x[0x7] = y[0xb]; x[0x8] = x[0xc]; x[0x9] = x[0xd]; x[0xa] = y[0xc]; x[0xb] = y[0xd]; x[0xc] = x[0xe]; x[0xd] = x[0xf]; x[0xe] = y[0xe]; x[0xf] = y[0xf]; #endif } static void SsePunpckhdq(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpckhdq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0x0] = x[0x8]; x[0x1] = x[0x9]; x[0x2] = x[0xa]; x[0x3] = x[0xb]; x[0x4] = y[0x8]; x[0x5] = y[0x9]; x[0x6] = y[0xa]; x[0x7] = y[0xb]; x[0x8] = x[0xc]; x[0x9] = x[0xd]; x[0xa] = x[0xe]; x[0xb] = x[0xf]; x[0xc] = y[0xc]; x[0xd] = y[0xd]; x[0xe] = y[0xe]; x[0xf] = y[0xf]; #endif } static void SsePunpcklqdq(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpcklqdq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0x8] = y[0x0]; x[0x9] = y[0x1]; x[0xa] = y[0x2]; x[0xb] = y[0x3]; x[0xc] = y[0x4]; x[0xd] = y[0x5]; x[0xe] = y[0x6]; x[0xf] = y[0x7]; x[0x0] = x[0x0]; x[0x1] = x[0x1]; x[0x2] = x[0x2]; x[0x3] = x[0x3]; x[0x4] = x[0x4]; x[0x5] = x[0x5]; x[0x6] = x[0x6]; x[0x7] = x[0x7]; #endif } static void SsePunpckhqdq(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("punpckhqdq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else x[0x0] = x[0x8]; x[0x1] = x[0x9]; x[0x2] = x[0xa]; x[0x3] = x[0xb]; x[0x4] = x[0xc]; x[0x5] = x[0xd]; x[0x6] = x[0xe]; x[0x7] = x[0xf]; x[0x8] = y[0x8]; x[0x9] = y[0x9]; x[0xa] = y[0xa]; x[0xb] = y[0xb]; x[0xc] = y[0xc]; x[0xd] = y[0xd]; x[0xe] = y[0xe]; x[0xf] = y[0xf]; #endif } static void SsePsrlw(u8 x[16], unsigned k) { MmxPsrlw(x + 0, k); MmxPsrlw(x + 8, k); } static void SsePsraw(u8 x[16], unsigned k) { MmxPsraw(x + 0, k); MmxPsraw(x + 8, k); } static void SsePsllw(u8 x[16], unsigned k) { MmxPsllw(x + 0, k); MmxPsllw(x + 8, k); } static void SsePsrld(u8 x[16], unsigned k) { MmxPsrld(x + 0, k); MmxPsrld(x + 8, k); } static void SsePsrad(u8 x[16], unsigned k) { MmxPsrad(x + 0, k); MmxPsrad(x + 8, k); } static void SsePslld(u8 x[16], unsigned k) { MmxPslld(x + 0, k); MmxPslld(x + 8, k); } static void SsePsrlq(u8 x[16], unsigned k) { MmxPsrlq(x + 0, k); MmxPsrlq(x + 8, k); } static void SsePsllq(u8 x[16], unsigned k) { MmxPsllq(x + 0, k); MmxPsllq(x + 8, k); } static void SsePsubsb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psubsb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MAX(-128, MIN(127, X[i] - Y[i])); } memcpy(x, X, 16); #endif } static void SsePaddsb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("paddsb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MAX(-128, MIN(127, X[i] + Y[i])); } memcpy(x, X, 16); #endif } static void SsePaddusb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("paddusb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; u8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MIN(255, X[i] + Y[i]); } memcpy(x, X, 16); #endif } static void SsePsubusb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psubusb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; u8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MIN(255, MAX(0, X[i] - Y[i])); } memcpy(x, X, 16); #endif } static void SsePsubusw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psubusw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsubusw(x + 0, y + 0); MmxPsubusw(x + 8, y + 8); #endif } static void SsePminsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pminsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPminsw(x + 0, y + 0); MmxPminsw(x + 8, y + 8); #endif } static void SsePmaxsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmaxsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPmaxsw(x + 0, y + 0); MmxPmaxsw(x + 8, y + 8); #endif } static void SsePsignb(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psignb\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsignb(x + 0, y + 0); MmxPsignb(x + 8, y + 8); #endif } static void SsePsignw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psignw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsignw(x + 0, y + 0); MmxPsignw(x + 8, y + 8); #endif } static void SsePsignd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psignd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsignd(x + 0, y + 0); MmxPsignd(x + 8, y + 8); #endif } static void SsePmulhrsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmulhrsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPmulhrsw(x + 0, y + 0); MmxPmulhrsw(x + 8, y + 8); #endif } static void SsePabsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pabsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPabsw(x + 0, y + 0); MmxPabsw(x + 8, y + 8); #endif } static void SsePabsd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pabsd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPabsd(x + 0, y + 0); MmxPabsd(x + 8, y + 8); #endif } static void SsePcmpgtd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pcmpgtd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPcmpgtd(x + 0, y + 0); MmxPcmpgtd(x + 8, y + 8); #endif } static void SsePcmpeqd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pcmpeqd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPcmpeqd(x + 0, y + 0); MmxPcmpeqd(x + 8, y + 8); #endif } static void SsePsrawv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psraw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsrawv(x + 0, y); MmxPsrawv(x + 8, y); #endif } static void SsePsradv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psrad\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsradv(x + 0, y); MmxPsradv(x + 8, y); #endif } static void SsePsrlwv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psrlw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsrlwv(x + 0, y); MmxPsrlwv(x + 8, y); #endif } static void SsePsllwv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psllw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsllwv(x + 0, y); MmxPsllwv(x + 8, y); #endif } static void SsePsrldv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psrld\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsrldv(x + 0, y); MmxPsrldv(x + 8, y); #endif } static void SsePslldv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pslld\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPslldv(x + 0, y); MmxPslldv(x + 8, y); #endif } static void SsePsrlqv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psrlq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsrlqv(x + 0, y); MmxPsrlqv(x + 8, y); #endif } static void SsePsllqv(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psllq\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPsllqv(x + 0, y); MmxPsllqv(x + 8, y); #endif } static void SsePmaddwd(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmaddwd\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPmaddwd(x + 0, y + 0); MmxPmaddwd(x + 8, y + 8); #endif } static void SsePmulhuw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmulhuw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPmulhuw(x + 0, y + 0); MmxPmulhuw(x + 8, y + 8); #endif } static void SsePmulld(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmulld\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else int i; u32 X[4] = {Get32(x), Get32(x + 4), Get32(x + 8), Get32(x + 12)}; u32 Y[4] = {Get32(y), Get32(y + 4), Get32(y + 8), Get32(y + 12)}; for (i = 0; i < 4; ++i) { X[i] *= Y[i]; } for (i = 0; i < 4; ++i) { Put32(x + i * 4, X[i]); } #endif } static void SsePmaddubsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmaddubsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else MmxPmaddubsw(x + 0, y + 0); MmxPmaddubsw(x + 8, y + 8); #endif } #ifdef DISABLE_MMX relegated void NoMmx(u8 x[8], const u8 y[8]) { OpUdImpl(g_machine); } static void NoMmxK(u8 x[8], unsigned k) { OpUdImpl(g_machine); } #define MmxKernel NoMmx #define MmxPabsd NoMmx #define MmxPabsw NoMmx #define MmxPackssdw NoMmx #define MmxPacksswb NoMmx #define MmxPackuswb NoMmx #define MmxPaddd NoMmx #define MmxPaddq NoMmx #define MmxPaddsb NoMmx #define MmxPaddusb NoMmx #define MmxPalignr NoMmx #define MmxPcmpeqd NoMmx #define MmxPcmpgtd NoMmx #define MmxPhaddd NoMmx #define MmxPhaddw NoMmx #define MmxPhsubd NoMmx #define MmxPhsubw NoMmx #define MmxPmaddubsw NoMmx #define MmxPmaddwd NoMmx #define MmxPmaxsw NoMmx #define MmxPminsw NoMmx #define MmxPmulhrsw NoMmx #define MmxPmulhuw NoMmx #define MmxPmulld NoMmx #define MmxPmuludq NoMmx #define MmxPsadbw NoMmx #define MmxPshufb NoMmx #define MmxPsignb NoMmx #define MmxPsignd NoMmx #define MmxPsignw NoMmx #define MmxPslld NoMmxK #define MmxPslldq NoMmxK #define MmxPslldv NoMmx #define MmxPsllq NoMmxK #define MmxPsllqv NoMmx #define MmxPsllw NoMmxK #define MmxPsllwv NoMmx #define MmxPsrad NoMmxK #define MmxPsradv NoMmx #define MmxPsraw NoMmxK #define MmxPsrawv NoMmx #define MmxPsrld NoMmxK #define MmxPsrldq NoMmxK #define MmxPsrldv NoMmx #define MmxPsrlq NoMmxK #define MmxPsrlqv NoMmx #define MmxPsrlw NoMmxK #define MmxPsrlwv NoMmx #define MmxPsubd NoMmx #define MmxPsubq NoMmx #define MmxPsubsb NoMmx #define MmxPsubusb NoMmx #define MmxPsubusw NoMmx #define MmxPunpckhbw NoMmx #define MmxPunpckhdq NoMmx #define MmxPunpckhqdq NoMmx #define MmxPunpckhwd NoMmx #define MmxPunpcklbw NoMmx #define MmxPunpckldq NoMmx #define MmxPunpcklqdq NoMmx #define MmxPunpcklwd NoMmx #endif static void OpPsb(P, void MmxKernel(u8[8], unsigned), void SseKernel(u8[16], unsigned)) { if (Osz(rde)) { SseKernel(XmmRexbRm(m, rde), uimm0); } else { MmxKernel(XmmRexbRm(m, rde), uimm0); } } optimizesize void Op171(P) { switch (ModrmReg(rde)) { case 2: OpPsb(A, MmxPsrlw, SsePsrlw); break; case 4: OpPsb(A, MmxPsraw, SsePsraw); break; case 6: OpPsb(A, MmxPsllw, SsePsllw); break; default: OpUdImpl(m); } } optimizesize void Op172(P) { switch (ModrmReg(rde)) { case 2: OpPsb(A, MmxPsrld, SsePsrld); break; case 4: OpPsb(A, MmxPsrad, SsePsrad); break; case 6: OpPsb(A, MmxPslld, SsePslld); break; default: OpUdImpl(m); } } optimizesize void Op173(P) { switch (ModrmReg(rde)) { case 2: OpPsb(A, MmxPsrlq, SsePsrlq); break; case 3: OpPsb(A, MmxPsrldq, SsePsrldq); break; case 6: OpPsb(A, MmxPsllq, SsePsllq); break; case 7: OpPsb(A, MmxPslldq, SsePslldq); break; default: OpUdImpl(m); } } void OpSsePalignr(P) { if (Osz(rde)) { SsePalignr(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(A), uimm0); } else { #ifndef DISABLE_MMX MmxPalignr(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(A), uimm0); #else OpUdImpl(m); #endif } } void OpSse(P, void MmxKernel(u8[8], const u8[8]), void SseKernel(u8[16], const u8[16])) { IGNORE_RACES_START(); if (Osz(rde)) { SseKernel(XmmRexrReg(m, rde), GetXmmAddress(A)); } else { #ifndef DISABLE_MMX MmxKernel(XmmRexrReg(m, rde), GetMmxAddress(A)); #else OpUdImpl(m); #endif } IGNORE_RACES_END(); if (IsMakingPath(m)) { Jitter(A, "z4P" // res0 = GetXmmOrMemPointer(RexbRm) "r0s1=" // sav1 = res0 "z4Q" // res0 = GetXmmPointer(RexrReg) "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "c", // call function Osz(rde) ? SseKernel : MmxKernel); } } // clang-format off void OpSsePunpcklbw(P) { OpSse(A, MmxPunpcklbw, SsePunpcklbw); } void OpSsePunpcklwd(P) { OpSse(A, MmxPunpcklwd, SsePunpcklwd); } void OpSsePunpckldq(P) { OpSse(A, MmxPunpckldq, SsePunpckldq); } void OpSsePacksswb(P) { OpSse(A, MmxPacksswb, SsePacksswb); } void OpSsePcmpgtd(P) { OpSse(A, MmxPcmpgtd, SsePcmpgtd); } void OpSsePackuswb(P) { OpSse(A, MmxPackuswb, SsePackuswb); } void OpSsePunpckhbw(P) { OpSse(A, MmxPunpckhbw, SsePunpckhbw); } void OpSsePunpckhwd(P) { OpSse(A, MmxPunpckhwd, SsePunpckhwd); } void OpSsePunpckhdq(P) { OpSse(A, MmxPunpckhdq, SsePunpckhdq); } void OpSsePackssdw(P) { OpSse(A, MmxPackssdw, SsePackssdw); } void OpSsePunpcklqdq(P) { OpSse(A, MmxPunpcklqdq, SsePunpcklqdq); } void OpSsePunpckhqdq(P) { OpSse(A, MmxPunpckhqdq, SsePunpckhqdq); } void OpSsePcmpeqd(P) { OpSse(A, MmxPcmpeqd, SsePcmpeqd); } void OpSsePsrlwv(P) { OpSse(A, MmxPsrlwv, SsePsrlwv); } void OpSsePsrldv(P) { OpSse(A, MmxPsrldv, SsePsrldv); } void OpSsePsrlqv(P) { OpSse(A, MmxPsrlqv, SsePsrlqv); } void OpSsePaddq(P) { OpSse(A, MmxPaddq, SsePaddq); } void OpSsePsubusb(P) { OpSse(A, MmxPsubusb, SsePsubusb); } void OpSsePsubusw(P) { OpSse(A, MmxPsubusw, SsePsubusw); } void OpSsePaddusb(P) { OpSse(A, MmxPaddusb, SsePaddusb); } void OpSsePsrawv(P) { OpSse(A, MmxPsrawv, SsePsrawv); } void OpSsePsradv(P) { OpSse(A, MmxPsradv, SsePsradv); } void OpSsePmulhuw(P) { OpSse(A, MmxPmulhuw, SsePmulhuw); } void OpSsePsubsb(P) { OpSse(A, MmxPsubsb, SsePsubsb); } void OpSsePminsw(P) { OpSse(A, MmxPminsw, SsePminsw); } void OpSsePaddsb(P) { OpSse(A, MmxPaddsb, SsePaddsb); } void OpSsePmaxsw(P) { OpSse(A, MmxPmaxsw, SsePmaxsw); } void OpSsePsllwv(P) { OpSse(A, MmxPsllwv, SsePsllwv); } void OpSsePslldv(P) { OpSse(A, MmxPslldv, SsePslldv); } void OpSsePsllqv(P) { OpSse(A, MmxPsllqv, SsePsllqv); } void OpSsePmuludq(P) { OpSse(A, MmxPmuludq, SsePmuludq); } void OpSsePmaddwd(P) { OpSse(A, MmxPmaddwd, SsePmaddwd); } void OpSsePsadbw(P) { OpSse(A, MmxPsadbw, SsePsadbw); } void OpSsePsubd(P) { OpSse(A, MmxPsubd, SsePsubd); } void OpSsePsubq(P) { OpSse(A, MmxPsubq, SsePsubq); } void OpSsePaddd(P) { OpSse(A, MmxPaddd, SsePaddd); } void OpSsePshufb(P) { OpSse(A, MmxPshufb, SsePshufb); } void OpSsePhaddw(P) { OpSse(A, MmxPhaddw, SsePhaddw); } void OpSsePhaddd(P) { OpSse(A, MmxPhaddd, SsePhaddd); } void OpSsePmaddubsw(P) { OpSse(A, MmxPmaddubsw, SsePmaddubsw); } void OpSsePhsubw(P) { OpSse(A, MmxPhsubw, SsePhsubw); } void OpSsePhsubd(P) { OpSse(A, MmxPhsubd, SsePhsubd); } void OpSsePsignb(P) { OpSse(A, MmxPsignb, SsePsignb); } void OpSsePsignw(P) { OpSse(A, MmxPsignw, SsePsignw); } void OpSsePsignd(P) { OpSse(A, MmxPsignd, SsePsignd); } void OpSsePmulhrsw(P) { OpSse(A, MmxPmulhrsw, SsePmulhrsw); } void OpSsePabsw(P) { OpSse(A, MmxPabsw, SsePabsw); } void OpSsePabsd(P) { OpSse(A, MmxPabsd, SsePabsd); } void OpSsePmulld(P) { OpSse(A, MmxPmulld, SsePmulld); } ================================================ FILE: blink/sse.h ================================================ #ifndef BLINK_SSE_H_ #define BLINK_SSE_H_ #include "blink/builtin.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/tsan.h" void OpSsePabsb(P); void OpSsePabsd(P); void OpSsePabsw(P); void OpSsePackssdw(P); void OpSsePacksswb(P); void OpSsePackuswb(P); void OpSsePaddb(P); void OpSsePaddd(P); void OpSsePaddq(P); void OpSsePaddsb(P); void OpSsePaddsw(P); void OpSsePaddusb(P); void OpSsePaddusw(P); void OpSsePaddw(P); void OpSsePalignr(P); void OpSsePand(P); void OpSsePandn(P); void OpSsePavgb(P); void OpSsePavgw(P); void OpSsePcmpeqb(P); void OpSsePcmpeqd(P); void OpSsePcmpeqw(P); void OpSsePcmpgtb(P); void OpSsePcmpgtd(P); void OpSsePcmpgtw(P); void OpSsePhaddd(P); void OpSsePhaddsw(P); void OpSsePhaddw(P); void OpSsePhsubd(P); void OpSsePhsubsw(P); void OpSsePhsubw(P); void OpSsePmaddubsw(P); void OpSsePmaddwd(P); void OpSsePmaxsw(P); void OpSsePmaxub(P); void OpSsePminsw(P); void OpSsePminub(P); void OpSsePmulhrsw(P); void OpSsePmulhuw(P); void OpSsePmulhw(P); void OpSsePmulld(P); void OpSsePmullw(P); void OpSsePmuludq(P); void OpSsePor(P); void OpSsePsadbw(P); void OpSsePshufb(P); void OpSsePsignb(P); void OpSsePsignd(P); void OpSsePsignw(P); void OpSsePslldv(P); void OpSsePsllqv(P); void OpSsePsllwv(P); void OpSsePsradv(P); void OpSsePsrawv(P); void OpSsePsrldv(P); void OpSsePsrlqv(P); void OpSsePsrlwv(P); void OpSsePsubb(P); void OpSsePsubd(P); void OpSsePsubq(P); void OpSsePsubsb(P); void OpSsePsubsw(P); void OpSsePsubusb(P); void OpSsePsubusw(P); void OpSsePsubw(P); void OpSsePunpckhbw(P); void OpSsePunpckhdq(P); void OpSsePunpckhqdq(P); void OpSsePunpckhwd(P); void OpSsePunpcklbw(P); void OpSsePunpckldq(P); void OpSsePunpcklqdq(P); void OpSsePunpcklwd(P); void OpSsePxor(P); void MmxPcmpgtb(u8[8], const u8[8]); void MmxPcmpgtw(u8[8], const u8[8]); void MmxPcmpeqb(u8[8], const u8[8]); void MmxPcmpeqw(u8[8], const u8[8]); void MmxPmullw(u8[8], const u8[8]); void MmxPminub(u8[8], const u8[8]); void MmxPaddusw(u8[8], const u8[8]); void MmxPmaxub(u8[8], const u8[8]); void MmxPavgb(u8[8], const u8[8]); void MmxPavgw(u8[8], const u8[8]); void MmxPmulhw(u8[8], const u8[8]); void MmxPsubsw(u8[8], const u8[8]); void MmxPaddsw(u8[8], const u8[8]); void MmxPsubb(u8[8], const u8[8]); void MmxPsubw(u8[8], const u8[8]); void MmxPaddb(u8[8], const u8[8]); void MmxPaddw(u8[8], const u8[8]); void MmxPhaddsw(u8[8], const u8[8]); void MmxPhsubsw(u8[8], const u8[8]); void MmxPabsb(u8[8], const u8[8]); void OpSse(P, void (*)(u8[8], const u8[8]), void (*)(u8[16], const u8[16])); #endif /* BLINK_SSE_H_ */ ================================================ FILE: blink/sse2.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/endian.h" #include "blink/intrin.h" #include "blink/macros.h" #include "blink/sse.h" /** * @fileoverview SSE operations that compilers are good at vectoring. */ #define COPY16_X_Y_FROM_x_y(T) \ T X[8] = {(T)Get16(x), (T)Get16(x + 2), (T)Get16(x + 4), \ (T)Get16(x + 6), (T)Get16(x + 8), (T)Get16(x + 10), \ (T)Get16(x + 12), (T)Get16(x + 14)}; \ T Y[8] = {(T)Get16(y), (T)Get16(y + 2), (T)Get16(y + 4), \ (T)Get16(y + 6), (T)Get16(y + 8), (T)Get16(y + 10), \ (T)Get16(y + 12), (T)Get16(y + 14)} #define COPY16_x_FROM_X \ for (i = 0; i < 8; ++i) { \ Put16(x + i * 2, X[i]); \ } static void MmxPor(u8 x[8], const u8 y[8]) { *(u64 *)x |= *(u64 *)y; } static void MmxPxor(u8 x[8], const u8 y[8]) { *(u64 *)x ^= *(u64 *)y; } static void MmxPand(u8 x[8], const u8 y[8]) { *(u64 *)x &= *(u64 *)y; } static void MmxPandn(u8 x[8], const u8 y[8]) { *(u64 *)x = ~*(u64 *)x & *(u64 *)y; } static void SsePsubw(u8 x[16], const u8 y[16]) { unsigned i; COPY16_X_Y_FROM_x_y(u16); for (i = 0; i < 8; ++i) { X[i] -= Y[i]; } COPY16_x_FROM_X; } static void SsePaddw(u8 x[16], const u8 y[16]) { unsigned i; COPY16_X_Y_FROM_x_y(u16); for (i = 0; i < 8; ++i) { X[i] += Y[i]; } COPY16_x_FROM_X; } static void SsePaddusw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("paddusw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; COPY16_X_Y_FROM_x_y(u16); for (i = 0; i < 8; ++i) { X[i] = MIN(65535, X[i] + Y[i]); } COPY16_x_FROM_X; #endif } static void SsePhaddsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("phaddsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else i16 t[8]; unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 4; ++i) { t[i] = MAX(-32768, MIN(32767, X[i * 2] + X[i * 2 + 1])); } for (i = 0; i < 4; ++i) { t[i + 4] = MAX(-32768, MIN(32767, Y[i * 2] + Y[i * 2 + 1])); } memcpy(X, t, 16); COPY16_x_FROM_X; #endif } static void SsePhsubsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("phsubsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else i16 t[8]; unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 4; ++i) { t[i] = MAX(-32768, MIN(32767, X[i * 2] - X[i * 2 + 1])); } for (i = 0; i < 4; ++i) { t[i + 4] = MAX(-32768, MIN(32767, Y[i * 2] - Y[i * 2 + 1])); } memcpy(X, t, 16); COPY16_x_FROM_X; #endif } static void SsePsubsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("psubsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 8; ++i) { X[i] = MAX(-32768, MIN(32767, X[i] - Y[i])); } COPY16_x_FROM_X; #endif } static void SsePaddsw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("paddsw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 8; ++i) { X[i] = MAX(-32768, MIN(32767, X[i] + Y[i])); } COPY16_x_FROM_X; #endif } static void SsePcmpgtw(u8 x[16], const u8 y[16]) { unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 8; ++i) { X[i] = -(X[i] > Y[i]); } COPY16_x_FROM_X; } static void SsePcmpeqw(u8 x[16], const u8 y[16]) { unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 8; ++i) { X[i] = -(X[i] == Y[i]); } COPY16_x_FROM_X; } static void SsePavgw(u8 x[16], const u8 y[16]) { unsigned i; COPY16_X_Y_FROM_x_y(u16); for (i = 0; i < 8; ++i) { X[i] = (X[i] + Y[i] + 1) >> 1; } COPY16_x_FROM_X; } static void SsePmulhw(u8 x[16], const u8 y[16]) { #if X86_INTRINSICS asm("pmulhw\t%1,%0" : "+x"(*(char_xmma_t *)x) : "xm"(*(const char_xmma_t *)y)); #else unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 8; ++i) { X[i] = (X[i] * Y[i]) >> 16; } COPY16_x_FROM_X; #endif } static void SsePmullw(u8 x[16], const u8 y[16]) { unsigned i; COPY16_X_Y_FROM_x_y(i16); for (i = 0; i < 8; ++i) { X[i] *= Y[i]; } COPY16_x_FROM_X; } static void SsePsubsb(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MAX(-128, MIN(127, X[i] - Y[i])); } memcpy(x, X, 16); } static void SsePaddsb(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MAX(-128, MIN(127, X[i] + Y[i])); } memcpy(x, X, 16); } static void SsePaddusb(u8 x[16], const u8 y[16]) { unsigned i; u8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MIN(255, X[i] + Y[i]); } memcpy(x, X, 16); } static void SsePsubusb(u8 x[16], const u8 y[16]) { unsigned i; u8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MIN(255, MAX(0, X[i] - Y[i])); } memcpy(x, X, 16); } static void SsePsubb(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] -= Y[i]; } memcpy(x, X, 16); } static void SsePaddb(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] += Y[i]; } memcpy(x, X, 16); } static void SsePor(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] |= Y[i]; } memcpy(x, X, 16); } static void SsePxor(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] ^= Y[i]; } memcpy(x, X, 16); } static void SsePand(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] &= Y[i]; } memcpy(x, X, 16); } static void SsePandn(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = ~X[i] & Y[i]; } memcpy(x, X, 16); } static void SsePcmpeqb(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = -(X[i] == Y[i]); } memcpy(x, X, 16); } static void SsePcmpgtb(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = -(X[i] > Y[i]); } memcpy(x, X, 16); } static void SsePavgb(u8 x[16], const u8 y[16]) { unsigned i; u8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = (X[i] + Y[i] + 1) >> 1; } memcpy(x, X, 16); } static void SsePabsb(u8 x[16], const u8 y[16]) { unsigned i; i8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = ABS((i8)Y[i]); } memcpy(x, X, 16); } static void SsePminub(u8 x[16], const u8 y[16]) { unsigned i; u8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MIN(X[i], Y[i]); } memcpy(x, X, 16); } static void SsePmaxub(u8 x[16], const u8 y[16]) { unsigned i; u8 X[16], Y[16]; memcpy(X, x, 16); memcpy(Y, y, 16); for (i = 0; i < 16; ++i) { X[i] = MAX(X[i], Y[i]); } memcpy(x, X, 16); } #ifdef DISABLE_MMX void NoMmx(u8[8], const u8[8]) relegated; #define MmxPor NoMmx #define MmxPxor NoMmx #define MmxPand NoMmx #define MmxPandn NoMmx #define MmxPcmpgtb NoMmx #define MmxPcmpgtw NoMmx #define MmxPcmpeqb NoMmx #define MmxPcmpeqw NoMmx #define MmxPmullw NoMmx #define MmxPminub NoMmx #define MmxPand NoMmx #define MmxPaddusw NoMmx #define MmxPmaxub NoMmx #define MmxPandn NoMmx #define MmxPavgb NoMmx #define MmxPavgw NoMmx #define MmxPmulhw NoMmx #define MmxPsubsw NoMmx #define MmxPor NoMmx #define MmxPaddsw NoMmx #define MmxPxor NoMmx #define MmxPsubb NoMmx #define MmxPsubw NoMmx #define MmxPaddb NoMmx #define MmxPaddw NoMmx #define MmxPhaddsw NoMmx #define MmxPhsubsw NoMmx #define MmxPabsb NoMmx #endif // clang-format off void OpSsePcmpgtb(P) { OpSse(A, MmxPcmpgtb, SsePcmpgtb); } void OpSsePcmpgtw(P) { OpSse(A, MmxPcmpgtw, SsePcmpgtw); } void OpSsePcmpeqb(P) { OpSse(A, MmxPcmpeqb, SsePcmpeqb); } void OpSsePcmpeqw(P) { OpSse(A, MmxPcmpeqw, SsePcmpeqw); } void OpSsePmullw(P) { OpSse(A, MmxPmullw, SsePmullw); } void OpSsePminub(P) { OpSse(A, MmxPminub, SsePminub); } void OpSsePand(P) { OpSse(A, MmxPand, SsePand); } void OpSsePaddusw(P) { OpSse(A, MmxPaddusw, SsePaddusw); } void OpSsePmaxub(P) { OpSse(A, MmxPmaxub, SsePmaxub); } void OpSsePandn(P) { OpSse(A, MmxPandn, SsePandn); } void OpSsePavgb(P) { OpSse(A, MmxPavgb, SsePavgb); } void OpSsePavgw(P) { OpSse(A, MmxPavgw, SsePavgw); } void OpSsePmulhw(P) { OpSse(A, MmxPmulhw, SsePmulhw); } void OpSsePsubsw(P) { OpSse(A, MmxPsubsw, SsePsubsw); } void OpSsePor(P) { OpSse(A, MmxPor, SsePor); } void OpSsePaddsw(P) { OpSse(A, MmxPaddsw, SsePaddsw); } void OpSsePxor(P) { OpSse(A, MmxPxor, SsePxor); } void OpSsePsubb(P) { OpSse(A, MmxPsubb, SsePsubb); } void OpSsePsubw(P) { OpSse(A, MmxPsubw, SsePsubw); } void OpSsePaddb(P) { OpSse(A, MmxPaddb, SsePaddb); } void OpSsePaddw(P) { OpSse(A, MmxPaddw, SsePaddw); } void OpSsePhaddsw(P) { OpSse(A, MmxPhaddsw, SsePhaddsw); } void OpSsePhsubsw(P) { OpSse(A, MmxPhsubsw, SsePhsubsw); } void OpSsePabsb(P) { OpSse(A, MmxPabsb, SsePabsb); } ================================================ FILE: blink/ssefloat.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/builtin.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/fpu.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/pun.h" #include "blink/stats.h" #include "blink/tsan.h" static void pshufw(i16 b[4], const i16 a[4], int m) { i16 t[4]; t[0] = a[(m & 0003) >> 0]; t[1] = a[(m & 0014) >> 2]; t[2] = a[(m & 0060) >> 4]; t[3] = a[(m & 0300) >> 6]; b[0] = t[0]; b[1] = t[1]; b[2] = t[2]; b[3] = t[3]; } static void pshufd(i32 b[4], const i32 a[4], int m) { i32 t[4]; t[0] = a[(m & 0003) >> 0]; t[1] = a[(m & 0014) >> 2]; t[2] = a[(m & 0060) >> 4]; t[3] = a[(m & 0300) >> 6]; b[0] = t[0]; b[1] = t[1]; b[2] = t[2]; b[3] = t[3]; } static void pshuflw(i16 b[8], const i16 a[8], int m) { i16 t[4]; t[0] = a[(m & 0003) >> 0]; t[1] = a[(m & 0014) >> 2]; t[2] = a[(m & 0060) >> 4]; t[3] = a[(m & 0300) >> 6]; b[0] = t[0]; b[1] = t[1]; b[2] = t[2]; b[3] = t[3]; b[4] = a[4]; b[5] = a[5]; b[6] = a[6]; b[7] = a[7]; } static void pshufhw(i16 b[8], const i16 a[8], int m) { i16 t[4]; t[0] = a[4 + ((m & 0003) >> 0)]; t[1] = a[4 + ((m & 0014) >> 2)]; t[2] = a[4 + ((m & 0060) >> 4)]; t[3] = a[4 + ((m & 0300) >> 6)]; b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3]; b[4] = t[0]; b[5] = t[1]; b[6] = t[2]; b[7] = t[3]; } void OpUnpcklpsd(P) { u8 *a, *b; a = XmmRexrReg(m, rde); b = GetModrmRegisterXmmPointerRead8(A); IGNORE_RACES_START(); if (Osz(rde)) { memcpy(a + 8, b, 8); } else { memcpy(a + 4 * 3, b + 4, 4); memcpy(a + 4 * 2, a + 4, 4); memcpy(a + 4 * 1, b + 0, 4); } IGNORE_RACES_END(); } void OpUnpckhpsd(P) { u8 *a, *b; a = XmmRexrReg(m, rde); b = GetModrmRegisterXmmPointerRead16(A); IGNORE_RACES_START(); if (Osz(rde)) { memcpy(a + 0, b + 8, 8); memcpy(a + 8, b + 8, 8); } else { memcpy(a + 4 * 0, a + 4 * 2, 4); memcpy(a + 4 * 1, b + 4 * 2, 4); memcpy(a + 4 * 2, a + 4 * 3, 4); memcpy(a + 4 * 3, b + 4 * 3, 4); } IGNORE_RACES_END(); } void OpPextrwGdqpUdqIb(P) { u8 i; i = uimm0; i &= Osz(rde) ? 7 : 3; Put16(RegRexrReg(m, rde), Get16(XmmRexbRm(m, rde) + i * 2)); } void OpPinsrwVdqEwIb(P) { u8 i; i = uimm0; i &= Osz(rde) ? 7 : 3; IGNORE_RACES_START(); Put16(XmmRexrReg(m, rde) + i * 2, Read16(GetModrmRegisterWordPointerRead2(A))); IGNORE_RACES_END(); } void OpShuffle(P) { i16 q16[4]; void *kernel; IGNORE_RACES_START(); switch (Rep(rde) | Osz(rde)) { case 0: memcpy(q16, GetModrmRegisterXmmPointerRead8(A), 8); pshufw(q16, q16, uimm0); memcpy(XmmRexrReg(m, rde), q16, 8); kernel = 0; break; case 1: pshufd((i32 *)XmmRexrReg(m, rde), (i32 *)GetModrmRegisterXmmPointerRead16(A), uimm0); kernel = (void *)(uintptr_t)pshufd; break; case 2: pshuflw((i16 *)XmmRexrReg(m, rde), (i16 *)GetModrmRegisterXmmPointerRead16(A), uimm0); kernel = (void *)(uintptr_t)pshuflw; break; case 3: pshufhw((i16 *)XmmRexrReg(m, rde), (i16 *)GetModrmRegisterXmmPointerRead16(A), uimm0); kernel = (void *)(uintptr_t)pshufhw; break; default: __builtin_unreachable(); } IGNORE_RACES_END(); if (IsMakingPath(m) && kernel) { Jitter(A, "z4P" // res0 = GetXmmOrMemPointer(RexbRm) "r0s1=" // sav1 = res0 "z4Q" // res0 = GetXmmPointer(RexrReg) "a2i" // arg2 = uimm0 "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "c", // call function uimm0, kernel); } } static void Shufps(P) { u8 *p; union FloatPun x[4], y[4], z[4]; p = GetModrmRegisterXmmPointerRead16(A); IGNORE_RACES_START(); y[0].i = Read32(p + 0 * 4); y[1].i = Read32(p + 1 * 4); y[2].i = Read32(p + 2 * 4); y[3].i = Read32(p + 3 * 4); p = XmmRexrReg(m, rde); x[0].i = Read32(p + 0 * 4); x[1].i = Read32(p + 1 * 4); x[2].i = Read32(p + 2 * 4); x[3].i = Read32(p + 3 * 4); z[0].f = x[(uimm0 & 0003) >> 0].f; z[1].f = x[(uimm0 & 0014) >> 2].f; z[2].f = y[(uimm0 & 0060) >> 4].f; z[3].f = y[(uimm0 & 0300) >> 6].f; Write32(p + 0 * 4, z[0].i); Write32(p + 1 * 4, z[1].i); Write32(p + 2 * 4, z[2].i); Write32(p + 3 * 4, z[3].i); IGNORE_RACES_END(); } static void Shufpd(P) { u8 *p; union DoublePun x[2], y[2], z[2]; p = GetModrmRegisterXmmPointerRead16(A); IGNORE_RACES_START(); y[0].i = Read64(p + 0 * 8); y[1].i = Read64(p + 1 * 8); p = XmmRexrReg(m, rde); x[0].i = Read64(p + 0 * 8); x[1].i = Read64(p + 1 * 8); z[0].f = x[(uimm0 & 0001) >> 0].f; z[1].f = y[(uimm0 & 0002) >> 1].f; Write64(p + 0 * 8, z[0].i); Write64(p + 1 * 8, z[1].i); IGNORE_RACES_END(); } void OpShufpsd(P) { if (Osz(rde)) { Shufpd(A); } else { Shufps(A); } } static void Movmskps(P) { u8 *p = GetModrmRegisterXmmPointerRead16(A); IGNORE_RACES_START(); Put64(RegRexrReg(m, rde), (!!(p[15] & 0x80) << 3 | !!(p[11] & 0x80) << 2 | !!(p[7] & 0x80) << 1 | !!(p[3] & 0x80))); IGNORE_RACES_END(); } static void Movmskpd(P) { u8 *p = GetModrmRegisterXmmPointerRead16(A); IGNORE_RACES_START(); Put64(RegRexrReg(m, rde), !!(p[15] & 0x80) << 1 | !!(p[7] & 0x80)); IGNORE_RACES_END(); } void OpMovmskpsd(P) { if (Osz(rde)) { Movmskpd(A); } else { Movmskps(A); } } void OpSqrtpsd(P) { IGNORE_RACES_START(); switch (Rep(rde) | Osz(rde)) { case 0: { int i; u8 *p; union FloatPun u[4]; p = GetModrmRegisterXmmPointerRead16(A); u[0].i = Read32(p + 0 * 4); u[1].i = Read32(p + 1 * 4); u[2].i = Read32(p + 2 * 4); u[3].i = Read32(p + 3 * 4); for (i = 0; i < 4; ++i) u[i].f = sqrtf(u[i].f); p = XmmRexrReg(m, rde); Write32(p + 0 * 4, u[0].i); Write32(p + 1 * 4, u[1].i); Write32(p + 2 * 4, u[2].i); Write32(p + 3 * 4, u[3].i); break; } case 1: { int i; u8 *p; union DoublePun u[2]; p = GetModrmRegisterXmmPointerRead16(A); u[0].i = Read32(p + 0 * 8); u[1].i = Read32(p + 1 * 8); for (i = 0; i < 2; ++i) u[i].f = sqrt(u[i].f); p = XmmRexrReg(m, rde); Write32(p + 0 * 8, u[0].i); Write32(p + 1 * 8, u[1].i); break; } case 2: { union DoublePun u; u.i = Read64(GetModrmRegisterXmmPointerRead8(A)); u.f = sqrt(u.f); Write64(XmmRexrReg(m, rde), u.i); break; } case 3: { union FloatPun u; u.i = Read32(GetModrmRegisterXmmPointerRead4(A)); u.f = sqrtf(u.f); Write32(XmmRexrReg(m, rde), u.i); break; } default: __builtin_unreachable(); } IGNORE_RACES_END(); } void OpRsqrtps(P) { IGNORE_RACES_START(); if (Rep(rde) != 3) { int i; u8 *p; union FloatPun u[4]; p = GetModrmRegisterXmmPointerRead16(A); u[0].i = Read32(p + 0 * 4); u[1].i = Read32(p + 1 * 4); u[2].i = Read32(p + 2 * 4); u[3].i = Read32(p + 3 * 4); for (i = 0; i < 4; ++i) u[i].f = 1.f / sqrtf(u[i].f); p = XmmRexrReg(m, rde); Write32(p + 0 * 4, u[0].i); Write32(p + 1 * 4, u[1].i); Write32(p + 2 * 4, u[2].i); Write32(p + 3 * 4, u[3].i); } else { union FloatPun u; u.i = Read32(GetModrmRegisterXmmPointerRead4(A)); u.f = 1.f / sqrtf(u.f); Write32(XmmRexrReg(m, rde), u.i); } IGNORE_RACES_END(); } void OpRcpps(P) { IGNORE_RACES_START(); if (Rep(rde) != 3) { int i; u8 *p; union FloatPun u[4]; p = GetModrmRegisterXmmPointerRead16(A); u[0].i = Read32(p + 0 * 4); u[1].i = Read32(p + 1 * 4); u[2].i = Read32(p + 2 * 4); u[3].i = Read32(p + 3 * 4); for (i = 0; i < 4; ++i) u[i].f = 1.f / u[i].f; p = XmmRexrReg(m, rde); Write32(p + 0 * 4, u[0].i); Write32(p + 1 * 4, u[1].i); Write32(p + 2 * 4, u[2].i); Write32(p + 3 * 4, u[3].i); } else { union FloatPun u; u.i = Read32(GetModrmRegisterXmmPointerRead4(A)); u.f = 1.f / u.f; Write32(XmmRexrReg(m, rde), u.i); } IGNORE_RACES_END(); } static void ComissKernel(const u8 rxr[8], const u8 reg[8], struct Machine *m) { bool zf, cf; union DoublePun xd, yd; m->mxcsr &= ~kMxcsrIe; xd.i = Read64(rxr); yd.i = Read64(reg); if (!isunordered(xd.f, yd.f)) { zf = xd.f == yd.f; cf = xd.f < yd.f; m->flags = SetFlag(m->flags, FLAGS_ZF, zf); m->flags = SetFlag(m->flags, FLAGS_CF, cf); m->flags = SetFlag(m->flags, FLAGS_PF, false); m->flags = SetFlag(m->flags, FLAGS_SF, false); m->flags = SetFlag(m->flags, FLAGS_OF, false); } else { m->flags = SetFlag(m->flags, FLAGS_ZF, true); m->flags = SetFlag(m->flags, FLAGS_CF, true); m->flags = SetFlag(m->flags, FLAGS_PF, true); m->flags = SetFlag(m->flags, FLAGS_SF, false); m->flags = SetFlag(m->flags, FLAGS_OF, false); m->mxcsr |= kMxcsrIe; if (!(m->mxcsr & kMxcsrIm)) { HaltMachine(m, kMachineSimdException); } } } void OpComissVsWs(P) { bool isucomiss; u8 zf, cf, pf, ie; isucomiss = ~Opcode(rde) & 1; IGNORE_RACES_START(); if (!Osz(rde)) { union FloatPun xf, yf; xf.i = Read32(XmmRexrReg(m, rde)); yf.i = Read32(GetModrmRegisterXmmPointerRead4(A)); if (!isunordered(xf.f, yf.f)) { zf = xf.f == yf.f; cf = xf.f < yf.f; pf = false; ie = false; } else { zf = cf = pf = ie = true; } } else { union DoublePun xd, yd; xd.i = Read64(XmmRexrReg(m, rde)); yd.i = Read64(GetModrmRegisterXmmPointerRead8(A)); if (!isunordered(xd.f, yd.f)) { zf = xd.f == yd.f; cf = xd.f < yd.f; pf = false; ie = false; } else { zf = cf = pf = ie = true; } if (IsMakingPath(m) && !isucomiss) { Jitter(A, "z4P" // res0 = GetXmmOrMemPointer(RexbRm) "r0s1=" // sav1 = res0 "z4Q" // res0 = GetXmmPointer(RexrReg) "s0a2=" // arg2 = sav0 (machine) "s1a1=" // arg1 = sav1 "t" // arg0 = res0 "c", // call function ComissKernel); } } m->flags = SetFlag(m->flags, FLAGS_ZF, zf); m->flags = SetFlag(m->flags, FLAGS_PF, pf); m->flags = SetFlag(m->flags, FLAGS_CF, cf); m->flags = SetFlag(m->flags, FLAGS_SF, false); m->flags = SetFlag(m->flags, FLAGS_OF, false); if (!isucomiss) { m->mxcsr &= ~kMxcsrIe; if (ie) { m->mxcsr |= kMxcsrIe; if (!(m->mxcsr & kMxcsrIm)) { HaltMachine(m, kMachineSimdException); } } } IGNORE_RACES_END(); } static void OpPsd(P, float fs(float x, float y), double fd(double x, double y), void s1(u8 *, struct Machine *, long), void d1(u8 *, struct Machine *, long)) { IGNORE_RACES_START(); if (Rep(rde) == 2) { d1(GetModrmRegisterXmmPointerRead8(A), m, RexrReg(rde)); if (IsMakingPath(m)) { Jitter(A, "z4P" // res0 = GetXmmOrMemPointer(RexbRm) "a2i" // arg2 = RexrReg(rde) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call function (d1) RexrReg(rde), d1); } } else if (Rep(rde) == 3) { union FloatPun x, y; y.i = Read32(GetModrmRegisterXmmPointerRead4(A)); x.i = Read32(XmmRexrReg(m, rde)); x.f = fs(x.f, y.f); Write32(XmmRexrReg(m, rde), x.i); if (IsMakingPath(m)) { Jitter(A, "z4P" // res0 = GetXmmOrMemPointer(RexbRm) "a2i" // arg2 = RexrReg(rde) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call function (d1) RexrReg(rde), s1); } } else if (Osz(rde)) { u8 *p; union DoublePun x[2], y[2]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read64(p + 0 * 8); y[1].i = Read64(p + 1 * 8); p = XmmRexrReg(m, rde); x[0].i = Read64(p + 0 * 8); x[1].i = Read64(p + 1 * 8); x[0].f = fd(x[0].f, y[0].f); x[1].f = fd(x[1].f, y[1].f); Write64(p + 0 * 8, x[0].i); Write64(p + 1 * 8, x[1].i); } else { u8 *p; union FloatPun x[4], y[4]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read32(p + 0 * 4); y[1].i = Read32(p + 1 * 4); y[2].i = Read32(p + 2 * 4); y[3].i = Read32(p + 3 * 4); p = XmmRexrReg(m, rde); x[0].i = Read32(p + 0 * 4); x[1].i = Read32(p + 1 * 4); x[2].i = Read32(p + 2 * 4); x[3].i = Read32(p + 3 * 4); x[0].f = fs(x[0].f, y[0].f); x[1].f = fs(x[1].f, y[1].f); x[2].f = fs(x[2].f, y[2].f); x[3].f = fs(x[3].f, y[3].f); Write32(p + 0 * 4, x[0].i); Write32(p + 1 * 4, x[1].i); Write32(p + 2 * 4, x[2].i); Write32(p + 3 * 4, x[3].i); } IGNORE_RACES_END(); } static inline float Adds(float x, float y) { return x + y; } static inline double Addd(double x, double y) { return x + y; } void OpAddpsd(P) { OpPsd(A, Adds, Addd, OpPsdAdds1, OpPsdAddd1); } static inline float Subs(float x, float y) { return x - y; } static inline double Subd(double x, double y) { return x - y; } void OpSubpsd(P) { OpPsd(A, Subs, Subd, OpPsdSubs1, OpPsdSubd1); } static inline float Muls(float x, float y) { return x * y; } static inline double Muld(double x, double y) { return x * y; } void OpMulpsd(P) { OpPsd(A, Muls, Muld, OpPsdMuls1, OpPsdMuld1); } static inline float Divs(float x, float y) { return x / y; } static inline double Divd(double x, double y) { return x / y; } void OpDivpsd(P) { OpPsd(A, Divs, Divd, OpPsdDivs1, OpPsdDivd1); } static inline float Mins(float x, float y) { return MIN(x, y); } static inline double Mind(double x, double y) { return MIN(x, y); } void OpMinpsd(P) { OpPsd(A, Mins, Mind, OpPsdMins1, OpPsdMind1); } static inline float Maxs(float x, float y) { return MAX(x, y); } static inline double Maxd(double x, double y) { return MAX(x, y); } void OpMaxpsd(P) { OpPsd(A, Maxs, Maxd, OpPsdMaxs1, OpPsdMaxd1); } static int Cmps(int imm, float x, float y) { switch (imm) { case 0: return x == y ? -1 : 0; case 1: return x < y ? -1 : 0; case 2: return x <= y ? -1 : 0; case 3: return isnan(x) || isnan(y) ? -1 : 0; case 4: return x != y ? -1 : 0; case 5: return x >= y ? -1 : 0; case 6: return x > y ? -1 : 0; case 7: return !(isnan(x) || isnan(y)) ? -1 : 0; default: return 0; } } static i32 Cmpd(int imm, double x, double y) { switch (imm) { case 0: return x == y ? -1 : 0; case 1: return x < y ? -1 : 0; case 2: return x <= y ? -1 : 0; case 3: return isnan(x) || isnan(y) ? -1 : 0; case 4: return x != y ? -1 : 0; case 5: return x >= y ? -1 : 0; case 6: return x > y ? -1 : 0; case 7: return !(isnan(x) || isnan(y)) ? -1 : 0; default: return 0; } } void OpCmppsd(P) { IGNORE_RACES_START(); int imm = uimm0; if (Rep(rde) == 2) { union DoublePun x, y; y.i = Read64(GetModrmRegisterXmmPointerRead8(A)); x.i = Read64(XmmRexrReg(m, rde)); x.f = Cmpd(imm, x.f, y.f); Write64(XmmRexrReg(m, rde), x.i); } else if (Rep(rde) == 3) { union FloatPun x, y; y.i = Read32(GetModrmRegisterXmmPointerRead4(A)); x.i = Read32(XmmRexrReg(m, rde)); x.f = Cmps(imm, x.f, y.f); Write32(XmmRexrReg(m, rde), x.i); } else if (Osz(rde)) { u8 *p; union DoublePun x[2], y[2]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read64(p + 0 * 8); y[1].i = Read64(p + 1 * 8); p = XmmRexrReg(m, rde); x[0].i = Read64(p + 0 * 8); x[1].i = Read64(p + 1 * 8); x[0].f = Cmpd(imm, x[0].f, y[0].f); x[1].f = Cmpd(imm, x[1].f, y[1].f); Write64(p + 0 * 8, x[0].i); Write64(p + 1 * 8, x[1].i); } else { u8 *p; union FloatPun x[4], y[4]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read32(p + 0 * 4); y[1].i = Read32(p + 1 * 4); y[2].i = Read32(p + 2 * 4); y[3].i = Read32(p + 3 * 4); p = XmmRexrReg(m, rde); x[0].i = Read32(p + 0 * 4); x[1].i = Read32(p + 1 * 4); x[2].i = Read32(p + 2 * 4); x[3].i = Read32(p + 3 * 4); x[0].f = Cmps(imm, x[0].f, y[0].f); x[1].f = Cmps(imm, x[1].f, y[1].f); x[2].f = Cmps(imm, x[2].f, y[2].f); x[3].f = Cmps(imm, x[3].f, y[3].f); Write32(p + 0 * 4, x[0].i); Write32(p + 1 * 4, x[1].i); Write32(p + 2 * 4, x[2].i); Write32(p + 3 * 4, x[3].i); } IGNORE_RACES_END(); } void OpAndpsd(P) { IGNORE_RACES_START(); u64 x[2], y[2]; memcpy(x, XmmRexrReg(m, rde), 16); memcpy(y, GetModrmRegisterXmmPointerRead16(A), 16); x[0] &= y[0]; x[1] &= y[1]; memcpy(XmmRexrReg(m, rde), x, 16); IGNORE_RACES_END(); } void OpAndnpsd(P) { IGNORE_RACES_START(); u64 x[2], y[2]; memcpy(x, XmmRexrReg(m, rde), 16); memcpy(y, GetModrmRegisterXmmPointerRead16(A), 16); x[0] = ~x[0] & y[0]; x[1] = ~x[1] & y[1]; memcpy(XmmRexrReg(m, rde), x, 16); IGNORE_RACES_END(); } void OpOrpsd(P) { IGNORE_RACES_START(); u64 x[2], y[2]; memcpy(x, XmmRexrReg(m, rde), 16); memcpy(y, GetModrmRegisterXmmPointerRead16(A), 16); x[0] |= y[0]; x[1] |= y[1]; memcpy(XmmRexrReg(m, rde), x, 16); IGNORE_RACES_END(); } void OpXorpsd(P) { IGNORE_RACES_START(); u64 x[2], y[2]; memcpy(x, XmmRexrReg(m, rde), 16); memcpy(y, GetModrmRegisterXmmPointerRead16(A), 16); x[0] ^= y[0]; x[1] ^= y[1]; memcpy(XmmRexrReg(m, rde), x, 16); IGNORE_RACES_END(); } void OpHaddpsd(P) { IGNORE_RACES_START(); u8 *p; if (Rep(rde) == 2) { union FloatPun x[4], y[4], z[4]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read32(p + 0 * 4); y[1].i = Read32(p + 1 * 4); y[2].i = Read32(p + 2 * 4); y[3].i = Read32(p + 3 * 4); p = XmmRexrReg(m, rde); x[0].i = Read32(p + 0 * 4); x[1].i = Read32(p + 1 * 4); x[2].i = Read32(p + 2 * 4); x[3].i = Read32(p + 3 * 4); z[0].f = x[0].f + x[1].f; z[1].f = x[2].f + x[3].f; z[2].f = y[0].f + y[1].f; z[3].f = y[2].f + y[3].f; Write32(p + 0 * 4, z[0].i); Write32(p + 1 * 4, z[1].i); Write32(p + 2 * 4, z[2].i); Write32(p + 3 * 4, z[3].i); } else if (Osz(rde)) { union DoublePun x[2], y[2], z[2]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read64(p + 0 * 8); y[1].i = Read64(p + 1 * 8); p = XmmRexrReg(m, rde); x[0].i = Read64(p + 0 * 8); x[1].i = Read64(p + 1 * 8); z[0].f = x[0].f + x[1].f; z[1].f = y[0].f + y[1].f; Write64(p + 0 * 8, z[0].i); Write64(p + 1 * 8, z[1].i); } else { OpUdImpl(m); } IGNORE_RACES_END(); } void OpHsubpsd(P) { IGNORE_RACES_START(); u8 *p; if (Rep(rde) == 2) { union FloatPun x[4], y[4], z[4]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read32(p + 0 * 4); y[1].i = Read32(p + 1 * 4); y[2].i = Read32(p + 2 * 4); y[3].i = Read32(p + 3 * 4); p = XmmRexrReg(m, rde); x[0].i = Read32(p + 0 * 4); x[1].i = Read32(p + 1 * 4); x[2].i = Read32(p + 2 * 4); x[3].i = Read32(p + 3 * 4); z[0].f = x[0].f - x[1].f; z[1].f = x[2].f - x[3].f; z[2].f = y[0].f - y[1].f; z[3].f = y[2].f - y[3].f; Write32(p + 0 * 4, z[0].i); Write32(p + 1 * 4, z[1].i); Write32(p + 2 * 4, z[2].i); Write32(p + 3 * 4, z[3].i); } else if (Osz(rde)) { union DoublePun x[2], y[2], z[2]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read64(p + 0 * 8); y[1].i = Read64(p + 1 * 8); p = XmmRexrReg(m, rde); x[0].i = Read64(p + 0 * 8); x[1].i = Read64(p + 1 * 8); z[0].f = x[0].f - x[1].f; z[1].f = y[0].f - y[1].f; Write64(p + 0 * 8, z[0].i); Write64(p + 1 * 8, z[1].i); } else { OpUdImpl(m); } IGNORE_RACES_END(); } void OpAddsubpsd(P) { IGNORE_RACES_START(); u8 *p; if (Rep(rde) == 2) { union FloatPun x[4], y[4], z[4]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read32(p + 0 * 4); y[1].i = Read32(p + 1 * 4); y[2].i = Read32(p + 2 * 4); y[3].i = Read32(p + 3 * 4); p = XmmRexrReg(m, rde); x[0].i = Read32(p + 0 * 4); x[1].i = Read32(p + 1 * 4); x[2].i = Read32(p + 2 * 4); x[3].i = Read32(p + 3 * 4); z[0].f = x[0].f - y[0].f; z[1].f = x[1].f + y[1].f; z[2].f = x[2].f - y[2].f; z[3].f = x[3].f + y[3].f; Write32(p + 0 * 4, z[0].i); Write32(p + 1 * 4, z[1].i); Write32(p + 2 * 4, z[2].i); Write32(p + 3 * 4, z[3].i); } else if (Osz(rde)) { union DoublePun x[2], y[2], z[2]; p = GetModrmRegisterXmmPointerRead16(A); y[0].i = Read64(p + 0 * 8); y[1].i = Read64(p + 1 * 8); p = XmmRexrReg(m, rde); x[0].i = Read64(p + 0 * 8); x[1].i = Read64(p + 1 * 8); z[0].f = x[0].f - y[0].f; z[1].f = x[1].f + y[1].f; Write64(p + 0 * 8, z[0].i); Write64(p + 1 * 8, z[1].i); } else { OpUdImpl(m); } IGNORE_RACES_END(); } ================================================ FILE: blink/ssemov.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/biosrom.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/intrin.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/stats.h" #include "blink/tsan.h" static u32 pmovmskb(const u8 p[16]) { #if X86_INTRINSICS return __builtin_ia32_pmovmskb128(*(char_xmma_t *)p); #else u32 i, m; for (m = i = 0; i < 16; ++i) { if (p[i] & 0x80) m |= 1 << i; } return m; #endif } static void MovdquVdqWdq(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(A), 16); IGNORE_RACES_END(); if (IsMakingPath(m)) { Jitter(A, "z4B" // 128-bit GetRegOrMem "z4C"); // 128-bit PutReg } } static void MovdquWdqVdq(P) { IGNORE_RACES_START(); memcpy(GetModrmRegisterXmmPointerWrite16(A), XmmRexrReg(m, rde), 16); IGNORE_RACES_END(); if (IsMakingPath(m)) { Jitter(A, "z4A" // 128-bit GetReg "z4D"); // 128-bit PutRegOrMem } } static void MovupsVpsWps(P) { MovdquVdqWdq(A); } static void MovupsWpsVps(P) { MovdquWdqVdq(A); } static void MovupdVpsWps(P) { MovdquVdqWdq(A); } static void MovupdWpsVps(P) { MovdquWdqVdq(A); } void OpLddquVdqMdq(P) { MovdquVdqWdq(A); } void OpMovntiMdqpGdqp(P) { IGNORE_RACES_START(); if (Rexw(rde)) { memcpy(ComputeReserveAddressWrite8(A), XmmRexrReg(m, rde), 8); } else { memcpy(ComputeReserveAddressWrite4(A), XmmRexrReg(m, rde), 4); } IGNORE_RACES_END(); } static void MovdqaVdqWdq(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), GetXmmAddress(A), 16); IGNORE_RACES_END(); if (IsMakingPath(m)) { Jitter(A, "z4B" // 128-bit GetRegOrMem "z4C"); // 128-bit PutReg } } static void MovdqaWdqVdq(P) { u8 *dst; IGNORE_RACES_START(); dst = GetXmmAddress(A); if (!IsRomAddress(m, dst)) { memcpy(dst, XmmRexrReg(m, rde), 16); } IGNORE_RACES_END(); if (IsMakingPath(m)) { Jitter(A, "z4A" // 128-bit GetReg "z4D"); // 128-bit PutRegOrMem } } static void MovntdqMdqVdq(P) { MovdqaWdqVdq(A); } static void MovntpsMpsVps(P) { MovdqaWdqVdq(A); } static void MovntpdMpdVpd(P) { MovdqaWdqVdq(A); } void OpMovntdqaVdqMdq(P) { MovdqaVdqWdq(A); } static void MovqPqQq(P) { IGNORE_RACES_START(); memcpy(MmReg(m, rde), GetModrmRegisterMmPointerRead8(A), 8); IGNORE_RACES_END(); } static void MovqQqPq(P) { IGNORE_RACES_START(); memcpy(GetModrmRegisterMmPointerWrite8(A), MmReg(m, rde), 8); IGNORE_RACES_END(); } static void MovqVdqEqp(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead8(A), 8); IGNORE_RACES_END(); memset(XmmRexrReg(m, rde) + 8, 0, 8); if (IsMakingPath(m)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "r1i" // res1 = zero "z4C", // PutReg[force128bit](RexrReg, res0, res1) 0); } } static void MovdVdqEd(P) { memset(XmmRexrReg(m, rde), 0, 16); IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead4(A), 4); IGNORE_RACES_END(); } static void MovqPqEqp(P) { IGNORE_RACES_START(); memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead8(A), 8); IGNORE_RACES_END(); } static void MovdPqEd(P) { IGNORE_RACES_START(); memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead4(A), 4); IGNORE_RACES_END(); memset(MmReg(m, rde) + 4, 0, 4); } static void MovdEdVdq(P) { if (IsModrmRegister(rde)) { Put64(RegRexbRm(m, rde), Read32(XmmRexrReg(m, rde))); } else { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite4(A), XmmRexrReg(m, rde), 4); IGNORE_RACES_END(); } } static void MovqEqpVdq(P) { IGNORE_RACES_START(); memcpy(GetModrmRegisterWordPointerWrite8(A), XmmRexrReg(m, rde), 8); IGNORE_RACES_END(); if (IsMakingPath(m)) { Jitter(A, "z4A" // res0,res1 = GetReg[force128bit](RexrReg) "r0z3D"); // PutRegOrMem[force64bit](RexbRm, res0) } } static void MovdEdPq(P) { if (IsModrmRegister(rde)) { Put64(RegRexbRm(m, rde), Read32(MmReg(m, rde))); } else { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite4(A), MmReg(m, rde), 4); IGNORE_RACES_END(); } } static void MovqEqpPq(P) { IGNORE_RACES_START(); memcpy(GetModrmRegisterWordPointerWrite8(A), MmReg(m, rde), 8); IGNORE_RACES_END(); } static void MovntqMqPq(P) { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite8(A), MmReg(m, rde), 8); IGNORE_RACES_END(); } static void MovqVqWq(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(A), 8); IGNORE_RACES_END(); memset(XmmRexrReg(m, rde) + 8, 0, 8); } static void MovssVpsWps(P) { if (IsModrmRegister(rde)) { memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 4); } else { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead4(A), 4); IGNORE_RACES_END(); memset(XmmRexrReg(m, rde) + 4, 0, 12); } } static void MovssWpsVps(P) { IGNORE_RACES_START(); memcpy(GetModrmRegisterXmmPointerWrite4(A), XmmRexrReg(m, rde), 4); IGNORE_RACES_END(); } static void MovsdVpsWps(P) { if (IsModrmRegister(rde)) { memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 8); } else { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(A), 8); IGNORE_RACES_END(); memset(XmmRexrReg(m, rde) + 8, 0, 8); if (IsMakingPath(m)) { Jitter(A, "z3B" // res0 = Get.....Mem[force64bit](RexbRm) "r1i" // res1 = 0 "z4C", // 128-bit PutReg (u64)0); } } } static void MovsdWpsVps(P) { IGNORE_RACES_START(); memcpy(GetModrmRegisterXmmPointerWrite8(A), XmmRexrReg(m, rde), 8); IGNORE_RACES_END(); if (IsMakingPath(m)) { Jitter(A, "z4P" // res0 = GetXmmOrMemPointer(RexbRm) "a2i" // arg2 = RexrReg(rde) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call function (d1) RexrReg(rde), MovsdWpsVpsOp); } } static void MovhlpsVqUq(P) { memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde) + 8, 8); } static void MovlpsVqMq(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(A), 8); IGNORE_RACES_END(); } static void MovlpdVqMq(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(A), 8); IGNORE_RACES_END(); } static void MovddupVqWq(P) { u8 *src = GetModrmRegisterXmmPointerRead8(A); IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde) + 0, src, 8); memcpy(XmmRexrReg(m, rde) + 8, src, 8); IGNORE_RACES_END(); } static void MovsldupVqWq(P) { u8 *dst, *src; dst = XmmRexrReg(m, rde); src = GetModrmRegisterXmmPointerRead16(A); IGNORE_RACES_START(); memcpy(dst + 0 + 0, src + 0, 4); memcpy(dst + 0 + 4, src + 0, 4); memcpy(dst + 8 + 0, src + 8, 4); memcpy(dst + 8 + 4, src + 8, 4); IGNORE_RACES_END(); } static void MovlpsMqVq(P) { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite8(A), XmmRexrReg(m, rde), 8); IGNORE_RACES_END(); } static void MovlpdMqVq(P) { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite8(A), XmmRexrReg(m, rde), 8); IGNORE_RACES_END(); } static void MovlhpsVqUq(P) { memcpy(XmmRexrReg(m, rde) + 8, XmmRexbRm(m, rde), 8); } static void MovhpsVqMq(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(A), 8); IGNORE_RACES_END(); } static void MovhpdVqMq(P) { IGNORE_RACES_START(); memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(A), 8); IGNORE_RACES_END(); } static void MovshdupVqWq(P) { u8 *dst, *src; dst = XmmRexrReg(m, rde); src = GetModrmRegisterXmmPointerRead16(A); IGNORE_RACES_START(); memcpy(dst + 0 + 0, src + 04, 4); memcpy(dst + 0 + 4, src + 04, 4); memcpy(dst + 8 + 0, src + 12, 4); memcpy(dst + 8 + 4, src + 12, 4); IGNORE_RACES_END(); } static void MovhpsMqVq(P) { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite8(A), XmmRexrReg(m, rde) + 8, 8); IGNORE_RACES_END(); } static void MovhpdMqVq(P) { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite8(A), XmmRexrReg(m, rde) + 8, 8); IGNORE_RACES_END(); } static void MovqWqVq(P) { if (IsModrmRegister(rde)) { memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 8); memset(XmmRexbRm(m, rde) + 8, 0, 8); } else { IGNORE_RACES_START(); memcpy(ComputeReserveAddressWrite8(A), XmmRexrReg(m, rde), 8); IGNORE_RACES_END(); } } static void Movq2dqVdqNq(P) { memcpy(XmmRexrReg(m, rde), MmRm(m, rde), 8); memset(XmmRexrReg(m, rde) + 8, 0, 8); } static void Movdq2qPqUq(P) { memcpy(MmReg(m, rde), XmmRexbRm(m, rde), 8); } static void MovapsVpsWps(P) { MovdqaVdqWdq(A); } static void MovapdVpdWpd(P) { MovdqaVdqWdq(A); } static void MovapsWpsVps(P) { MovdqaWdqVdq(A); } static void MovapdWpdVpd(P) { MovdqaWdqVdq(A); } void OpMovWpsVps(P) { switch (Rep(rde) | Osz(rde)) { case 0: MovupsWpsVps(A); break; case 1: MovupdWpsVps(A); break; case 2: MovsdWpsVps(A); // hot break; case 3: MovssWpsVps(A); break; default: __builtin_unreachable(); } } void OpMov0f28(P) { if (!Osz(rde)) { MovapsVpsWps(A); } else { MovapdVpdWpd(A); } } void OpMov0f6e(P) { if (Osz(rde)) { if (Rexw(rde)) { MovqVdqEqp(A); } else { MovdVdqEd(A); } } else { if (Rexw(rde)) { MovqPqEqp(A); } else { MovdPqEd(A); } } } void OpMov0f6f(P) { if (Osz(rde)) { MovdqaVdqWdq(A); } else if (Rep(rde) == 3) { MovdquVdqWdq(A); } else { MovqPqQq(A); } } void OpMov0fE7(P) { if (!Osz(rde)) { MovntqMqPq(A); } else { MovntdqMdqVdq(A); } } void OpMov0f7e(P) { if (Rep(rde) == 3) { MovqVqWq(A); } else if (Osz(rde)) { if (Rexw(rde)) { MovqEqpVdq(A); } else { MovdEdVdq(A); } } else { if (Rexw(rde)) { MovqEqpPq(A); } else { MovdEdPq(A); } } } void OpMov0f7f(P) { if (Rep(rde) == 3) { MovdquWdqVdq(A); } else if (Osz(rde)) { MovdqaWdqVdq(A); } else { MovqQqPq(A); } } void OpMov0f10(P) { switch (Rep(rde) | Osz(rde)) { case 0: MovupsVpsWps(A); break; case 1: MovupdVpsWps(A); break; case 2: MovsdVpsWps(A); break; case 3: MovssVpsWps(A); break; default: __builtin_unreachable(); } } void OpMov0f29(P) { if (!Osz(rde)) { MovapsWpsVps(A); } else { MovapdWpdVpd(A); } } void OpMov0f2b(P) { if (!Osz(rde)) { MovntpsMpsVps(A); } else { MovntpdMpdVpd(A); } } void OpMov0f12(P) { switch (Rep(rde) | Osz(rde)) { case 0: if (IsModrmRegister(rde)) { MovhlpsVqUq(A); } else { MovlpsVqMq(A); } break; case 1: MovlpdVqMq(A); break; case 2: MovddupVqWq(A); break; case 3: MovsldupVqWq(A); break; default: __builtin_unreachable(); } } void OpMov0f13(P) { if (Osz(rde)) { MovlpdMqVq(A); } else { MovlpsMqVq(A); } } void OpMov0f16(P) { switch (Rep(rde) | Osz(rde)) { case 0: if (IsModrmRegister(rde)) { MovlhpsVqUq(A); } else { MovhpsVqMq(A); } break; case 1: MovhpdVqMq(A); break; case 3: MovshdupVqWq(A); break; default: OpUdImpl(m); break; } } void OpMov0f17(P) { if (Osz(rde)) { MovhpdMqVq(A); } else { MovhpsMqVq(A); } } void OpMov0fD6(P) { if (Rep(rde) == 3) { Movq2dqVdqNq(A); } else if (Rep(rde) == 2) { Movdq2qPqUq(A); } else if (Osz(rde)) { MovqWqVq(A); } else { OpUdImpl(m); } } void OpPmovmskbGdqpNqUdq(P) { Put64(RegRexrReg(m, rde), pmovmskb(XmmRexbRm(m, rde)) & (Osz(rde) ? 0xffff : 0xff)); } void OpMaskMovDiXmmRegXmmRm(P) { void *p[2]; u64 v; unsigned i, n; u8 *mem, b[16]; v = AddressDi(A); n = Osz(rde) ? 16 : 8; mem = BeginStore(m, v, n, p, b); for (i = 0; i < n; ++i) { if (XmmRexbRm(m, rde)[i] & 0x80) { mem[i] = XmmRexrReg(m, rde)[i]; } } EndStore(m, v, n, p, b); } ================================================ FILE: blink/stack.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/tsan.h" #include "blink/x86.h" static const u8 kStackOsz[2][3] = {{4, 4, 8}, {2, 2, 2}}; static const u8 kCallOsz[2][3] = {{4, 4, 8}, {2, 2, 8}}; static void WriteStackWord(u8 *p, u64 rde, u32 osz, u64 x) { IGNORE_RACES_START(); if (osz == 8) { Write64(p, x); } else if (osz == 2) { Write16(p, x); } else { Write32(p, x); } IGNORE_RACES_END(); } static u64 ReadStackWord(u8 *p, u32 osz) { u64 x; IGNORE_RACES_START(); if (osz == 8) { x = Read64(p); } else if (osz == 2) { x = Read16(p); } else { x = Read32(p); } IGNORE_RACES_END(); return x; } static void WriteMemWord(u8 *p, u64 rde, u32 osz, u64 x) { if (osz == 8) { Store64(p, x); } else if (osz == 2) { Store16(p, x); } else { Store32(p, x); } } static u64 ReadMemWord(u8 *p, u32 osz) { u64 x; if (osz == 8) { x = Load64(p); } else if (osz == 2) { x = Load16(p); } else { x = Load32(p); } return x; } static void PushN(P, u64 x, unsigned mode, unsigned osz) { u8 *w; u64 v; u8 b[8]; void *p[2]; switch (mode) { case XED_MODE_REAL: v = (Get32(m->sp) - osz) & 0xffff; Put16(m->sp, v); v += m->ss.base; break; case XED_MODE_LEGACY: v = (Get32(m->sp) - osz) & 0xffffffff; Put64(m->sp, v); v += m->ss.base; break; case XED_MODE_LONG: v = (Get64(m->sp) - osz) & 0xffffffffffffffff; Put64(m->sp, v); break; default: __builtin_unreachable(); } w = AccessRam(m, v, osz, p, b, false); WriteStackWord(w, rde, osz, x); EndStore(m, v, osz, p, b); } void Push(P, u64 x) { PushN(A, x, Mode(rde), kStackOsz[Osz(rde)][Mode(rde)]); } void OpPushZvq(P) { int osz = kStackOsz[Osz(rde)][Mode(rde)]; PushN(A, ReadStackWord(RegRexbSrm(m, rde), osz), Mode(rde), osz); if (IsMakingPath(m) && HasLinearMapping() && !Osz(rde)) { Jitter(A, "a1i" "m", RexbSrm(rde), FastPush); } } static u64 PopN(P, u16 extra, unsigned osz) { u64 v; u8 b[8]; void *p[2]; switch (Mode(rde)) { case XED_MODE_LONG: v = Get64(m->sp); Put64(m->sp, v + osz + extra); break; case XED_MODE_LEGACY: v = Get32(m->sp); Put64(m->sp, (v + osz + extra) & 0xffffffff); v += m->ss.base; break; case XED_MODE_REAL: v = Get16(m->sp); Put16(m->sp, v + osz + extra); v += m->ss.base; break; default: __builtin_unreachable(); } return ReadStackWord(AccessRam(m, v, osz, p, b, true), osz); } u64 Pop(P, u16 extra) { return PopN(A, extra, kStackOsz[Osz(rde)][Mode(rde)]); } void OpPopZvq(P) { u64 x; int osz; osz = kStackOsz[Osz(rde)][Mode(rde)]; x = PopN(A, 0, osz); switch (osz) { case 8: case 4: Put64(RegRexbSrm(m, rde), x); break; case 2: Put16(RegRexbSrm(m, rde), x); break; default: __builtin_unreachable(); } if (IsMakingPath(m) && HasLinearMapping() && !Osz(rde)) { Jitter(A, "a1i" "m", RexbSrm(rde), FastPop); } } static void OpCall(P, u64 func) { PushN(A, m->ip, Mode(rde), kCallOsz[Osz(rde)][Mode(rde)]); m->ip = func; } void OpCallJvds(P) { OpCall(A, m->ip + disp); if (HasLinearMapping() && IsMakingPath(m)) { Terminate(A, FastCall); } } static u64 LoadAddressFromMemory(P) { unsigned osz = kCallOsz[Osz(rde)][Mode(rde)]; return ReadMemWord(GetModrmRegisterWordPointerRead(A, osz), osz); } void OpCallEq(P) { if (IsMakingPath(m) && HasLinearMapping() && !Osz(rde)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call micro-op (FastCallAbs) FastCallAbs); } OpCall(A, LoadAddressFromMemory(A)); } void OpJmpEq(P) { if (IsMakingPath(m) && HasLinearMapping() && !Osz(rde)) { Jitter(A, "z3B" // res0 = GetRegOrMem[force64bit](RexbRm) "s0a1=" // arg1 = machine "t" // arg0 = res0 "m", // call micro-op (FastJmpAbs) FastJmpAbs); } m->ip = LoadAddressFromMemory(A); } void OpEnter(P) { u16 allocsz = (u16)uimm0; u8 nesting = (u8)(uimm0 >> 16); unsigned osz = kStackOsz[Osz(rde)][Mode(rde)]; if (nesting != 0) OpUdImpl(m); Push(A, Get64(m->bp)); switch (osz) { case 8: Put64(m->bp, Get64(m->sp)); Put64(m->sp, Get64(m->sp) - allocsz); break; case 4: Put64(m->bp, Get32(m->sp)); Put64(m->sp, Get32(m->sp) - allocsz); break; case 2: Put16(m->bp, Get16(m->sp)); Put16(m->sp, Get16(m->sp) - allocsz); break; default: __builtin_unreachable(); } } void OpLeave(P) { unsigned osz = kStackOsz[Osz(rde)][Mode(rde)]; switch (osz) { case 8: Put64(m->sp, Get64(m->bp)); Put64(m->bp, Pop(A, 0)); if (HasLinearMapping() && IsMakingPath(m)) { Jitter(A, "m", FastLeave); } break; case 4: Put64(m->sp, Get32(m->bp)); Put64(m->bp, PopN(A, osz, 0)); break; case 2: Put16(m->sp, Get16(m->bp)); Put16(m->bp, PopN(A, osz, 0)); break; default: __builtin_unreachable(); } } void OpRet(P) { m->ip = Pop(A, 0); if (IsMakingPath(m) && HasLinearMapping() && !Osz(rde)) { #ifdef __x86_64__ Jitter(A, "a1i" // arg1 = prediction "m" // call micro-op (PredictRet) "q", // arg0 = machine m->ip, PredictRet); AlignJit(m->path.jb, 8, 3); u8 code[] = { 0x48, 0x85, 0300 | kJitRes0 << 3 | kJitRes0, // test %rax,%rax 0x75, 0x05, // jnz +5 }; #else Jitter(A, "a1i" // arg1 = prediction "m" // call micro-op (PredictRet) "r0a2=" // arg2 = res0 "q", // arg0 = machine m->ip, PredictRet); u32 code[] = { 0xb5000000 | (8 / 4) << 5 | kJitArg2, // cbnz x2,#8 }; #endif AppendJit(m->path.jb, code, sizeof(code)); Connect(A, m->ip, true); AppendJitJump(m->path.jb, (void *)m->system->ender); FinishPath(m); } } relegated void OpRetIw(P) { m->ip = Pop(A, uimm0); } void OpPushEvq(P) { unsigned osz = kStackOsz[Osz(rde)][Mode(rde)]; Push(A, ReadMemWord(GetModrmRegisterWordPointerRead(A, osz), osz)); } void OpPopEvq(P) { unsigned osz = kStackOsz[Osz(rde)][Mode(rde)]; WriteMemWord(GetModrmRegisterWordPointerWrite(A, osz), rde, osz, Pop(A, 0)); } ================================================ FILE: blink/startdir.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/util.h" static char *g_startdir; static void FreeStartDir(void) { free(g_startdir); g_startdir = 0; } char *GetStartDir(void) { if (!g_startdir) { char cwd[PATH_MAX]; if (!getcwd(cwd, sizeof(cwd))) strcpy(cwd, "."); g_startdir = strdup(cwd); atexit(FreeStartDir); } return g_startdir; } ================================================ FILE: blink/startswith.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/util.h" bool StartsWith(const char *s, const char *p) { for (;;) { if (!*p) return true; if (!*s) return false; if (*s++ != *p++) return false; } } ================================================ FILE: blink/statfs.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include // ordering matters on openbsd #include #include #include #include #include #include "blink/endian.h" #include "blink/errno.h" #include "blink/linux.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/syscall.h" #include "blink/types.h" #ifdef __linux #include #endif #if defined(HAVE_SYS_MOUNT_H) && !defined(_POSIX_C_SOURCE) #include #endif #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)) && \ !defined(_POSIX_C_SOURCE) #include #endif struct FsId { u32 val[2]; }; static unsigned long XlatStatvfsFlags(unsigned long flags) { unsigned long res = 0; #ifdef MNT_RDONLY if ((flags & MNT_RDONLY) == MNT_RDONLY) res |= ST_RDONLY_LINUX; #elif defined(ST_RDONLY) if ((flags & ST_RDONLY) == ST_RDONLY) res |= ST_RDONLY_LINUX; #endif #ifdef MNT_NOSUID if ((flags & MNT_NOSUID) == MNT_NOSUID) res |= ST_NOSUID_LINUX; #elif defined(ST_NOSUID) if ((flags & ST_NOSUID) == ST_NOSUID) res |= ST_NOSUID_LINUX; #endif #ifdef MNT_NODEV if ((flags & MNT_NODEV) == MNT_NODEV) res |= ST_NODEV_LINUX; #elif defined(ST_NODEV) if ((flags & ST_NODEV) == ST_NODEV) res |= ST_NODEV_LINUX; #endif #ifdef MNT_NOEXEC if ((flags & MNT_NOEXEC) == MNT_NOEXEC) res |= ST_NOEXEC_LINUX; #elif defined(ST_NOEXEC) if ((flags & ST_NOEXEC) == ST_NOEXEC) res |= ST_NOEXEC_LINUX; #endif #ifdef MNT_SYNCHRONOUS if ((flags & MNT_SYNCHRONOUS) == MNT_SYNCHRONOUS) res |= ST_SYNCHRONOUS_LINUX; #elif defined(ST_SYNCHRONOUS) if ((flags & ST_SYNCHRONOUS) == ST_SYNCHRONOUS) res |= ST_SYNCHRONOUS_LINUX; #endif #ifdef MNT_NOATIME if ((flags & MNT_NOATIME) == MNT_NOATIME) res |= ST_NOATIME_LINUX; #elif defined(ST_NOATIME) if ((flags & ST_NOATIME) == ST_NOATIME) res |= ST_NOATIME_LINUX; #endif #ifdef MNT_RELATIME if ((flags & MNT_RELATIME) == MNT_RELATIME) res |= ST_RELATIME_LINUX; #elif defined(ST_RELATIME) if ((flags & ST_RELATIME) == ST_RELATIME) res |= ST_RELATIME_LINUX; #endif #ifdef MNT_APPEND if ((flags & MNT_APPEND) == MNT_APPEND) res |= ST_APPEND_LINUX; #elif defined(ST_APPEND) if ((flags & ST_APPEND) == ST_APPEND) res |= ST_APPEND_LINUX; #endif #ifdef MNT_IMMUTABLE if ((flags & MNT_IMMUTABLE) == MNT_IMMUTABLE) res |= ST_IMMUTABLE_LINUX; #elif defined(ST_IMMUTABLE) if ((flags & ST_IMMUTABLE) == ST_IMMUTABLE) res |= ST_IMMUTABLE_LINUX; #endif #ifdef MNT_MANDLOCK if ((flags & MNT_MANDLOCK) == MNT_MANDLOCK) res |= ST_MANDLOCK_LINUX; #elif defined(ST_MANDLOCK) if ((flags & ST_MANDLOCK) == ST_MANDLOCK) res |= ST_MANDLOCK_LINUX; #endif #ifdef MNT_NODIRATIME if ((flags & MNT_NODIRATIME) == MNT_NODIRATIME) res |= ST_NODIRATIME_LINUX; #elif defined(ST_NODIRATIME) if ((flags & ST_NODIRATIME) == ST_NODIRATIME) res |= ST_NODIRATIME_LINUX; #endif #ifdef MNT_WRITE if ((flags & MNT_WRITE) == MNT_WRITE) res |= ST_WRITE_LINUX; #elif defined(ST_WRITE) if ((flags & ST_WRITE) == ST_WRITE) res |= ST_WRITE_LINUX; #endif return res; } static int ConvertBsdFsTypeNameToLinux(const char *fstypename) { size_t i; static const struct FsTypeName { char name[8]; u32 lunix; } kFsTypeName[] = { {"apfs", 0x4253584e}, // {"zfs", 0x2fc12fc1}, // {"ufs", 0x00011954}, // {"iso9660", 0x9660}, // {"ext", 0x4244}, // {"ext2fs", 0x4244}, // {"hfs", 0x4244}, // {"msdos", 0x4d44}, // {"ntfs", 0x5346544e}, // {"efs", 0x00414a53}, // {"jfs2", 0x3153464a}, // {"udf", 0x15013346}, // {"hpfs", 0xf995e849}, // {"sysv", 0x012ff7b5}, // {"devfs", 0x1373}, // {"procfs", 0x002f}, // {{'l', 'i', 'n', 's', 'y', 's', 'f', 's'}, 0x62656572}, // linsysfs }; for (i = 0; i < ARRAYLEN(kFsTypeName); ++i) { if (Read64((const u8 *)fstypename) == Read64((const u8 *)kFsTypeName[i].name)) { return kFsTypeName[i].lunix; } } return 0; } static void XlatStatvfsToLinux(struct statfs_linux *sf, const void *arg) { #if defined(__linux) && !defined(_POSIX_C_SOURCE) struct FsId fsid; const struct statfs *vfs = (const struct statfs *)arg; memset(sf, 0, sizeof(*sf)); memcpy(&fsid, &vfs->f_fsid, sizeof(fsid)); Write64(sf->type, vfs->f_type); Write64(sf->bsize, vfs->f_bsize); Write64(sf->frsize, vfs->f_frsize); Write64(sf->blocks, vfs->f_blocks); Write64(sf->bfree, vfs->f_bfree); Write64(sf->bavail, vfs->f_bavail); Write64(sf->files, vfs->f_files); Write64(sf->ffree, vfs->f_ffree); Write32(sf->fsid[0], fsid.val[0]); Write32(sf->fsid[1], fsid.val[1]); Write64(sf->flags, XlatStatvfsFlags(vfs->f_flags)); Write64(sf->namelen, vfs->f_namelen); #elif (defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && \ !defined(_POSIX_C_SOURCE) struct FsId fsid; const struct statfs *vfs = (const struct statfs *)arg; memset(sf, 0, sizeof(*sf)); memcpy(&fsid, &vfs->f_fsid, sizeof(fsid)); Write64(sf->type, ConvertBsdFsTypeNameToLinux(vfs->f_fstypename)); Write64(sf->bsize, vfs->f_iosize); Write64(sf->frsize, vfs->f_bsize); Write64(sf->blocks, vfs->f_blocks); Write64(sf->bfree, vfs->f_bfree); Write64(sf->bavail, vfs->f_bavail); Write64(sf->files, vfs->f_files); Write64(sf->ffree, vfs->f_ffree); Write32(sf->fsid[0], fsid.val[0]); Write32(sf->fsid[1], fsid.val[1]); Write64(sf->flags, XlatStatvfsFlags(vfs->f_flags)); #if defined(__APPLE__) || defined(__NetBSD__) Write64(sf->namelen, NAME_MAX); #else Write64(sf->namelen, vfs->f_namemax); #endif #else const struct statvfs *vfs = (const struct statvfs *)arg; memset(sf, 0, sizeof(*sf)); Write64(sf->bsize, vfs->f_bsize); Write64(sf->frsize, vfs->f_frsize); Write64(sf->blocks, vfs->f_blocks); Write64(sf->bfree, vfs->f_bfree); Write64(sf->bavail, vfs->f_bavail); Write64(sf->files, vfs->f_files); Write64(sf->ffree, vfs->f_ffree); Write32(sf->fsid[0], vfs->f_fsid); Write32(sf->fsid[1], (u64)vfs->f_fsid >> 32); Write64(sf->flags, XlatStatvfsFlags(vfs->f_flag)); Write64(sf->namelen, vfs->f_namemax); #endif } #if (defined(__linux) || defined(__APPLE__) || defined(__FreeBSD__) || \ defined(__OpenBSD__)) && \ !defined(_POSIX_C_SOURCE) static int Statfs(uintptr_t arg, struct statfs *buf) { return statfs((const char *)arg, buf); } static int Fstatfs(uintptr_t arg, struct statfs *buf) { return fstatfs((int)arg, buf); } static int SysStatfsImpl(struct Machine *m, uintptr_t arg, i64 addr, int thunk(uintptr_t, struct statfs *)) { int rc; struct statfs vfs; struct statfs_linux sf; if (!IsValidMemory(m, addr, sizeof(sf), PROT_WRITE)) return efault(); RESTARTABLE(rc = thunk(arg, &vfs)); if (rc != -1) { XlatStatvfsToLinux(&sf, &vfs); CopyToUserWrite(m, addr, &sf, sizeof(sf)); } return rc; } #else static int Statfs(uintptr_t arg, struct statvfs *buf) { return statvfs((const char *)arg, buf); } static int Fstatfs(uintptr_t arg, struct statvfs *buf) { return fstatvfs((int)arg, buf); } static int SysStatfsImpl(struct Machine *m, uintptr_t arg, i64 addr, int thunk(uintptr_t, struct statvfs *)) { int rc; struct statvfs vfs; struct statfs_linux sf; if (!IsValidMemory(m, addr, sizeof(sf), PROT_WRITE)) return efault(); RESTARTABLE(rc = thunk(arg, &vfs)); if (rc != -1) { XlatStatvfsToLinux(&sf, &vfs); CopyToUserWrite(m, addr, &sf, sizeof(sf)); } return rc; } #endif int SysStatfs(struct Machine *m, i64 path, i64 addr) { return SysStatfsImpl(m, (uintptr_t)LoadStr(m, path), addr, Statfs); } int SysFstatfs(struct Machine *m, i32 fildes, i64 addr) { return SysStatfsImpl(m, (uintptr_t)(u32)fildes, addr, Fstatfs); } ================================================ FILE: blink/stats.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/stats.h" #include "blink/log.h" #define DEFINE_AVERAGE(S) struct Average S; #define DEFINE_COUNTER(S) long S; #include "blink/stats.inc" #undef DEFINE_AVERAGE #undef DEFINE_COUNTER #define APPEND(...) o += snprintf(b + o, o > n ? 0 : n - o, __VA_ARGS__) void PrintStats(void) { #ifndef NDEBUG char b[4096]; int n = sizeof(b); int o = 0; b[0] = 0; #define DEFINE_COUNTER(S) \ if (S) APPEND("%-32s = %ld\n", #S, S); #define DEFINE_AVERAGE(S) \ if (S.a) APPEND("%-32s = %.6g\n", #S, S.a); #include "blink/stats.inc" #undef S WriteErrorString(b); #endif } ================================================ FILE: blink/stats.h ================================================ #ifndef BLINK_STATS_H_ #define BLINK_STATS_H_ #include #include "blink/builtin.h" #include "blink/tsan.h" #ifndef NDEBUG // we don't care about the accuracy of statistics across threads. some // hardware architectures don't even seem to have atomic addition ops. #define STATISTIC(x) \ do { \ IGNORE_RACES_START(); \ x; \ IGNORE_RACES_END(); \ } while (0) #else #define STATISTIC(x) (void)0 #endif #ifdef DEBUG #define COSTLY_STATISTIC(x) STATISTIC(x) #else #define COSTLY_STATISTIC(x) (void)0 #endif #define AVERAGE(S, x) S.a += ((x)-S.a) / ++S.i #ifndef NDEBUG #ifdef __GNUC__ #define GET_COUNTER(S) \ __extension__({ \ IGNORE_RACES_START(); \ long S_ = S; \ IGNORE_RACES_END(); \ S_; \ }) #else #define GET_COUNTER(S) (S) #endif #else #define GET_COUNTER(S) 0L #endif #define DEFINE_COUNTER(S) extern long S; #define DEFINE_AVERAGE(S) extern struct Average S; #include "blink/stats.inc" #undef DEFINE_COUNTER #undef DEFINE_AVERAGE struct Average { double a; long i; }; extern bool FLAG_statistics; void PrintStats(void); #endif /* BLINK_STATS_H_ */ ================================================ FILE: blink/stats.inc ================================================ DEFINE_COUNTER(instructions_cached) DEFINE_COUNTER(instructions_decoded) DEFINE_COUNTER(instructions_dispatched) DEFINE_COUNTER(instructions_jitted) DEFINE_COUNTER(interps) DEFINE_COUNTER(page_locks) DEFINE_COUNTER(page_overlaps) DEFINE_COUNTER(path_count) DEFINE_COUNTER(path_cycles) DEFINE_COUNTER(path_connected_total) DEFINE_COUNTER(path_connected_lazily) DEFINE_COUNTER(path_connected_directly) DEFINE_COUNTER(path_connected_interpreter) DEFINE_COUNTER(path_elements) DEFINE_COUNTER(path_elements_auto) DEFINE_COUNTER(path_longest) DEFINE_COUNTER(path_spliced) DEFINE_COUNTER(path_abandoned) DEFINE_COUNTER(path_longest_bytes) DEFINE_AVERAGE(path_average_bytes) DEFINE_AVERAGE(path_average_elements) DEFINE_COUNTER(path_patches) DEFINE_COUNTER(iov_created) DEFINE_COUNTER(iov_stretches) DEFINE_COUNTER(iov_fragments) DEFINE_COUNTER(iov_reallocs) DEFINE_COUNTER(smc_resets) DEFINE_COUNTER(syscalls) DEFINE_COUNTER(jumps_recorded) DEFINE_COUNTER(jumps_applied) DEFINE_COUNTER(path_ooms) DEFINE_COUNTER(alu_ops) DEFINE_COUNTER(freelisted) DEFINE_COUNTER(alu_unflagged) DEFINE_COUNTER(alu_simplified) DEFINE_COUNTER(fused_branches) DEFINE_COUNTER(tlb_hits) DEFINE_COUNTER(tlb_misses) DEFINE_COUNTER(tlb_resets) DEFINE_COUNTER(icache_resets) DEFINE_AVERAGE(jit_average_block) DEFINE_COUNTER(jit_blocks_retired) DEFINE_COUNTER(jit_blocks_wired) DEFINE_COUNTER(jit_blocks_killed) DEFINE_COUNTER(jit_max_paths_per_block) DEFINE_COUNTER(jit_max_edges_per_page) DEFINE_COUNTER(jit_cycles_avoided) DEFINE_COUNTER(jit_pages_hits_1) DEFINE_COUNTER(jit_pages_hits_2) DEFINE_COUNTER(jit_hooks_staged) DEFINE_COUNTER(jit_hooks_installed) DEFINE_COUNTER(jit_hooks_clobbered) DEFINE_COUNTER(jit_hooks_deleted) DEFINE_COUNTER(jit_hash_lookups) DEFINE_COUNTER(jit_hash_collisions) DEFINE_COUNTER(jit_hash_elements) DEFINE_COUNTER(jit_page_resets) DEFINE_AVERAGE(jit_page_resets_average_hooks) DEFINE_AVERAGE(jit_page_average_bits) DEFINE_COUNTER(jit_reallocs) DEFINE_COUNTER(jit_callocs) DEFINE_COUNTER(jit_frees) DEFINE_COUNTER(jit_ints_alloc_freelist) DEFINE_COUNTER(jit_ints_alloc_slab) DEFINE_COUNTER(jit_ints_alloc_system) DEFINE_COUNTER(jit_jump_alloc_freelist) DEFINE_COUNTER(jit_jump_alloc_system) DEFINE_COUNTER(jit_NewJitJump) DEFINE_COUNTER(jit_NewJitPage) DEFINE_COUNTER(jit_NewJitBlock) DEFINE_COUNTER(jit_NewJitStage) DEFINE_COUNTER(smc_checks) DEFINE_COUNTER(smc_flushes) DEFINE_COUNTER(smc_enqueued) DEFINE_COUNTER(smc_segfaults) DEFINE_AVERAGE(redraw_latency_us) DEFINE_AVERAGE(redraw_compressed_bytes) DEFINE_AVERAGE(redraw_uncompressed_bytes) DEFINE_COUNTER(x1) DEFINE_COUNTER(x2) DEFINE_COUNTER(x3) DEFINE_COUNTER(x4) DEFINE_COUNTER(x5) DEFINE_COUNTER(x6) DEFINE_COUNTER(x7) DEFINE_COUNTER(x8) DEFINE_COUNTER(x9) DEFINE_COUNTER(x10) ================================================ FILE: blink/strace.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/strace.h" #include #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/bitscan.h" #include "blink/describeflags.h" #include "blink/endian.h" #include "blink/fds.h" #include "blink/flag.h" #include "blink/linux.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/thread.h" #include "blink/util.h" #define APPEND(...) bi += snprintf(bp + bi, bi > bn ? 0 : bn - bi, __VA_ARGS__) struct MagicNumber { int x; const char *s; }; static const char *const kOpenAccmode[] = { "O_RDONLY", // "O_WRONLY", // "O_RDWR", // }; static const struct DescribeFlagz kAccessModes[] = { {R_OK_LINUX, "R_OK"}, // {W_OK_LINUX, "W_OK"}, // {X_OK_LINUX, "X_OK"}, // }; static const struct DescribeFlagz kOpenFlags[] = { {O_APPEND_LINUX, "APPEND"}, // {O_CREAT_LINUX, "CREAT"}, // {O_EXCL_LINUX, "EXCL"}, // {O_TRUNC_LINUX, "TRUNC"}, // {O_NDELAY_LINUX, "NDELAY"}, // {O_DIRECT_LINUX, "DIRECT"}, // {O_TMPFILE_LINUX, "TMPFILE"}, // comes before O_DIRECTORY {O_DIRECTORY_LINUX, "DIRECTORY"}, // {O_NOFOLLOW_LINUX, "NOFOLLOW"}, // {O_CLOEXEC_LINUX, "CLOEXEC"}, // {O_NOCTTY_LINUX, "NOCTTY"}, // {O_ASYNC_LINUX, "ASYNC"}, // {O_NOATIME_LINUX, "NOATIME"}, // {O_PATH_LINUX, "PATH"}, // {O_LARGEFILE_LINUX, "LARGEFILE"}, // {O_SYNC_LINUX, "SYNC"}, // comes before O_DSYNC {O_DSYNC_LINUX, "DSYNC"}, // }; static const struct DescribeFlagz kProtFlags[] = { {PROT_READ_LINUX, "READ"}, // {PROT_WRITE_LINUX, "WRITE"}, // {PROT_EXEC_LINUX, "EXEC"}, // {PROT_SEM_LINUX, "SEM"}, // {PROT_GROWSDOWN_LINUX, "GROWSDOWN"}, // {PROT_GROWSUP_LINUX, "GROWSUP"}, // }; static const struct DescribeFlagz kMapFlags[] = { {MAP_SHARED_LINUX, "SHARED"}, // {MAP_PRIVATE_LINUX, "PRIVATE"}, // {MAP_FIXED_LINUX, "FIXED"}, // {MAP_FIXED_NOREPLACE_LINUX, "FIXED_NOREPLACE"}, // {MAP_NONBLOCK_LINUX, "NONBLOCK"}, // {MAP_ANONYMOUS_LINUX, "ANONYMOUS"}, // {MAP_GROWSDOWN_LINUX, "GROWSDOWN"}, // {MAP_STACK_LINUX, "STACK"}, // {MAP_NORESERVE_LINUX, "NORESERVE"}, // {MAP_POPULATE_LINUX, "POPULATE"}, // {MAP_HUGETLB_LINUX, "HUGETLB"}, // {MAP_SYNC_LINUX, "SYNC"}, // {MAP_UNINITIALIZED_LINUX, "UNINITIALIZED"}, // }; static const struct DescribeFlagz kSaFlags[] = { {SA_NOCLDSTOP_LINUX, "NOCLDSTOP"}, // {SA_NOCLDWAIT_LINUX, "NOCLDWAIT"}, // {SA_SIGINFO_LINUX, "SIGINFO"}, // {SA_UNSUPPORTED_LINUX, "UNSUPPORTED"}, // {SA_EXPOSE_TAGBITS_LINUX, "EXPOSE_TAGBITS"}, // {SA_RESTORER_LINUX, "RESTORER"}, // {SA_ONSTACK_LINUX, "ONSTACK"}, // {SA_RESTART_LINUX, "RESTART"}, // {SA_NODEFER_LINUX, "NODEFER"}, // {SA_RESETHAND_LINUX, "RESETHAND"}, // }; static const struct DescribeFlagz kAtFlags[] = { {AT_SYMLINK_NOFOLLOW_LINUX, "SYMLINK_NOFOLLOW"}, // {AT_REMOVEDIR_LINUX, "REMOVEDIR"}, // {AT_EACCESS_LINUX, "EACCESS"}, // {AT_SYMLINK_FOLLOW_LINUX, "SYMLINK_FOLLOW"}, // {AT_EMPTY_PATH_LINUX, "EMPTY_PATH"}, // }; #ifndef DISABLE_THREADS static const struct DescribeFlagz kCloneFlags[] = { {CLONE_VM_LINUX, "VM"}, // {CLONE_THREAD_LINUX, "THREAD"}, // {CLONE_FS_LINUX, "FS"}, // {CLONE_FILES_LINUX, "FILES"}, // {CLONE_SIGHAND_LINUX, "SIGHAND"}, // {CLONE_VFORK_LINUX, "VFORK"}, // {CLONE_SYSVSEM_LINUX, "SYSVSEM"}, // {CLONE_SETTLS_LINUX, "SETTLS"}, // {CLONE_PARENT_SETTID_LINUX, "PARENT_SETTID"}, // {CLONE_CHILD_CLEARTID_LINUX, "CHILD_CLEARTID"}, // {CLONE_DETACHED_LINUX, "DETACHED"}, // {CLONE_CHILD_SETTID_LINUX, "CHILD_SETTID"}, // {CLONE_NEWCGROUP_LINUX, "NEWCGROUP"}, // {CLONE_NEWUTS_LINUX, "NEWUTS"}, // {CLONE_NEWIPC_LINUX, "NEWIPC"}, // {CLONE_NEWUSER_LINUX, "NEWUSER"}, // {CLONE_NEWPID_LINUX, "NEWPID"}, // {CLONE_NEWNET_LINUX, "NEWNET"}, // {CLONE_IO_LINUX, "IO"}, // }; #endif #ifndef DISABLE_NONPOSIX static const struct DescribeFlagz kRenameFlags[] = { {RENAME_NOREPLACE_LINUX, "NOREPLACE"}, // {RENAME_EXCHANGE_LINUX, "EXCHANGE"}, // {RENAME_WHITEOUT_LINUX, "WHITEOUT"}, // }; #endif #ifdef HAVE_FORK static const struct DescribeFlagz kWaitFlags[] = { {WNOHANG_LINUX, "WNOHANG"}, // {WUNTRACED_LINUX, "WUNTRACED"}, // {WEXITED_LINUX, "WEXITED"}, // {WCONTINUED_LINUX, "WCONTINUED"}, // {WNOWAIT_LINUX, "WNOWAIT"}, // {__WNOTHREAD_LINUX, "__WNOTHREAD"}, // {__WALL_LINUX, "__WALL"}, // {__WCLONE_LINUX, "__WCLONE"}, // }; #endif #ifndef DISABLE_SOCKETS static const struct DescribeFlagz kSockFlags[] = { {SOCK_CLOEXEC_LINUX, "CLOEXEC"}, // {SOCK_NONBLOCK_LINUX, "NONBLOCK"}, // }; #endif const struct MagicNumber kWhence[] = { {SEEK_SET_LINUX, "SEEK_SET"}, // {SEEK_CUR_LINUX, "SEEK_CUR"}, // {SEEK_END_LINUX, "SEEK_END"}, // }; const struct MagicNumber kSigHow[] = { {SIG_BLOCK_LINUX, "SIG_BLOCK"}, // {SIG_UNBLOCK_LINUX, "SIG_UNBLOCK"}, // {SIG_SETMASK_LINUX, "SIG_SETMASK"}, // }; const struct MagicNumber kSocketFamily[] = { {AF_UNSPEC_LINUX, "AF_UNSPEC"}, // {AF_UNIX_LINUX, "AF_UNIX"}, // {AF_INET_LINUX, "AF_INET"}, // {AF_INET6_LINUX, "AF_INET6"}, // {AF_NETLINK_LINUX, "AF_NETLINK"}, // {AF_PACKET_LINUX, "AF_PACKET"}, // {AF_VSOCK_LINUX, "AF_VSOCK"}, // }; const struct MagicNumber kSocketType[] = { {SOCK_STREAM_LINUX, "SOCK_STREAM"}, // {SOCK_DGRAM_LINUX, "SOCK_DGRAM"}, // {SOCK_RAW_LINUX, "SOCK_RAW"}, // }; const struct MagicNumber kClock[] = { {CLOCK_REALTIME_LINUX, "CLOCK_REALTIME"}, // {CLOCK_MONOTONIC_LINUX, "CLOCK_MONOTONIC"}, // {CLOCK_PROCESS_CPUTIME_ID_LINUX, "CLOCK_PROCESS_CPUTIME_ID"}, // {CLOCK_THREAD_CPUTIME_ID_LINUX, "CLOCK_THREAD_CPUTIME_ID"}, // {CLOCK_MONOTONIC_RAW_LINUX, "CLOCK_MONOTONIC_RAW"}, // {CLOCK_REALTIME_COARSE_LINUX, "CLOCK_REALTIME_COARSE"}, // {CLOCK_MONOTONIC_COARSE_LINUX, "CLOCK_MONOTONIC_COARSE"}, // {CLOCK_BOOTTIME_LINUX, "CLOCK_BOOTTIME"}, // {CLOCK_REALTIME_ALARM_LINUX, "CLOCK_REALTIME_ALARM"}, // {CLOCK_BOOTTIME_ALARM_LINUX, "CLOCK_BOOTTIME_ALARM"}, // {CLOCK_TAI_LINUX, "CLOCK_TAI"}, // }; const struct MagicNumber kResource[] = { {RLIMIT_CPU_LINUX, "RLIMIT_CPU"}, // {RLIMIT_FSIZE_LINUX, "RLIMIT_FSIZE"}, // {RLIMIT_DATA_LINUX, "RLIMIT_DATA"}, // {RLIMIT_STACK_LINUX, "RLIMIT_STACK"}, // {RLIMIT_CORE_LINUX, "RLIMIT_CORE"}, // {RLIMIT_RSS_LINUX, "RLIMIT_RSS"}, // {RLIMIT_NPROC_LINUX, "RLIMIT_NPROC"}, // {RLIMIT_NOFILE_LINUX, "RLIMIT_NOFILE"}, // {RLIMIT_MEMLOCK_LINUX, "RLIMIT_MEMLOCK"}, // {RLIMIT_AS_LINUX, "RLIMIT_AS"}, // {RLIMIT_LOCKS_LINUX, "RLIMIT_LOCKS"}, // {RLIMIT_SIGPENDING_LINUX, "RLIMIT_SIGPENDING"}, // {RLIMIT_MSGQUEUE_LINUX, "RLIMIT_MSGQUEUE"}, // {RLIMIT_NICE_LINUX, "RLIMIT_NICE"}, // {RLIMIT_RTPRIO_LINUX, "RLIMIT_RTPRIO"}, // {RLIMIT_RTTIME_LINUX, "RLIMIT_RTTIME"}, // }; const struct MagicNumber kFcntl[] = { {F_DUPFD_LINUX, "F_DUPFD"}, // {F_DUPFD_CLOEXEC_LINUX, "F_DUPFD_CLOEXEC"}, // {F_GETFL_LINUX, "F_GETFL"}, // {F_SETFL_LINUX, "F_SETFL"}, // {F_GETLK_LINUX, "F_GETLK"}, // {F_SETLK_LINUX, "F_SETLK"}, // {F_SETLKW_LINUX, "F_SETLKW"}, // {F_SETOWN_LINUX, "F_SETOWN"}, // {F_GETOWN_LINUX, "F_GETOWN"}, // {F_SETSIG_LINUX, "F_SETSIG"}, // {F_GETSIG_LINUX, "F_GETSIG"}, // {F_SETOWN_EX_LINUX, "F_SETOWN_EX"}, // {F_GETOWN_EX_LINUX, "F_GETOWN_EX"}, // {F_GETOWNER_UIDS_LINUX, "F_GETOWNER_UIDS"}, // }; const struct MagicNumber kFlockType[] = { {F_RDLCK_LINUX, "F_RDLCK"}, // {F_WRLCK_LINUX, "F_WRLCK"}, // {F_UNLCK_LINUX, "F_UNLCK"}, // }; static const char *GetMagicNumber(const struct MagicNumber *p, int n, int x) { int i; _Thread_local static char ibuf[21]; for (i = 0; i < n; ++i) { if (p[i].x == x) { return p[i].s; } } FormatInt64(ibuf, x); return ibuf; } static const char *DescribeSockaddr(const struct sockaddr_storage_linux *ss) { _Thread_local static char abuf[64], sabuf[80]; switch (Read16(ss->family)) { case AF_UNIX_LINUX: return !ss->storage[sizeof(struct sockaddr_un_linux)] ? ((const struct sockaddr_un_linux *)ss)->path : 0; case AF_INET_LINUX: snprintf(sabuf, sizeof(sabuf), "{\"%s\", %d}", inet_ntop(Read16(ss->family), &((const struct sockaddr_in_linux *)ss)->addr, abuf, sizeof(abuf)), htons(((const struct sockaddr_in6_linux *)ss)->port)); return sabuf; case AF_INET6_LINUX: snprintf(sabuf, sizeof(sabuf), "{\"%s\", %d}", inet_ntop(Read16(ss->family), &((const struct sockaddr_in6_linux *)ss)->addr, abuf, sizeof(abuf)), htons(((const struct sockaddr_in6_linux *)ss)->port)); return sabuf; default: snprintf(abuf, sizeof(abuf), "{%s}", GetMagicNumber(kSocketFamily, ARRAYLEN(kSocketFamily), Read16(ss->family))); return abuf; } } static const char *DescribeBuf(struct Machine *m, i64 arg, u64 len, u64 ax, bool isentry, bool isout) { _Thread_local static char bp[1 + kStraceBufMax * 3 + 1 + 3 + 2 + 21 + 1]; u64 have; const u8 *data; int j, bi, bn, preview; bi = 0; have = len; bn = sizeof(bp); preview = MIN(len, kStraceBufMax); if (isout) { if (!isentry) { have = MIN(len, ax); preview = MIN(preview, ax); } else { preview = -1; } } if (preview > 0 && (data = (const u8 *)SchlepR(m, arg, preview))) { APPEND("\""); for (j = 0; j < preview; ++j) { APPEND("%lc", (wint_t)kCp437[data[j]]); } APPEND("\""); if (j < have) { APPEND("..."); } } else if (!preview) { APPEND("\"\""); } else { APPEND("%#" PRIx64, arg); } APPEND(", %" PRId64, len); return bp; } static void DescribeSigset(char *bp, int bn, u64 ss) { int sig, got = 0, bi = 0; if (popcount(ss) > 32) { APPEND("~"); ss = ~ss; } APPEND("{"); for (sig = 1; sig <= 64; ++sig) { if (ss & ((u64)1 << (sig - 1))) { if (got) { APPEND(", "); } else { got = true; } APPEND("%s", DescribeSignal(sig)); } } APPEND("}"); } void Strace(struct Machine *m, const char *func, bool isentry, const char *fmt, ...) { char *bp; va_list va; i64 ax, arg; bool isoutmem; int c, i, bi, bn; char tmp[kStraceArgMax]; char buf[7][kStraceArgMax]; va_start(va, fmt); for (i = 0; i < 7; ++i) { buf[i][0] = 0; } i = 0; if (isentry) { strcpy(buf[0], "..."); ++i; } for (ax = 0; (c = fmt[i]); ++i) { bi = 0; bp = buf[i]; bn = sizeof(buf[i]); if (i >= 2) APPEND(", "); arg = va_arg(va, i64); if (IS_I32(c)) arg = (i32)arg; if (i == 0) ax = arg; if (i == 0 && arg == -1) { APPEND("-%s", DescribeHostErrno(errno)); continue; } if ((isoutmem = arg && !isentry && // (IS_MEM_O(c) || IS_MEM_IO(c)) && // !IS_ADDR(c))) { APPEND("["); } if (arg == -1) { APPEND("-1"); } else if (IS_MEM(c) && !arg) { APPEND("NULL"); } else if (c == I64_HEX[0] || (ax == -1 && (IS_MEM_O(c) || IS_MEM_IO(c)))) { JustPrintHex: APPEND("%#" PRIx64, arg); } else if (c == I64[0]) { APPEND("%" PRId64, arg); } else if (c == I32[0]) { APPEND("%" PRId32, (i32)arg); } else if (c == I32_OCTAL[0]) { APPEND("%#" PRIo32, (i32)arg); } else if (c == I32_FD[0] || c == I32_DIRFD[0]) { struct Fd *fd; if (c == I32_DIRFD[0] && arg == AT_FDCWD_LINUX) { APPEND("AT_FDCWD"); } else { APPEND("%d", (int)arg); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, arg))) { if (fd->path) { APPEND(" \"%s\"", fd->path); } } UNLOCK(&m->system->fds.lock); } } else if (IS_BUF(c)) { u64 len = va_arg(va, i64); APPEND("%s", DescribeBuf(m, arg, len, ax, isentry, c == O_BUF[0])); ++i; } else if (IS_IOVEC(c)) { u64 rem; const struct iovec_linux *iov; int j, iovlen = va_arg(va, i64); if ((iov = (const struct iovec_linux *)SchlepR( m, arg, iovlen * sizeof(struct iovec_linux)))) { rem = ax; APPEND("{"); for (j = 0; j < iovlen; ++j) { if (j) APPEND(", "); APPEND("{%s}", DescribeBuf(m, Read64(iov[j].base), Read64(iov[j].len), rem, isentry, c == O_IOVEC[0])); rem -= MIN(rem, Read64(iov[j].len)); } APPEND("}"); } else { APPEND("%#" PRIx64, arg); } ++i; snprintf(buf[i], sizeof(buf[i]), ", %d", iovlen); } else if (c == I_STR[0]) { const char *str; if ((str = LoadStr(m, arg))) { APPEND("\"%s\"", str); } else { goto JustPrintHex; } } else if (c == I32_SIG[0]) { APPEND("%s", DescribeSignal(arg)); } else if (c == I32_ACCMODE[0]) { if (!arg) { APPEND("F_OK"); } else { DescribeFlagz(tmp, sizeof(tmp), kAccessModes, ARRAYLEN(kAccessModes), "", arg); APPEND("%s", tmp); } #ifdef HAVE_FORK } else if (c == I32_WAITFLAGS[0]) { DescribeFlagz(tmp, sizeof(tmp), kWaitFlags, ARRAYLEN(kWaitFlags), "", arg); APPEND("%s", tmp); } else if (c == O_WSTATUS[0]) { const u8 *p; if ((p = (const u8 *)SchlepR(m, arg, 4))) { i32 s = Read32(p); if (WIFEXITED(s)) { APPEND("{WIFEXITED(s) && WEXITSTATUS(s) == %d}", WEXITSTATUS(s)); } else if (WIFSTOPPED(s)) { APPEND("{WIFSTOPPED(s) && WSTOPSIG(s) == %s}", DescribeSignal(WSTOPSIG(s))); } else if (WIFSIGNALED(s)) { APPEND("{WIFSIGNALED(s) && WTERMSIG(s) == %s}", DescribeSignal(WTERMSIG(s))); } else { APPEND("{%#" PRIx32 "}", s); } } #endif } else if (c == I32_PROT[0]) { if (arg) { DescribeFlagz(tmp, sizeof(tmp), kProtFlags, ARRAYLEN(kProtFlags), "PROT_", arg); APPEND("%s", tmp); } else { APPEND("PROT_NONE"); } } else if (c == I32_MAPFLAGS[0]) { DescribeFlagz(tmp, sizeof(tmp), kMapFlags, ARRAYLEN(kMapFlags), "MAP_", arg); APPEND("%s", tmp); } else if (c == I32_OFLAGS[0]) { i32 arg2 = arg; if ((arg2 & O_ACCMODE_LINUX) < ARRAYLEN(kOpenAccmode)) { APPEND("%s", kOpenAccmode[arg2 & O_ACCMODE_LINUX]); arg2 &= ~O_ACCMODE_LINUX; } if (arg2) { DescribeFlagz(tmp, sizeof(tmp), kOpenFlags, ARRAYLEN(kOpenFlags), "O_", arg2); APPEND("|%s", tmp); } if (!(arg & O_CREAT_LINUX) && !(arg & __O_TMPFILE_LINUX)) { ++i; // ignore mode } } else if (c == I32_ATFLAGS[0]) { DescribeFlagz(tmp, sizeof(tmp), kAtFlags, ARRAYLEN(kAtFlags), "AT_", arg); APPEND("%s", tmp); #ifndef DISABLE_THREADS } else if (c == I32_CLONEFLAGS[0]) { DescribeFlagz(tmp, sizeof(tmp), kCloneFlags, ARRAYLEN(kCloneFlags), "CLONE_", arg); APPEND("%s", tmp); #endif } else if (IS_SIGSET(c)) { const struct sigset_linux *ss; if ((ss = (const struct sigset_linux *)SchlepR( m, arg, sizeof(struct sigset_linux)))) { DescribeSigset(tmp, sizeof(tmp), Read64(ss->sigmask)); APPEND("%s", tmp); } else { goto JustPrintHex; } #if defined(HAVE_FORK) || defined(HAVE_THREADS) } else if (c == O_PFDS[0]) { const u8 *pfds; if ((pfds = (const u8 *)SchlepR(m, arg, 8))) { APPEND("{%" PRId32 ", %" PRId32 "}", Read32(pfds), Read32(pfds + 4)); } else { goto JustPrintHex; } #endif } else if (c == IO_FDSET[0]) { const u8 *fdset; if ((fdset = (const u8 *)SchlepR(m, arg, FD_SETSIZE_LINUX / 8))) { int fd; bool gotsome = false; APPEND("{"); for (fd = 0; fd < FD_SETSIZE_LINUX; ++fd) { if (fdset[fd >> 3] & (1 << (fd & 7))) { if (!gotsome) { gotsome = true; } else { APPEND(","); } APPEND("%d", fd); } } APPEND("}"); } else { goto JustPrintHex; } } else if (IS_TIME(c) || c == IO_TIMEV[0]) { const struct timespec_linux *ts; if ((ts = (const struct timespec_linux *)SchlepR( m, arg, sizeof(struct timespec_linux)))) { APPEND("{%" PRId64 ", %" PRId64 "}", Read64(ts->sec), Read64(ts->nsec)); } else { goto JustPrintHex; } } else if (c == O_TIME2[0]) { const struct timespec_linux *ts; if ((ts = (const struct timespec_linux *)SchlepR( m, arg, sizeof(struct timespec_linux) * 2))) { APPEND("{.atim = {%" PRId64 ", %" PRId64 "}," " .mtim = {%" PRId64 ", %" PRId64 "}}", Read64(ts[0].sec), Read64(ts[0].nsec), Read64(ts[1].sec), Read64(ts[1].nsec)); } else { goto JustPrintHex; } } else if (c == O_STAT[0]) { const struct stat_linux *st; if ((st = (const struct stat_linux *)SchlepR( m, arg, sizeof(struct stat_linux)))) { APPEND("{.st_%s=%" PRId64, "size", Read64(st->size)); if (Read64(st->blocks)) { APPEND(", .st_blocks=%" PRIu64 "/512", Read64(st->blocks) * 512); } if (Read32(st->mode)) { APPEND(", .st_mode=%#" PRIo32, Read32(st->mode)); } if (Read64(st->nlink) != 1) { APPEND(", .st_nlink=%" PRIu64, Read64(st->nlink)); } if (Read32(st->uid)) { APPEND(", .st_uid=%" PRIu32, Read32(st->uid)); } if (Read32(st->gid)) { APPEND(", .st_gid=%" PRIu32, Read32(st->gid)); } if (Read64(st->dev)) { APPEND(", .st_dev=%" PRIu64, Read64(st->dev)); } if (Read64(st->ino)) { APPEND(", .st_ino=%" PRIu64, Read64(st->ino)); } if (Read64(st->rdev)) { APPEND(", .st_rdev=%" PRIu64, Read64(st->rdev)); } if (Read64(st->blksize) != 4096) { APPEND(", .st_blksize=%" PRIu64, Read64(st->blksize)); } APPEND("}"); } else { goto JustPrintHex; } } else if (IS_HAND(c)) { const struct sigaction_linux *sa; if ((sa = (const struct sigaction_linux *)SchlepR( m, arg, sizeof(struct sigaction_linux)))) { APPEND("{.sa_handler="); switch (Read64(sa->handler)) { case SIG_DFL_LINUX: APPEND("SIG_DFL"); break; case SIG_IGN_LINUX: APPEND("SIG_DFL"); break; default: APPEND("%#" PRIx64, Read64(sa->handler)); break; } if (Read64(sa->flags)) { DescribeFlagz(tmp, sizeof(tmp), kSaFlags, ARRAYLEN(kSaFlags), "SA_", Read64(sa->flags)); APPEND(", .sa_flags=%s", tmp); } if (Read64(sa->mask)) { DescribeSigset(tmp, sizeof(tmp), Read64(sa->mask)); APPEND(", .sa_mask=%s", tmp); } if (Read64(sa->restorer)) { APPEND(", .sa_restorer=%#" PRIx64, Read64(sa->restorer)); } APPEND("}"); } else { goto JustPrintHex; } } else if (c == I32_SIGHOW[0]) { APPEND("%s", GetMagicNumber(kSigHow, ARRAYLEN(kSigHow), arg)); } else if (c == I32_FAMILY[0]) { APPEND("%s", GetMagicNumber(kSocketFamily, ARRAYLEN(kSocketFamily), arg)); } else if (c == I32_SOCKTYPE[0]) { if (arg & SOCK_NONBLOCK_LINUX) { APPEND("SOCK_NONBLOCK|"); arg &= ~SOCK_NONBLOCK_LINUX; } if (arg & SOCK_CLOEXEC_LINUX) { APPEND("SOCK_CLOEXEC|"); arg &= ~SOCK_CLOEXEC_LINUX; } APPEND("%s", GetMagicNumber(kSocketType, ARRAYLEN(kSocketType), arg)); } else if (c == I32_RESOURCE[0]) { APPEND("%s", GetMagicNumber(kResource, ARRAYLEN(kResource), arg)); } else if (c == I_RLIMIT[0] || c == O_RLIMIT[0]) { const struct rlimit_linux *ts; if ((ts = (const struct rlimit_linux *)SchlepR( m, arg, sizeof(struct rlimit_linux)))) { APPEND("{%" PRId64 ", %" PRId64 "}", Read64(ts->cur), Read64(ts->max)); } else { goto JustPrintHex; } } else if (c == I32_CLOCK[0]) { APPEND("%s", GetMagicNumber(kClock, ARRAYLEN(kClock), arg)); #ifndef DISABLE_SOCKETS } else if (c == I32_SOCKFLAGS[0]) { DescribeFlagz(tmp, sizeof(tmp), kSockFlags, ARRAYLEN(kSockFlags), "SOCK_", arg); APPEND("%s", tmp); } else if (IS_ADDR(c)) { const u8 *p = 0; i64 len = va_arg(va, i64); struct sockaddr_storage_linux ss; memset(&ss, 0, sizeof(ss)); if (c == I_ADDR[0]) len = (u32)len; if (c != I_ADDR[0] && !(p = (const u8 *)SchlepR(m, len, 4))) { APPEND("%#" PRIx64 ", %" PRIx64, arg, len); } else { if (c == I_ADDR[0]) { len = (u32)len; } else { len = Read32(p); } if (c != I_ADDR[0]) APPEND("["); if (arg && CopyFromUserRead(m, &ss, arg, MIN(len, sizeof(ss))) != -1) { APPEND("%s", DescribeSockaddr(&ss)); } else { APPEND("%#" PRIx64, arg); } if (c != I_ADDR[0]) APPEND("]"); if (c == I_ADDR[0]) { APPEND(", %" PRId64, len); } else { APPEND(", [%" PRId64 "]", len); } } ++i; #endif #ifndef DISABLE_NONPOSIX } else if (c == I32_RENFLAGS[0]) { DescribeFlagz(tmp, sizeof(tmp), kRenameFlags, ARRAYLEN(kRenameFlags), "RENAME_", arg); APPEND("%s", tmp); #endif } else if (c == WAT_FCNTL[0]) { APPEND("%s", GetMagicNumber(kFcntl, ARRAYLEN(kFcntl), arg)); if (arg == F_SETLK_LINUX || // arg == F_SETLKW_LINUX || // arg == F_GETLK_LINUX) { i64 addr = va_arg(va, i64); const struct flock_linux *l; if ((l = (const struct flock_linux *)SchlepR( m, addr, sizeof(struct flock_linux)))) { APPEND(", "); if (arg == F_GETLK_LINUX) { APPEND("["); } APPEND("{%s", GetMagicNumber(kFlockType, ARRAYLEN(kFlockType), Read16(l->type))); APPEND(", %s", GetMagicNumber(kWhence, ARRAYLEN(kWhence), Read16(l->whence))); if (Read64(l->start)) { APPEND(", .l_start=%#" PRIx64, Read64(l->start)); } if (Read64(l->len)) { APPEND(", .l_len=%" PRIu64, Read64(l->len)); } if (Read64(l->pid) && arg == F_GETLK_LINUX) { APPEND(", .l_pid=%" PRIu32, Read32(l->pid)); } APPEND("}"); if (arg == F_GETLK_LINUX) { APPEND("]"); } } else { APPEND(", %#" PRIx64, addr); } } else if (arg == F_SETFD_LINUX) { i32 flags = va_arg(va, i64); if (flags == FD_CLOEXEC_LINUX) { APPEND(", FD_CLOEXEC"); } else { APPEND(", %#" PRIx32, flags); } } else if (arg == F_SETFL_LINUX) { i32 flags = va_arg(va, i64); DescribeFlagz(tmp, sizeof(tmp), kOpenFlags, ARRAYLEN(kOpenFlags), "O_", flags); APPEND("%s", tmp); } else if (arg == F_SETOWN_LINUX) { i32 fd = va_arg(va, i64); APPEND(", %#" PRIx32, fd); } } else { LOGF("missing strace signature specifier %#o", c); goto JustPrintHex; } if (bi + 2 > bn) { bi = bn - 5; bp[bi++] = '.'; bp[bi++] = '.'; bp[bi++] = '.'; bp[bi] = 0; } if (isoutmem) { bp[bi++] = ']'; bp[bi] = 0; } } va_end(va); SYS_LOGF("%s(%s%s%s%s%s%s) -> %s", func, buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[0]); } ================================================ FILE: blink/strace.h ================================================ #ifndef BLINK_STRACE_H_ #define BLINK_STRACE_H_ #include "blink/machine.h" #if !defined(DISABLE_STRACE) && !defined(TINY) #define STRACE 1 #else #define STRACE 0 #endif #define IS_INT(c) (0000 == (0200 & (c))) #define IS_I32(c) (0000 == (0300 & (c))) #define IS_I64(c) (0100 == (0300 & (c))) #define IS_MEM(c) (0200 == (0200 & (c))) #define IS_MEM_I(c) (0200 == (0340 & (c))) #define IS_MEM_O(c) (0300 == (0340 & (c))) #define IS_MEM_IO(c) (0360 == (0340 & (c))) #define IS_BUF(c) (0200 == (0277 & (c))) #define IS_TIME(c) (0202 == (0237 & (c))) #define IS_HAND(c) (0203 == (0277 & (c))) #define IS_ADDR(c) (0210 == (0277 & (c))) #define IS_IOVEC(c) (0212 == (0277 & (c))) #define IS_SIGSET(c) (0204 == (0277 & (c))) #define ST_HAS(s, f) \ (f(s[1]) || f(s[2]) || f(s[3]) || f(s[4]) || f(s[5]) || f(s[6])) // system call classification, numbered by minimum number of `-s` flags // that need to be supplied on the command line to log a syscall entry. #define TWOWAY "\001" // has read+write parameter #define BLOCKY "\002" // cancellation points likely to block #define CANCPT "\003" // cancellation points unlikely to block #define NORMAL "\004" // everything else #define UN #define PAD "\000" #define I32 "\001" #define I32_FD "\002" #define I32_DIRFD "\003" #define I32_OCTAL "\004" #define I32_OFLAGS "\005" #define I32_WHENCE "\006" #define I32_ATFLAGS "\007" #define I32_PROT "\010" #define I32_MAPFLAGS "\011" #define I32_MSFLAGS "\012" #define I32_SIG "\013" #define I32_RENFLAGS "\014" #define I32_CLONEFLAGS "\015" #define I32_CLOCK "\016" #define I32_WAITFLAGS "\017" #define I32_FAMILY "\020" #define I32_SOCKTYPE "\021" #define I32_SOCKFLAGS "\022" #define I32_SIGHOW "\023" #define I32_ACCMODE "\024" #define I32_RESOURCE "\025" #define I64 "\100" #define I64_HEX "\101" #define I_BUF "\200" #define I_STR "\201" #define I_TIME "\202" #define I_HAND "\203" #define I_SIGSET "\204" #define I_ADDR "\210" #define I_IOVEC "\212" #define I_RLIMIT "\213" #define O_BUF "\300" #define O_STAT "\301" #define O_TIME "\302" #define O_HAND "\303" #define O_SIGSET "\304" #define O_PFDS "\306" #define O_WSTATUS "\307" #define O_ADDR "\310" #define O_TIME2 "\311" #define O_IOVEC "\312" #define O_RLIMIT "\313" #define IO_POLL "\340" #define IO_TIME "\342" #define IO_TIMEV "\343" #define IO_FDSET "\344" #define WAT_IOCTL "\375" #define WAT_FCNTL "\376" #define WAT_PSELECT "\377" #define RC0 I32 #define PID I32 #define UID I32 #define GID I32 #define ADDRLEN I32 #define FD I32_FD #define DIRFD I32_DIRFD #define SIG I32_SIG #define MODE I32_OCTAL #define PROT I32_PROT #define CLOCK I32_CLOCK #define WHENCE I32_WHENCE #define OFLAGS I32_OFLAGS #define FAMILY I32_FAMILY #define MSFLAGS I32_MSFLAGS #define ATFLAGS I32_ATFLAGS #define SOCKTYPE I32_SOCKTYPE #define MAPFLAGS I32_MAPFLAGS #define RENFLAGS I32_RENFLAGS #define WAITFLAGS I32_WAITFLAGS #define SOCKFLAGS I32_SOCKFLAGS #define CLONEFLAGS I32_CLONEFLAGS #define RESOURCE I32_RESOURCE #define ACCMODE I32_ACCMODE #define SIGHOW I32_SIGHOW #define SIZE I64_HEX #define SSIZE_ I64 #define OFF I64_HEX #define HEX I64_HEX #define PTR I64_HEX #define STR I_STR #define PATH I_STR #define BUFSZ I64 #define O_RUSAGE I64_HEX // clang-format off // SYSCALL KIND RET ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 #define STRACE_0 NORMAL HEX UN UN UN UN UN UN #define STRACE_1 NORMAL HEX HEX UN UN UN UN UN #define STRACE_2 NORMAL HEX HEX HEX UN UN UN UN #define STRACE_3 NORMAL HEX HEX HEX HEX UN UN UN #define STRACE_4 NORMAL HEX HEX HEX HEX HEX UN UN #define STRACE_5 NORMAL HEX HEX HEX HEX HEX HEX UN #define STRACE_6 NORMAL HEX HEX HEX HEX HEX HEX HEX #define STRACE_READ BLOCKY SSIZE_ FD O_BUF BUFSZ UN UN UN #define STRACE_READV BLOCKY SSIZE_ FD O_IOVEC BUFSZ UN UN UN #define STRACE_PREAD BLOCKY SSIZE_ FD O_BUF BUFSZ OFF UN UN #define STRACE_PREADV BLOCKY SSIZE_ FD O_IOVEC BUFSZ OFF UN UN #define STRACE_PREADV2 BLOCKY SSIZE_ FD O_IOVEC BUFSZ OFF I32 UN #define STRACE_WRITE CANCPT SSIZE_ FD I_BUF BUFSZ UN UN UN #define STRACE_WRITEV CANCPT SSIZE_ FD I_IOVEC BUFSZ UN UN UN #define STRACE_PWRITE CANCPT SSIZE_ FD I_BUF BUFSZ OFF UN UN #define STRACE_PWRITEV CANCPT SSIZE_ FD I_IOVEC BUFSZ OFF UN UN #define STRACE_PWRITEV2 CANCPT SSIZE_ FD I_IOVEC BUFSZ OFF I32 UN #define STRACE_OPEN CANCPT I32 PATH OFLAGS MODE UN UN UN #define STRACE_OPENAT CANCPT I32 DIRFD STR OFLAGS MODE UN UN #define STRACE_CREAT CANCPT I32 PATH MODE UN UN UN UN #define STRACE_CLOSE CANCPT RC0 FD UN UN UN UN UN #define STRACE_STAT NORMAL RC0 PATH O_STAT UN UN UN UN #define STRACE_FSTAT NORMAL RC0 FD O_STAT UN UN UN UN #define STRACE_LSTAT NORMAL RC0 PATH O_STAT UN UN UN UN #define STRACE_FSTATAT NORMAL RC0 DIRFD PATH O_STAT ATFLAGS UN UN #define STRACE_UTIMENSAT NORMAL RC0 DIRFD PATH O_TIME2 ATFLAGS UN UN #define STRACE_POLL TWOWAY I32 IO_POLL I32 UN UN UN UN #define STRACE_PPOLL TWOWAY RC0 IO_POLL IO_TIME I_SIGSET SSIZE_ UN UN #define STRACE_LSEEK NORMAL OFF FD OFF WHENCE UN UN UN #define STRACE_MMAP NORMAL PTR PTR SIZE PROT MAPFLAGS FD OFF #define STRACE_PAUSE BLOCKY RC0 UN UN UN UN UN UN #define STRACE_SYNC BLOCKY RC0 UN UN UN UN UN UN #define STRACE_FSYNC BLOCKY RC0 FD UN UN UN UN UN #define STRACE_FDATASYNC BLOCKY RC0 FD UN UN UN UN UN #define STRACE_DUP NORMAL I32 FD UN UN UN UN UN #define STRACE_DUP2 NORMAL I32 FD I32 UN UN UN UN #define STRACE_DUP3 NORMAL I32 FD I32 OFLAGS PAD UN UN #define STRACE_MSYNC NORMAL RC0 PTR SIZE MSFLAGS UN UN UN #define STRACE_ALARM NORMAL I32 I32 UN UN UN UN UN #define STRACE_GETCWD NORMAL SSIZE_ O_BUF BUFSZ UN UN UN UN #define STRACE_TRUNCATE CANCPT RC0 STR OFF UN UN UN UN #define STRACE_FTRUNCATE CANCPT RC0 FD OFF UN UN UN UN #define STRACE_GETRANDOM CANCPT SSIZE_ O_BUF BUFSZ I32 UN UN UN #define STRACE_MPROTECT NORMAL RC0 PTR SIZE PROT UN UN UN #define STRACE_MUNMAP NORMAL RC0 PTR SIZE UN UN UN UN #define STRACE_SIGACTION NORMAL RC0 SIG I_HAND O_HAND SSIZE_ UN UN #define STRACE_SIGPROCMASK NORMAL RC0 SIGHOW I_SIGSET O_SIGSET SSIZE_ UN UN #define STRACE_CLOCK_SLEEP BLOCKY RC0 CLOCK I32 I_TIME O_TIME UN UN #define STRACE_SIGSUSPEND BLOCKY RC0 I_SIGSET SSIZE_ UN UN UN UN #define STRACE_NANOSLEEP BLOCKY RC0 I_TIME O_TIME UN UN UN UN #define STRACE_IOCTL CANCPT I32 FD WAT_IOCTL UN UN UN UN #define STRACE_PIPE NORMAL SSIZE_ O_PFDS UN UN UN UN UN #define STRACE_PIPE2 NORMAL SSIZE_ O_PFDS OFLAGS PAD UN UN UN #define STRACE_SOCKETPAIR NORMAL RC0 FAMILY SOCKTYPE I32 O_PFDS UN UN #define STRACE_SELECT TWOWAY SSIZE_ I32 IO_FDSET IO_FDSET IO_FDSET IO_TIMEV UN #define STRACE_PSELECT TWOWAY SSIZE_ I32 IO_FDSET IO_FDSET IO_FDSET IO_TIME WAT_PSELECT #define STRACE_SCHED_YIELD NORMAL RC0 UN UN UN UN UN UN #define STRACE_FCNTL CANCPT I64 FD WAT_FCNTL UN UN UN UN #define STRACE_FORK NORMAL PID UN UN UN UN UN UN #define STRACE_VFORK NORMAL PID UN UN UN UN UN UN #define STRACE_WAIT4 BLOCKY PID PID O_WSTATUS WAITFLAGS O_RUSAGE UN UN #define STRACE_KILL NORMAL RC0 PID SIG UN UN UN UN #define STRACE_TKILL NORMAL RC0 PID SIG UN UN UN UN #define STRACE_ACCESS NORMAL RC0 PATH ACCMODE UN UN UN UN #define STRACE_FACCESSAT NORMAL RC0 DIRFD PATH ACCMODE UN UN UN #define STRACE_FACCESSAT2 NORMAL RC0 DIRFD PATH ACCMODE ATFLAGS UN UN #define STRACE_READLINK NORMAL SSIZE_ PATH O_BUF BUFSZ UN UN UN #define STRACE_READLINKAT NORMAL SSIZE_ DIRFD STR O_BUF BUFSZ UN UN #define STRACE_SYMLINK NORMAL RC0 PATH PATH UN UN UN UN #define STRACE_SYMLINKAT NORMAL RC0 PATH DIRFD PATH UN UN UN #define STRACE_UNLINK NORMAL RC0 PATH UN UN UN UN UN #define STRACE_UNLINKAT NORMAL RC0 DIRFD PATH ATFLAGS UN UN UN #define STRACE_LINK NORMAL RC0 PATH PATH UN UN UN UN #define STRACE_LINKAT NORMAL RC0 DIRFD PATH DIRFD PATH ATFLAGS UN #define STRACE_RENAME NORMAL RC0 PATH PATH UN UN UN UN #define STRACE_RENAMEAT NORMAL RC0 DIRFD PATH DIRFD PATH UN UN #define STRACE_RENAMEAT2 NORMAL RC0 DIRFD PATH DIRFD PATH ATFLAGS UN #define STRACE_MKDIR NORMAL RC0 PATH MODE UN UN RENFLAGS UN #define STRACE_MKDIRAT NORMAL RC0 DIRFD PATH MODE UN UN UN #define STRACE_RMDIR NORMAL RC0 PATH UN UN UN UN UN #define STRACE_CHMOD NORMAL RC0 PATH MODE UN UN UN UN #define STRACE_FCHMOD NORMAL RC0 FD MODE UN UN UN UN #define STRACE_FCHMODAT NORMAL RC0 DIRFD PATH MODE ATFLAGS UN UN #define STRACE_CHOWN NORMAL RC0 PATH UID GID UN UN UN #define STRACE_LCHOWN NORMAL RC0 PATH UID GID UN UN UN #define STRACE_FCHOWN NORMAL RC0 FD UID GID UN UN UN #define STRACE_CHOWNAT NORMAL RC0 DIRFD PATH UID GID ATFLAGS UN #define STRACE_GETTID NORMAL PID UN UN UN UN UN UN #define STRACE_GETPID NORMAL PID UN UN UN UN UN UN #define STRACE_GETPPID NORMAL PID UN UN UN UN UN UN #define STRACE_GETPGID NORMAL PID PID UN UN UN UN UN #define STRACE_GETUID NORMAL UID UN UN UN UN UN UN #define STRACE_GETGID NORMAL GID UN UN UN UN UN UN #define STRACE_GETEUID NORMAL UID UN UN UN UN UN UN #define STRACE_GETEGID NORMAL GID UN UN UN UN UN UN #define STRACE_SETSID NORMAL PID UN UN UN UN UN UN #define STRACE_GETPGRP NORMAL PID UN UN UN UN UN UN #define STRACE_SETUID NORMAL RC0 UID UN UN UN UN UN #define STRACE_SETGID NORMAL RC0 GID UN UN UN UN UN #define STRACE_SETREUID NORMAL RC0 UID UID UN UN UN UN #define STRACE_SETREGID NORMAL RC0 GID GID UN UN UN UN #define STRACE_SETRESUID NORMAL RC0 UID UID UID UN UN UN #define STRACE_SETRESGID NORMAL RC0 GID GID GID UN UN UN #define STRACE_UMASK NORMAL MODE MODE UN UN UN UN UN #define STRACE_CHDIR NORMAL RC0 PATH UN UN UN UN UN #define STRACE_CHROOT NORMAL RC0 PATH UN UN UN UN UN #define STRACE_FCHDIR NORMAL RC0 FD UN UN UN UN UN #define STRACE_CLONE NORMAL PID CLONEFLAGS PTR PTR PTR PTR PTR #define STRACE_FUTEX CANCPT HEX HEX HEX HEX HEX HEX HEX #define STRACE_SOCKET NORMAL I32 FAMILY SOCKTYPE I32 UN UN UN #define STRACE_CONNECT NORMAL I32 FD I_ADDR ADDRLEN UN UN UN #define STRACE_LISTEN NORMAL RC0 FD UN UN UN UN UN #define STRACE_ACCEPT BLOCKY FD FD O_ADDR I64 UN UN UN #define STRACE_ACCEPT4 BLOCKY FD FD O_ADDR I64 SOCKFLAGS UN UN #define STRACE_BIND NORMAL RC0 FD I_ADDR ADDRLEN UN UN UN #define STRACE_GETSOCKNAME NORMAL RC0 FD O_ADDR I64 UN UN UN #define STRACE_GETPEERNAME NORMAL RC0 FD O_ADDR I64 UN UN UN #define STRACE_SENDTO NORMAL SSIZE_ FD I_BUF SIZE I32 I_ADDR ADDRLEN #define STRACE_RECVFROM BLOCKY SSIZE_ FD O_BUF SIZE I32 O_ADDR I64 #define STRACE_GETRLIMIT NORMAL RC0 RESOURCE O_RLIMIT UN UN UN UN #define STRACE_SETRLIMIT NORMAL RC0 RESOURCE I_RLIMIT UN UN UN UN #define STRACE_PRLIMIT NORMAL RC0 PID RESOURCE I_RLIMIT O_RLIMIT UN UN #define STRACE_MOUNT NORMAL STR STR STR MSFLAGS PTR UN UN // clang-format on void EnterStrace(struct Machine *, const char *, const char *, ...); void LeaveStrace(struct Machine *, const char *, const char *, ...); #endif /* BLINK_STRACE_H_ */ ================================================ FILE: blink/strchrnul.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/util.h" char *strchrnul_(const char *s, int c) { for (;; ++s) { if ((*s & 255) == (c & 255)) return (char *)s; if (!*s) return (char *)s; } } ================================================ FILE: blink/string.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/string.h" #include #include #include "blink/alu.h" #include "blink/atomic.h" #include "blink/biosrom.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/tsan.h" #include "blink/util.h" #include "blink/x86.h" static u64 ReadInt(u8 p[8], unsigned long w) { switch (w) { case 0: return Read8(p); case 1: return Read16(p); case 2: return Read32(p); case 3: return Read64(p); default: __builtin_unreachable(); } } static void WriteInt(u8 p[8], u64 x, unsigned long w) { switch (w) { case 0: Write8(p, x); break; case 1: Write16(p, x); break; case 2: Write32(p, x); break; case 3: Write64(p, x); break; default: __builtin_unreachable(); } } static void AddDi(P, u64 x) { switch (Eamode(rde)) { case XED_MODE_LONG: Put64(m->di, Get64(m->di) + x); break; case XED_MODE_LEGACY: Put64(m->di, (Get32(m->di) + x) & 0xffffffff); break; case XED_MODE_REAL: Put16(m->di, Get16(m->di) + x); break; default: __builtin_unreachable(); } } static void AddSi(P, u64 x) { switch (Eamode(rde)) { case XED_MODE_LONG: Put64(m->si, Get64(m->si) + x); break; case XED_MODE_LEGACY: Put64(m->si, (Get32(m->si) + x) & 0xffffffff); break; case XED_MODE_REAL: Put16(m->si, Get16(m->si) + x); break; default: __builtin_unreachable(); } } static u64 ReadCx(P) { switch (Eamode(rde)) { case XED_MODE_LONG: return Get64(m->cx); case XED_MODE_LEGACY: return Get32(m->cx); case XED_MODE_REAL: return Get16(m->cx); default: __builtin_unreachable(); } } static u64 SubtractCx(P, u64 x) { u64 cx = Get64(m->cx) - x; if (Eamode(rde) != XED_MODE_REAL) { if (Eamode(rde) == XED_MODE_LEGACY) { cx &= 0xffffffff; } Put64(m->cx, cx); } else { cx &= 0xffff; Put16(m->cx, cx); } return cx; } static void StringOp(P, int op) { bool stop; unsigned n; i64 sgn, v; void *p[2]; u8 s[3][8]; stop = false; n = 1 << RegLog2(rde); sgn = GetFlag(m->flags, FLAGS_DF) ? -1 : 1; IGNORE_RACES_START(); atomic_thread_fence(memory_order_acquire); do { if (Rep(rde) && !ReadCx(A)) break; switch (op) { case STRING_CMPS: kAlu[ALU_SUB][RegLog2(rde)]( m, ReadInt(Load(m, AddressSi(A), n, s[2]), RegLog2(rde)), ReadInt(Load(m, AddressDi(A), n, s[1]), RegLog2(rde))); AddDi(A, sgn * n); AddSi(A, sgn * n); stop = (Rep(rde) == 2 && GetFlag(m->flags, FLAGS_ZF)) || (Rep(rde) == 3 && !GetFlag(m->flags, FLAGS_ZF)); break; case STRING_MOVS: memmove(BeginStore(m, (v = AddressDi(A)), n, p, s[0]), Load(m, AddressSi(A), n, s[1]), n); AddDi(A, sgn * n); AddSi(A, sgn * n); EndStore(m, v, n, p, s[0]); break; case STRING_STOS: memmove(BeginStore(m, (v = AddressDi(A)), n, p, s[0]), m->ax, n); AddDi(A, sgn * n); EndStore(m, v, n, p, s[0]); break; case STRING_LODS: memmove(m->ax, Load(m, AddressSi(A), n, s[1]), n); AddSi(A, sgn * n); break; case STRING_SCAS: kAlu[ALU_SUB][RegLog2(rde)]( m, ReadInt(Load(m, AddressDi(A), n, s[1]), RegLog2(rde)), ReadInt(m->ax, RegLog2(rde))); AddDi(A, sgn * n); stop = (Rep(rde) == 2 && GetFlag(m->flags, FLAGS_ZF)) || (Rep(rde) == 3 && !GetFlag(m->flags, FLAGS_ZF)); break; #ifndef DISABLE_METAL case STRING_OUTS: OpOut(m, Get16(m->dx), ReadInt(Load(m, AddressSi(A), n, s[1]), RegLog2(rde))); AddSi(A, sgn * n); break; case STRING_INS: WriteInt((u8 *)BeginStore(m, (v = AddressDi(A)), n, p, s[0]), OpIn(m, Get16(m->dx)), RegLog2(rde)); AddDi(A, sgn * n); EndStore(m, v, n, p, s[0]); break; #endif /* DISABLE_METAL */ default: Abort(); } if (Rep(rde)) { SubtractCx(A, 1); } else { break; } } while (!stop); atomic_thread_fence(memory_order_release); IGNORE_RACES_END(); } static void RepMovsbEnhanced(P) { u8 *direal, *sireal; u64 diactual, siactual, cx; u16 dilow, silow; long diremain, siremain, i, n; if ((cx = ReadCx(A))) { diactual = AddressDi(A); siactual = AddressSi(A); if (diactual != siactual) { if (!GetFlag(m->flags, FLAGS_DF)) { SetWriteAddr(m, diactual, cx); SetReadAddr(m, siactual, cx); } else { SetWriteAddr(m, diactual - cx + 1, cx); SetReadAddr(m, siactual - cx + 1, cx); } IGNORE_RACES_START(); atomic_thread_fence(memory_order_acquire); do { direal = ResolveAddress(m, diactual); sireal = ResolveAddress(m, siactual); dilow = Get16(m->di); silow = Get16(m->si); if (!GetFlag(m->flags, FLAGS_DF)) { diremain = 4096 - (diactual & 4095); diremain = MIN(diremain, 65536 - dilow); siremain = 4096 - (siactual & 4095); siremain = MIN(siremain, 65536 - silow); n = MIN(cx, MIN(diremain, siremain)); if (!IsRomAddress(m, direal)) { for (i = 0; i < n; ++i) { direal[i] = sireal[i]; } } AddDi(A, n); AddSi(A, n); } else { diremain = (diactual & 4095) + 1; diremain = MIN(diremain, (long)dilow + 1); siremain = (siactual & 4095) + 1; siremain = MIN(siremain, (long)silow + 1); n = MIN(cx, MIN(diremain, siremain)); if (!IsRomAddress(m, direal)) { for (i = 0; i < n; ++i) { direal[-i] = sireal[-i]; } } AddDi(A, -n); AddSi(A, -n); } cx = SubtractCx(A, n); if (cx) { diactual = AddressDi(A); siactual = AddressSi(A); } } while (cx); atomic_thread_fence(memory_order_release); IGNORE_RACES_END(); } } } static void RepStosbEnhanced(P) { u8 *direal; u64 diactual, cx; u16 dilow; unsigned diremain, n; if ((cx = ReadCx(A))) { diactual = AddressDi(A); SetWriteAddr(m, diactual, cx); IGNORE_RACES_START(); do { direal = ResolveAddress(m, diactual); dilow = Get16(m->di); diremain = 4096 - (diactual & 4095); diremain = MIN(diremain, 65536 - dilow); n = MIN(cx, diremain); if (!IsRomAddress(m, direal)) memset(direal, m->al, n); AddDi(A, n); cx = SubtractCx(A, n); if (cx) diactual = AddressDi(A); } while (cx); atomic_thread_fence(memory_order_release); IGNORE_RACES_END(); } } void OpMovs(P) { StringOp(A, STRING_MOVS); } void OpCmps(P) { StringOp(A, STRING_CMPS); } void OpStos(P) { StringOp(A, STRING_STOS); } void OpLods(P) { StringOp(A, STRING_LODS); } void OpScas(P) { StringOp(A, STRING_SCAS); } void OpIns(P) { StringOp(A, STRING_INS); } void OpOuts(P) { StringOp(A, STRING_OUTS); } void OpMovsb(P) { if (Rep(rde)) { RepMovsbEnhanced(A); } else { OpMovs(A); } } void OpStosb(P) { if (Rep(rde) && !GetFlag(m->flags, FLAGS_DF)) { RepStosbEnhanced(A); } else { OpStos(A); } } ================================================ FILE: blink/string.h ================================================ #ifndef BLINK_STRING_H_ #define BLINK_STRING_H_ #include "blink/machine.h" #define STRING_CMPS 0 #define STRING_MOVS 1 #define STRING_STOS 2 #define STRING_LODS 3 #define STRING_SCAS 4 #define STRING_OUTS 5 #define STRING_INS 6 void OpCmps(P); void OpIns(P); void OpLods(P); void OpMovs(P); void OpMovsb(P); void OpOuts(P); void OpScas(P); void OpStos(P); void OpStosb(P); #endif /* BLINK_STRING_H_ */ ================================================ FILE: blink/strwidth.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/strwidth.h" #include #include "blink/builtin.h" #include "blink/macros.h" #include "blink/thompike.h" #include "blink/util.h" /** * Returns monospace display width of UTF-8 string. * * - Control codes are discounted * - ANSI escape sequences are discounted * - East asian glyphs, emoji, etc. count as two * * @param s is NUL-terminated string * @param o is string offset for computing tab widths * @return monospace display width */ int strwidth(const char *s, size_t o) { return strnwidth(s, -1, 0); } /** * Returns monospace display width of UTF-8 string. * * - Control codes are discounted * - ANSI escape sequences are discounted * - East asian glyphs, emoji, etc. count as two * * @param s is NUL-terminated string * @param n is max bytes to consider * @param o is offset for doing tabs * @return monospace display width */ int strnwidth(const char *s, size_t n, size_t o) { size_t i; wint_t c, w; unsigned l, r, k; enum { kAscii, kUtf8, kEsc, kCsi } t; for (t = kAscii, w = r = l = i = 0; i < n;) { if ((c = s[i++] & 0xff)) { switch (t) { case kAscii: if (0x20 <= c && c <= 0x7E) { ++l; } else if (c == '\t') { if ((k = (o + i - 1) & 7)) { l += 8 - k; } else { l += 8; } } else if (c == 033) { t = kEsc; } else if (c >= 0300) { t = kUtf8; w = ThomPikeByte(c); r = ThomPikeLen(c) - 1; } break; case kUtf8: if (ThomPikeCont(c)) { w = ThomPikeMerge(w, c); if (--r) break; } k = wcwidth(w); l += MAX(0, k); t = kAscii; break; case kEsc: if (c == '[') { t = kCsi; } else if (!(040 <= c && c < 060)) { t = kAscii; } break; case kCsi: if (!(060 <= c && c < 0100)) { t = kAscii; } break; default: __builtin_unreachable(); } } else { break; } } return l; } ================================================ FILE: blink/strwidth.h ================================================ #ifndef BLINK_STRWIDTH_H_ #define BLINK_STRWIDTH_H_ #include int strwidth(const char *, size_t); int strnwidth(const char *, size_t, size_t); #endif /* BLINK_STRWIDTH_H_ */ ================================================ FILE: blink/swap.h ================================================ #ifndef BLINK_SWAP_H_ #define BLINK_SWAP_H_ #include #include "blink/builtin.h" #if __has_builtin(__builtin_bswap64) || defined(__GNUC__) #define SWAP16(x) __builtin_bswap16(x) #define SWAP32(x) __builtin_bswap32(x) #define SWAP64(x) __builtin_bswap64(x) #else #define SWAP16(x) \ (((UINT64_C(0x00000000000000ff) & (x)) << 010) | \ ((UINT64_C(0x000000000000ff00) & (x)) >> 010)) #define SWAP32(x) \ (((UINT64_C(0x00000000000000ff) & (x)) << 030) | \ ((UINT64_C(0x000000000000ff00) & (x)) << 010) | \ ((UINT64_C(0x0000000000ff0000) & (x)) >> 010) | \ ((UINT64_C(0x00000000ff000000) & (x)) >> 030)) #define SWAP64(x) \ (((UINT64_C(0x00000000000000ff) & (x)) << 070) | \ ((UINT64_C(0x000000000000ff00) & (x)) << 050) | \ ((UINT64_C(0x0000000000ff0000) & (x)) << 030) | \ ((UINT64_C(0x00000000ff000000) & (x)) << 010) | \ ((UINT64_C(0x000000ff00000000) & (x)) >> 010) | \ ((UINT64_C(0x0000ff0000000000) & (x)) >> 030) | \ ((UINT64_C(0x00ff000000000000) & (x)) >> 050) | \ ((UINT64_C(0xff00000000000000) & (x)) >> 070)) #endif #endif /* BLINK_SWAP_H_ */ ================================================ FILE: blink/syscall.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/syscall.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "blink/ancillary.h" #include "blink/assert.h" #include "blink/atomic.h" #include "blink/bitscan.h" #include "blink/bus.h" #include "blink/case.h" #include "blink/checked.h" #include "blink/debug.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/flag.h" #include "blink/iovs.h" #include "blink/limits.h" #include "blink/linux.h" #include "blink/loader.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/ndelay.h" #include "blink/overlays.h" #include "blink/pml4t.h" #include "blink/preadv.h" #include "blink/random.h" #include "blink/signal.h" #include "blink/stats.h" #include "blink/strace.h" #include "blink/swap.h" #include "blink/thread.h" #include "blink/timespec.h" #include "blink/util.h" #include "blink/vfs.h" #include "blink/xlat.h" #ifdef __linux #include #endif #ifdef __EMSCRIPTEN__ #include #endif #ifdef __HAIKU__ #include #include #endif #ifdef HAVE_SCHED_H #include #endif #ifdef HAVE_EPOLL_PWAIT1 #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef SO_LINGER_SEC #define SO_LINGER_ SO_LINGER_SEC #else #define SO_LINGER_ SO_LINGER #endif #define SYSARGS0 #define SYSARGS1 , di #define SYSARGS2 , di, si #define SYSARGS3 , di, si, dx #define SYSARGS4 , di, si, dx, r0 #define SYSARGS5 , di, si, dx, r0, r8 #define SYSARGS6 , di, si, dx, r0, r8, r9 #define SYSCALL(arity, ordinal, name, func, signature) \ case ordinal: \ if (STRACE && FLAG_strace >= (signature)[0]) { \ Strace(m, name, true, &(signature)[1] SYSARGS##arity); \ } \ ax = func(m SYSARGS##arity); \ if (STRACE && FLAG_strace) { \ Strace(m, name, false, &(signature)[1], ax SYSARGS##arity); \ } \ break char *g_blink_path; bool FLAG_statistics; // delegate to work around function pointer errors, b/c // old musl toolchains using `int ioctl(int, int, ...)` static int SystemIoctl(int fd, unsigned long request, ...) { va_list va; uintptr_t arg; va_start(va, request); arg = va_arg(va, uintptr_t); va_end(va); return VfsIoctl(fd, request, (void *)arg); } #ifdef __EMSCRIPTEN__ // If this runs on the main thread, the browser is blocked until we return // back to the main loop. Yield regularly when the process waits for some // user input. int em_poll(struct pollfd *fds, nfds_t nfds, int timeout) { int ret = VfsPoll(fds, nfds, timeout); if (ret == 0) emscripten_sleep(50); return ret; } ssize_t em_readv(int fd, const struct iovec *iov, int iovcnt) { // Handle blocking reads by waiting for POLLIN if ((VfsFcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; while (em_poll(&pfd, 1, 50) == 0) { } } size_t ret = VfsReadv(fd, iov, iovcnt); if (ret == -1 && errno == EAGAIN) emscripten_sleep(50); return ret; } #endif static int my_tcgetwinsize(int fd, struct winsize *ws) { return VfsIoctl(fd, TIOCGWINSZ, (void *)ws); } static int my_tcsetwinsize(int fd, const struct winsize *ws) { return VfsIoctl(fd, TIOCSWINSZ, (void *)ws); } const struct FdCb kFdCbHost = { .close = VfsClose, #ifdef __EMSCRIPTEN__ .readv = em_readv, #else .readv = VfsReadv, #endif .writev = VfsWritev, #ifdef __EMSCRIPTEN__ .poll = em_poll, #else .poll = VfsPoll, #endif .tcgetattr = VfsTcgetattr, .tcsetattr = VfsTcsetattr, .tcgetwinsize = my_tcgetwinsize, .tcsetwinsize = my_tcsetwinsize, }; struct Fd *GetAndLockFd(struct Machine *m, int fildes) { struct Fd *fd; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) LockFd(fd); UNLOCK(&m->system->fds.lock); return fd; } int GetDirFildes(int fildes) { if (fildes == AT_FDCWD_LINUX) return AT_FDCWD; return fildes; } const char *GetDirFildesPath(struct System *s, int fildes) { struct Fd *fd; if (fildes == AT_FDCWD_LINUX) return "."; if ((fd = GetFd(&s->fds, fildes))) return fd->path; return 0; } void SignalActor(struct Machine *m) { for (;;) { STATISTIC(++interps); JitlessDispatch(DISPATCH_NOTHING); if (atomic_load_explicit(&m->attention, memory_order_acquire)) { if (m->restored) break; CheckForSignals(m); } } } bool DeliverSignalRecursively(struct Machine *m, int sig) { bool issigsuspend; sigset_t unblock, oldmask; SYS_LOGF("recursing %s", DescribeSignal(sig)); if (m->sigdepth >= kMaxSigDepth) { LOGF("exceeded max signal depth"); return false; } // we're officially calling a signal handler // run the signal handler code inside the i/o routine // it's very important that no locks are currently held // garbage may exist on the freelist for calls like sendmsg ++m->sigdepth; if ((issigsuspend = m->issigsuspend)) { m->issigsuspend = false; unassert(!sigemptyset(&unblock)); unassert(!pthread_sigmask(SIG_BLOCK, &unblock, &oldmask)); } m->restored = false; m->insyscall = false; SignalActor(m); m->insyscall = true; m->restored = false; if (issigsuspend) { unassert(!pthread_sigmask(SIG_SETMASK, &oldmask, 0)); m->issigsuspend = true; } --m->sigdepth; return true; } bool CheckInterrupt(struct Machine *m, bool restartable) { bool res, restart; int sig, delivered; // an actual i/o call just received EINTR from the kernel HandleSomeMoreInterrupts: // determine if there's any signals pending for our guest Put64(m->ax, -EINTR_LINUX); if ((sig = ConsumeSignal(m, &delivered, &restart))) { TerminateSignal(m, sig, 0); } if (delivered) { if (DeliverSignalRecursively(m, delivered)) { if (restart && restartable) { // try to consume some more signals while we're here goto HandleSomeMoreInterrupts; } else { // let the i/o routine return eintr errno = EINTR; res = true; } } else { errno = EINTR; res = true; } } else { // no signal is being delivered res = false; } m->interrupted = res; return res; } static struct Futex *FindFutex(struct Machine *m, i64 addr) { struct Dll *e; for (e = dll_first(g_bus->futexes.active); e; e = dll_next(g_bus->futexes.active, e)) { if (FUTEX_CONTAINER(e)->addr == addr) { return FUTEX_CONTAINER(e); } } return 0; } static int SysFutexWake(struct Machine *m, i64 uaddr, u32 count) { int rc; struct Futex *f; if (!count) return 0; LOCK(&g_bus->futexes.lock); if ((f = FindFutex(m, uaddr))) { LOCK(&f->lock); } UNLOCK(&g_bus->futexes.lock); if (f && f->waiters) { THR_LOGF("pid=%d tid=%d is waking %d waiters at address %#" PRIx64, m->system->pid, m->tid, f->waiters, uaddr); if (count == 1) { unassert(!pthread_cond_signal(&f->cond)); rc = 1; } else { unassert(!pthread_cond_broadcast(&f->cond)); rc = f->waiters; } UNLOCK(&f->lock); } else { if (f) UNLOCK(&f->lock); THR_LOGF("pid=%d tid=%d is waking no one at address %#" PRIx64, m->system->pid, m->tid, uaddr); rc = 0; } return rc; } static void ClearChildTid(struct Machine *m) { #if defined(HAVE_FORK) || defined(HAVE_THREADS) _Atomic(int) *ctid; if (m->ctid) { THR_LOGF("ClearChildTid(%#" PRIx64 ")", m->ctid); if ((ctid = (_Atomic(int) *)LookupAddress(m, m->ctid))) { atomic_store_explicit(ctid, 0, memory_order_seq_cst); } else { THR_LOGF("invalid clear child tid address %#" PRIx64, m->ctid); } } SysFutexWake(m, m->ctid, INT_MAX); #endif } _Noreturn void SysExitGroup(struct Machine *m, int rc) { THR_LOGF("pid=%d tid=%d SysExitGroup", m->system->pid, m->tid); ClearChildTid(m); if (m->system->isfork) { #ifndef NDEBUG if (FLAG_statistics) { PrintStats(); } #endif THR_LOGF("calling _Exit(%d)", rc); _Exit(rc); } else { THR_LOGF("calling exit(%d)", rc); KillOtherThreads(m->system); #ifdef HAVE_JIT DisableJit(&m->system->jit); // unmapping exec pages is slow #endif if (m->system->trapexit && !m->system->exited) { m->system->exited = true; m->system->exitcode = rc; HaltMachine(m, kMachineExitTrap); } FreeMachine(m); #ifdef HAVE_JIT ShutdownJit(); #endif #ifndef NDEBUG if (FLAG_statistics) { PrintStats(); } #endif exit(rc); } } _Noreturn void SysExit(struct Machine *m, int rc) { #ifdef HAVE_THREADS THR_LOGF("pid=%d tid=%d SysExit", m->system->pid, m->tid); if (IsOrphan(m)) { SysExitGroup(m, rc); } else { ClearChildTid(m); FreeMachine(m); pthread_exit(EXIT_SUCCESS); } #else SysExitGroup(m, rc); #endif } static int Fork(struct Machine *m, u64 flags, u64 stack, u64 ctid) { int pid, newpid = 0; _Atomic(int) *ctid_ptr; unassert(!m->path.jb); // NOTES ON THE LOCKING TOPOLOGY // exec_lock must come before sig_lock (see dup3) // exec_lock must come before fds.lock (see dup3) // exec_lock must come before fds.lock (see execve) // mmap_lock must come before fds.lock (see GetOflags) // mmap_lock must come before pagelocks_lock (see FreePage) if (m->threaded) { LOCK(&m->system->exec_lock); LOCK(&m->system->sig_lock); LOCK(&m->system->mmap_lock); LOCK(&m->system->pagelocks_lock); LOCK(&m->system->fds.lock); LOCK(&m->system->machines_lock); #ifndef HAVE_PTHREAD_PROCESS_SHARED LOCK(&g_bus->futexes.lock); #endif #ifdef HAVE_JIT LOCK(&m->system->jit.lock); #endif } pid = fork(); #ifdef __HAIKU__ // haiku wipes tls after fork() in child // https://dev.haiku-os.org/ticket/17896 if (!pid) g_machine = m; #endif if (m->threaded) { #ifdef HAVE_JIT UNLOCK(&m->system->jit.lock); #endif #ifndef HAVE_PTHREAD_PROCESS_SHARED UNLOCK(&g_bus->futexes.lock); #endif UNLOCK(&m->system->machines_lock); UNLOCK(&m->system->fds.lock); UNLOCK(&m->system->pagelocks_lock); UNLOCK(&m->system->mmap_lock); UNLOCK(&m->system->sig_lock); UNLOCK(&m->system->exec_lock); } if (!pid) { newpid = getpid(); if (stack) { Put64(m->sp, stack); } #ifndef HAVE_PTHREAD_PROCESS_SHARED InitBus(); #endif THR_LOGF("pid=%d tid=%d SysFork -> pid=%d tid=%d", // m->system->pid, m->tid, newpid, newpid); m->tid = m->system->pid = newpid; m->system->isfork = true; RemoveOtherThreads(m->system); #ifdef __CYGWIN__ // Cygwin doesn't seem to properly set the PROT_EXEC // protection for JIT blocks after forking. FixJitProtection(&m->system->jit); #endif if ((flags & (CLONE_CHILD_SETTID_LINUX | CLONE_CHILD_CLEARTID_LINUX)) && !(ctid & (sizeof(i32) - 1)) && (ctid_ptr = (_Atomic(i32) *)LookupAddress(m, ctid))) { if (flags & CLONE_CHILD_SETTID_LINUX) { atomic_store_explicit(ctid_ptr, Little32(newpid), memory_order_release); } if (flags & CLONE_CHILD_CLEARTID_LINUX) { m->ctid = ctid; } } } return pid; } static int SysFork(struct Machine *m) { return Fork(m, 0, 0, 0); } static int SysVfork(struct Machine *m) { // TODO: Parent should be stopped while child is running. return SysFork(m); } static void *OnSpawn(void *arg) { int rc; struct Machine *m = (struct Machine *)arg; THR_LOGF("pid=%d tid=%d OnSpawn", m->system->pid, m->tid); m->thread = pthread_self(); if (!(rc = sigsetjmp(m->onhalt, 1))) { m->canhalt = true; unassert(!pthread_sigmask(SIG_SETMASK, &m->spawn_sigmask, 0)); } else if (rc == kMachineFatalSystemSignal) { HandleFatalSystemSignal(m, &g_siginfo); } Blink(m); } #ifdef HAVE_THREADS static int SysSpawn(struct Machine *m, u64 flags, u64 stack, u64 ptid, u64 ctid, u64 tls, u64 func) { int tid; int err; int ignored; pthread_t thread; unsigned supported; unsigned mandatory; sigset_t ss, oldss; pthread_attr_t attr; _Atomic(int) *ptid_ptr; _Atomic(int) *ctid_ptr; struct Machine *m2 = 0; THR_LOGF("pid=%d tid=%d SysSpawn", m->system->pid, m->tid); if ((flags & 255) != 0 && (flags & 255) != SIGCHLD_LINUX) { LOGF("unsupported clone() signal: %" PRId64, flags & 255); return einval(); } flags &= ~255; supported = CLONE_THREAD_LINUX | CLONE_VM_LINUX | CLONE_FS_LINUX | CLONE_FILES_LINUX | CLONE_SIGHAND_LINUX | CLONE_SETTLS_LINUX | CLONE_PARENT_SETTID_LINUX | CLONE_CHILD_CLEARTID_LINUX | CLONE_CHILD_SETTID_LINUX | CLONE_SYSVSEM_LINUX; mandatory = CLONE_THREAD_LINUX | CLONE_VM_LINUX | CLONE_FS_LINUX | CLONE_FILES_LINUX | CLONE_SIGHAND_LINUX; ignored = CLONE_DETACHED_LINUX | CLONE_IO_LINUX; flags &= ~ignored; if (flags & ~supported) { LOGF("unsupported clone() flags: %#" PRIx64, flags & ~supported); return einval(); } if ((flags & mandatory) != mandatory) { LOGF("missing mandatory clone() thread flags: %#" PRIx64 " out of %#" PRIx64, (flags & mandatory) ^ mandatory, flags); return einval(); } if (((flags & CLONE_PARENT_SETTID_LINUX) && ((ptid & (sizeof(int) - 1)) || !IsValidMemory(m, ptid, 4, PROT_READ | PROT_WRITE) || !(ptid_ptr = (_Atomic(int) *)LookupAddress(m, ptid)))) || ((flags & CLONE_CHILD_SETTID_LINUX) && ((ctid & (sizeof(int) - 1)) || !IsValidMemory(m, ctid, 4, PROT_READ | PROT_WRITE) || !(ctid_ptr = (_Atomic(int) *)LookupAddress(m, ctid))))) { LOGF("bad clone() ptid / ctid pointers: %#" PRIx64, flags); return efault(); } m->threaded = true; m->system->jit.threaded = true; if (!(m2 = NewMachine(m->system, m))) { return eagain(); } sigfillset(&ss); unassert(!pthread_sigmask(SIG_SETMASK, &ss, &oldss)); tid = m2->tid; if (flags & CLONE_SETTLS_LINUX) { m2->fs.base = tls; } if (flags & CLONE_CHILD_CLEARTID_LINUX) { m2->ctid = ctid; } if (flags & CLONE_CHILD_SETTID_LINUX) { atomic_store_explicit(ctid_ptr, Little32(tid), memory_order_release); } Put64(m2->ax, 0); Put64(m2->sp, stack); m2->spawn_sigmask = oldss; unassert(!pthread_attr_init(&attr)); unassert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); err = pthread_create(&thread, &attr, OnSpawn, m2); unassert(!pthread_attr_destroy(&attr)); if (err) { FreeMachine(m2); unassert(!pthread_sigmask(SIG_SETMASK, &oldss, 0)); return eagain(); } if (flags & CLONE_PARENT_SETTID_LINUX) { atomic_store_explicit(ptid_ptr, Little32(tid), memory_order_release); } unassert(!pthread_sigmask(SIG_SETMASK, &oldss, 0)); return tid; } #endif static bool IsForkOrVfork(u64 flags) { u64 supported = CLONE_CHILD_SETTID_LINUX | CLONE_CHILD_CLEARTID_LINUX; return (flags & ~supported) == SIGCHLD_LINUX || (flags & ~supported) == (CLONE_VM_LINUX | CLONE_VFORK_LINUX | SIGCHLD_LINUX); } static int SysClone(struct Machine *m, u64 flags, u64 stack, u64 ptid, u64 ctid, u64 tls, u64 func) { if (IsForkOrVfork(flags)) { #ifdef HAVE_FORK return Fork(m, flags, stack, ctid); #else LOGF("forking support disabled"); return enosys(); #endif } #ifdef HAVE_THREADS return SysSpawn(m, flags, stack, ptid, ctid, tls, func); #else LOGF("threading support disabled"); return enosys(); #endif } static struct Futex *NewFutex(i64 addr) { struct Dll *e; struct Futex *f; if (!(e = dll_first(g_bus->futexes.free))) { LOG_ONCE(LOGF("ran out of futexes")); enomem(); return 0; } dll_remove(&g_bus->futexes.free, e); f = FUTEX_CONTAINER(e); f->waiters = 1; f->addr = addr; return f; } static void FreeFutex(struct Futex *f) { dll_make_first(&g_bus->futexes.free, &f->elem); } static int LoadTimespec(struct Machine *m, i64 addr, struct timespec *ts, u64 mask, u64 need) { const struct timespec_linux *gt; if ((gt = (const struct timespec_linux *)Schlep(m, addr, sizeof(*gt), mask, need))) { ts->tv_sec = Read64(gt->sec); ts->tv_nsec = Read64(gt->nsec); if (0 <= ts->tv_sec && (0 <= ts->tv_nsec && ts->tv_nsec < 1000000000)) { return 0; } else { return einval(); } } else { return -1; } } static int LoadTimespecR(struct Machine *m, i64 addr, struct timespec *ts) { return LoadTimespec(m, addr, ts, PAGE_U, PAGE_U); } static int LoadTimespecRW(struct Machine *m, i64 addr, struct timespec *ts) { return LoadTimespec(m, addr, ts, PAGE_U | PAGE_RW, PAGE_U | PAGE_RW); } static int SysFutexWait(struct Machine *m, // i64 uaddr, // i32 op, // u32 expect, // i64 timeout_addr) { int rc; u8 *mem; struct Futex *f; const struct timespec_linux *gtimeout; struct timespec now, tick, timeout, deadline; now = tick = GetTime(); if (timeout_addr) { if (!(gtimeout = (const struct timespec_linux *)SchlepR( m, timeout_addr, sizeof(*gtimeout)))) { return -1; } timeout.tv_sec = Read64(gtimeout->sec); timeout.tv_nsec = Read64(gtimeout->nsec); if (!(0 <= timeout.tv_nsec && timeout.tv_nsec < 1000000000)) { return einval(); } deadline = AddTime(now, timeout); } else { deadline = GetMaxTime(); } if (!(mem = LookupAddress(m, uaddr))) return -1; LOCK(&g_bus->futexes.lock); if (Load32(mem) != expect) { UNLOCK(&g_bus->futexes.lock); return eagain(); } if ((f = FindFutex(m, uaddr))) { LOCK(&f->lock); ++f->waiters; UNLOCK(&f->lock); } if (!f) { if ((f = NewFutex(uaddr))) { dll_make_first(&g_bus->futexes.active, &f->elem); } else { UNLOCK(&g_bus->futexes.lock); return -1; } } UNLOCK(&g_bus->futexes.lock); THR_LOGF("pid=%d tid=%d is waiting at address %#" PRIx64, m->system->pid, m->tid, uaddr); do { if (m->killed) { rc = EAGAIN; break; } if (CheckInterrupt(m, true)) { rc = EINTR; break; } if (!(mem = LookupAddress(m, uaddr))) { rc = errno; break; } LOCK(&f->lock); if (Load32(mem) != expect) { rc = 0; } else { tick = AddTime(tick, FromMilliseconds(kPollingMs)); if (CompareTime(tick, deadline) > 0) tick = deadline; rc = pthread_cond_timedwait(&f->cond, &f->lock, &tick); if (rc == ETIMEDOUT) { THR_LOGF("futex wait timed out"); } else { THR_LOGF("futex wait returned %s", DescribeHostErrno(rc)); } } UNLOCK(&f->lock); } while (rc == ETIMEDOUT && CompareTime(tick, deadline) < 0); LOCK(&g_bus->futexes.lock); LOCK(&f->lock); if (!--f->waiters) { dll_remove(&g_bus->futexes.active, &f->elem); UNLOCK(&f->lock); FreeFutex(f); UNLOCK(&g_bus->futexes.lock); } else { UNLOCK(&f->lock); UNLOCK(&g_bus->futexes.lock); } if (rc) { errno = rc; rc = -1; } return rc; } static int SysFutex(struct Machine *m, // i64 uaddr, // i32 op, // u32 val, // i64 timeout_addr, // i64 uaddr2, // u32 val3) { if (uaddr & 3) return efault(); op &= ~FUTEX_PRIVATE_FLAG_LINUX; switch (op) { case FUTEX_WAIT_LINUX: return SysFutexWait(m, uaddr, op, val, timeout_addr); case FUTEX_WAKE_LINUX: return SysFutexWake(m, uaddr, val); case FUTEX_WAIT_BITSET_LINUX: case FUTEX_WAIT_BITSET_LINUX | FUTEX_CLOCK_REALTIME_LINUX: // will be supported soon // avoid logging when cosmo feature checks this if (!m->system->iscosmo) goto DefaultCase; return einval(); default: DefaultCase: LOGF("unsupported %s op %#x", "futex", op); return einval(); } } static void UnlockRobustFutex(struct Machine *m, u64 futex_addr, bool ispending) { int owner; u32 value, replace; _Atomic(u32) *futex; if (futex_addr & 3) { LOGF("robust futex isn't aligned"); return; } if (!(futex = (_Atomic(u32) *)SchlepR(m, futex_addr, 4))) { LOGF("encountered efault in robust futex list"); return; } for (value = atomic_load_explicit(futex, memory_order_acquire);;) { owner = value & FUTEX_TID_MASK_LINUX; if (ispending && !owner) { THR_LOGF("unlocking pending ownerless futex"); SysFutexWake(m, futex_addr, 1); return; } if (owner && owner != m->tid) { THR_LOGF("robust futex 0x%08" PRIx32 " was owned by %d but we're tid=%d pid=%d", value, owner, m->tid, m->system->pid); return; } replace = FUTEX_OWNER_DIED_LINUX | (value & FUTEX_WAITERS_LINUX); if (atomic_compare_exchange_weak_explicit(futex, &value, replace, memory_order_release, memory_order_acquire)) { THR_LOGF("successfully unlocked robust futex"); if (value & FUTEX_WAITERS_LINUX) { THR_LOGF("waking robust futex waiters"); SysFutexWake(m, futex_addr, 1); } return; } else { THR_LOGF("robust futex cas failed"); } } } void UnlockRobustFutexes(struct Machine *m) { if (1) return; // TODO: Figure out how these work. int limit = 1000; bool once = false; u64 list, item, pending; struct robust_list_linux *data; if (!(item = list = m->robust_list)) return; m->robust_list = 0; pending = 0; do { if (!(data = (struct robust_list_linux *)SchlepR(m, item, sizeof(*data)))) { LOGF("encountered efault in robust futex list"); break; } THR_LOGF("unlocking robust futex %#" PRIx64 " {.next=%#" PRIx64 " .offset=%" PRId64 " .pending=%#" PRIx64 "}", item, Read64(data->next), Read64(data->offset), Read64(data->pending)); if (!once) { pending = Read64(data->pending); once = true; } if (!--limit) { LOGF("encountered cycle or limit in robust futex list"); break; } if (item != pending) { UnlockRobustFutex(m, item + Read64(data->offset), false); } item = Read64(data->next); } while (item != list); if (!pending) return; if (!(data = (struct robust_list_linux *)SchlepR(m, pending, sizeof(*data)))) { LOGF("encountered efault in robust futex list"); return; } THR_LOGF("unlocking pending robust futex %#" PRIx64 " {.next=%#" PRIx64 " .offset=%" PRId64 " .pending=%#" PRIx64 "}", item, Read64(data->next), Read64(data->offset), Read64(data->pending)); UnlockRobustFutex(m, pending + Read64(data->offset), true); } static i32 ReturnRobustList(struct Machine *m, i64 head_ptr_addr, i64 len_ptr_addr) { u8 buf[8]; Write64(buf, m->robust_list); CopyToUserWrite(m, head_ptr_addr, buf, sizeof(buf)); Write64(buf, sizeof(struct robust_list_linux)); CopyToUserWrite(m, len_ptr_addr, buf, sizeof(buf)); return 0; } static i32 SysGetRobustList(struct Machine *m, int pid, i64 head_ptr_addr, i64 len_ptr_addr) { int rc; struct Dll *e; struct Machine *m2; if (!pid || pid == m->tid) { rc = ReturnRobustList(m, head_ptr_addr, len_ptr_addr); } else { rc = -1; errno = ESRCH; LOCK(&m->system->machines_lock); for (e = dll_first(m->system->machines); e; e = dll_next(m->system->machines, e)) { m2 = MACHINE_CONTAINER(e); if (m2->tid == pid) { rc = ReturnRobustList(m2, head_ptr_addr, len_ptr_addr); break; } } UNLOCK(&m->system->machines_lock); } return rc; } static i32 SysSetRobustList(struct Machine *m, i64 head_addr, u64 len) { if (len != sizeof(struct robust_list_linux)) return einval(); if (!IsValidMemory(m, head_addr, len, PROT_READ | PROT_WRITE)) return -1; m->robust_list = head_addr; return 0; } static int ValidateAffinityPid(struct Machine *m, int pid) { if (pid < 0) return esrch(); if (pid && pid != m->tid && pid != m->system->pid) return eperm(); return 0; } static int SysSchedSetaffinity(struct Machine *m, // i32 pid, // u64 cpusetsize, // i64 maskaddr) { if (ValidateAffinityPid(m, pid) == -1) return -1; #ifdef HAVE_SCHED_GETAFFINITY u8 *mask; size_t i, n; cpu_set_t sysmask; GetCpuCount(); // call for effect n = MIN(cpusetsize, CPU_SETSIZE / 8) * 8; if (!(mask = (u8 *)AddToFreeList(m, malloc(n / 8)))) return -1; if (CopyFromUserRead(m, mask, maskaddr, n / 8) == -1) return -1; CPU_ZERO(&sysmask); for (i = 0; i < n; ++i) { if (mask[i / 8] & (1 << (i % 8))) { CPU_SET(i, &sysmask); } } return sched_setaffinity(pid, sizeof(sysmask), &sysmask); #else return 0; // do nothing #endif } static int SysSchedGetaffinity(struct Machine *m, // i32 pid, // u64 cpusetsize, // i64 maskaddr) { if (ValidateAffinityPid(m, pid) == -1) return -1; #ifdef HAVE_SCHED_GETAFFINITY int rc; u8 *mask; size_t i, n; cpu_set_t sysmask; n = MIN(cpusetsize, CPU_SETSIZE / 8) * 8; if (!(mask = (u8 *)AddToFreeList(m, malloc(n / 8)))) return -1; rc = sched_getaffinity(pid, sizeof(sysmask), &sysmask); unassert(rc == 0 || rc == -1); if (!rc) { rc = n / 8; memset(mask, 0, n / 8); for (i = 0; i < n; ++i) { if (CPU_ISSET(i, &sysmask)) { mask[i / 8] |= 1 << (i % 8); } } if (CopyToUserWrite(m, maskaddr, mask, n / 8) == -1) rc = -1; } return rc; #else u8 *mask; unsigned i, rc, count; count = GetCpuCount(); rc = ROUNDUP(count, 64) / 8; if (cpusetsize < rc) return einval(); if (!(mask = (u8 *)AddToFreeList(m, calloc(1, rc)))) return -1; count = MIN(count, rc * 8); for (i = 0; i < count; ++i) { mask[i / 8] |= 1 << (i % 8); } if (CopyToUserWrite(m, maskaddr, mask, rc) == -1) rc = -1; return rc; #endif } static int SysPrctlGetTsc(struct Machine *m, i64 arg2) { u8 word[4]; Write32(word, m->traprdtsc ? PR_TSC_SIGSEGV_LINUX : PR_TSC_ENABLE_LINUX); return CopyToUserWrite(m, arg2, word, sizeof(word)); } static int SysPrctlSetTsc(struct Machine *m, i64 arg2) { switch (arg2) { case PR_TSC_ENABLE_LINUX: m->traprdtsc = false; return 0; case PR_TSC_SIGSEGV_LINUX: m->traprdtsc = true; return 0; default: return einval(); } } static int SysPrctl(struct Machine *m, int op, i64 arg2, i64 arg3, i64 arg4, i64 arg5) { switch (op) { case PR_GET_TSC_LINUX: return SysPrctlGetTsc(m, arg2); case PR_SET_TSC_LINUX: return SysPrctlSetTsc(m, arg2); #ifdef PR_CAPBSET_DROP case PR_CAPBSET_DROP_LINUX: return prctl(PR_CAPBSET_DROP, arg2, arg3, arg4, arg5); #else case PR_CAPBSET_DROP_LINUX: return einval(); #endif #ifdef PR_SET_NO_NEW_PRIVS case PR_SET_NO_NEW_PRIVS_LINUX: return prctl(PR_SET_NO_NEW_PRIVS, arg2, arg3, arg4, arg5); #else case PR_SET_NO_NEW_PRIVS_LINUX: return einval(); #endif case PR_GET_SECCOMP_LINUX: case PR_SET_SECCOMP_LINUX: // avoid noisy feature check warnings in cosmopolitan if (!m->system->iscosmo) goto DefaultCase; return einval(); default: DefaultCase: LOGF("unsupported %s op %#x", "prctl", op); return einval(); } } static int SysArchPrctl(struct Machine *m, int op, i64 addr) { #ifndef DISABLE_NONPOSIX u8 buf[8]; #endif switch (op) { case ARCH_SET_FS_LINUX: m->fs.base = addr; return 0; #ifndef DISABLE_NONPOSIX case ARCH_SET_GS_LINUX: m->gs.base = addr; return 0; case ARCH_GET_FS_LINUX: Write64(buf, m->fs.base); return CopyToUserWrite(m, addr, buf, 8); case ARCH_GET_GS_LINUX: Write64(buf, m->gs.base); return CopyToUserWrite(m, addr, buf, 8); case ARCH_GET_CPUID_LINUX: return !m->trapcpuid; case ARCH_SET_CPUID_LINUX: m->trapcpuid = !addr; return 0; #endif default: LOGF("unsupported %s op %#x", "arch_prctl", op); return einval(); } } static u64 Prot2Page(int prot) { u64 key = 0; if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) return einval(); if (prot & PROT_READ) key |= PAGE_U; if (prot & PROT_WRITE) key |= PAGE_RW | PAGE_U; if (~prot & PROT_EXEC) key |= PAGE_XD; return key; } static int SysMprotect(struct Machine *m, i64 addr, u64 size, int prot) { _Static_assert(PROT_READ == 1, ""); _Static_assert(PROT_WRITE == 2, ""); _Static_assert(PROT_EXEC == 4, ""); int rc; int unsupported; if (size > NUMERIC_MAX(size_t)) return eoverflow(); if (!IsValidAddrSize(addr, size)) return einval(); if ((unsupported = prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))) { LOGF("unsupported mprotect() protection: %#x", unsupported); return einval(); } BEGIN_NO_PAGE_FAULTS; LOCK(&m->system->mmap_lock); rc = ProtectVirtual(m->system, addr, size, prot, false); unassert(CheckMemoryInvariants(m->system)); UNLOCK(&m->system->mmap_lock); END_NO_PAGE_FAULTS; return rc; } static int SysMadvise(struct Machine *m, i64 addr, u64 len, int advice) { return 0; } static i64 SysBrk(struct Machine *m, i64 addr) { i64 rc, size; long pagesize; BEGIN_NO_PAGE_FAULTS; LOCK(&m->system->mmap_lock); MEM_LOGF("brk(%#" PRIx64 ") currently %#" PRIx64, addr, m->system->brk); pagesize = FLAG_pagesize; addr = ROUNDUP(addr, pagesize); if (addr >= kNullSize) { if (addr > m->system->brk) { size = addr - m->system->brk; CleanseMemory(m->system, size); if (m->system->rss < GetMaxRss(m->system)) { if (size / 4096 + m->system->vss < GetMaxVss(m->system)) { if (ReserveVirtual(m->system, m->system->brk, addr - m->system->brk, PAGE_FILE | PAGE_RW | PAGE_U | PAGE_XD, -1, 0, 0, 0) != -1) { if (!m->system->brkchanged) { unassert(AddFileMap(m->system, m->system->brk, addr - m->system->brk, "[heap]", -1)); m->system->brkchanged = true; } MEM_LOGF("increased break %" PRIx64 " -> %" PRIx64, m->system->brk, addr); m->system->brk = addr; } } else { LOGF("not enough virtual memory (%lx / %#lx pages) to map size " "%#" PRIx64, m->system->vss, GetMaxVss(m->system), size); } } else { LOGF("ran out of resident memory (%#lx / %#lx pages)", m->system->rss, GetMaxRss(m->system)); } } else if (addr < m->system->brk) { if (FreeVirtual(m->system, addr, m->system->brk - addr) != -1) { m->system->brk = addr; } } } rc = m->system->brk; unassert(CheckMemoryInvariants(m->system)); UNLOCK(&m->system->mmap_lock); END_NO_PAGE_FAULTS; return rc; } static int SysMunmap(struct Machine *m, i64 virt, u64 size) { int rc; BEGIN_NO_PAGE_FAULTS; LOCK(&m->system->mmap_lock); rc = FreeVirtual(m->system, virt, size); unassert(CheckMemoryInvariants(m->system)); UNLOCK(&m->system->mmap_lock); END_NO_PAGE_FAULTS; return rc; } int GetOflags(struct Machine *m, int fildes) { int oflags; struct Fd *fd; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { oflags = fd->oflags; } else { oflags = -1; } UNLOCK(&m->system->fds.lock); return oflags; } static i64 SysMmapImpl(struct Machine *m, i64 virt, i64 size, int prot, int flags, int fildes, i64 offset) { u64 key; int oflags; bool fixedmap; i64 newautomap; if (!IsValidAddrSize(virt, size)) return einval(); if (flags & MAP_GROWSDOWN_LINUX) return enotsup(); if ((key = Prot2Page(prot)) == (u64)-1) return einval(); CleanseMemory(m->system, size); if (m->system->rss >= GetMaxRss(m->system)) { LOGF("ran out of resident memory (%lx / %lx pages)", m->system->rss, GetMaxRss(m->system)); return enomem(); } if (size / 4096 + m->system->vss > GetMaxVss(m->system)) { LOGF("not enough virtual memory (%lx / %lx pages) to map size %" PRIx64, m->system->vss, GetMaxVss(m->system), size); return enomem(); } if (flags & MAP_ANONYMOUS_LINUX) { fildes = -1; if ((flags & MAP_TYPE_LINUX) == MAP_FILE_LINUX) { return einval(); } } else if (offset < 0) { return einval(); } else if (offset > NUMERIC_MAX(off_t)) { return eoverflow(); } if (fildes != -1) { if ((oflags = GetOflags(m, fildes)) == -1) return -1; if ((oflags & O_ACCMODE) == O_WRONLY || // ((prot & PROT_WRITE) && // (oflags & O_APPEND)) || // ((prot & PROT_WRITE) && // (flags & MAP_SHARED_LINUX) && // (oflags & O_ACCMODE) != O_RDWR)) { // errno = EACCES; return -1; } } newautomap = -1; fixedmap = false; if (flags & MAP_FIXED_LINUX) { fixedmap = true; goto CreateTheMap; } if (flags & MAP_FIXED_NOREPLACE_LINUX) { if (IsFullyUnmapped(m->system, virt, size)) { goto CreateTheMap; } else { MEM_LOGF("memory already exists on the interval" " [%" PRIx64 ",%" PRIx64 ")\n" "%s", virt, virt + size, FormatPml4t(g_machine)); errno = EEXIST; virt = -1; goto Finished; } } if (HasLinearMapping() && FLAG_vabits <= 47 && !kSkew && !virt) { goto CreateTheMap; } if ((!virt || !IsFullyUnmapped(m->system, virt, size))) { if ((virt = FindVirtual(m->system, m->system->automap, size)) == -1) { goto Finished; } newautomap = ROUNDUP(virt + size, FLAG_pagesize); if (newautomap >= FLAG_automapend) { newautomap = FLAG_automapstart; } } CreateTheMap: virt = ReserveVirtual(m->system, virt, size, key, fildes, offset, !!(flags & MAP_SHARED_LINUX), fixedmap); if (virt != -1 && newautomap != -1) { m->system->automap = newautomap; } Finished: return virt; } static i64 SysMmap(struct Machine *m, i64 virt, u64 size, int prot, int flags, int fildes, i64 offset) { i64 res; BEGIN_NO_PAGE_FAULTS; LOCK(&m->system->mmap_lock); res = SysMmapImpl(m, virt, size, prot, flags, fildes, offset); unassert(CheckMemoryInvariants(m->system)); UNLOCK(&m->system->mmap_lock); END_NO_PAGE_FAULTS; return res; } static i64 SysMremap(struct Machine *m, i64 old_address, u64 old_size, u64 new_size, int flags, i64 new_address) { // would be nice to have // avoid being noisy in the logs // hope program has fallback for failure LOG_ONCE(MEM_LOGF("mremap() not supported yet")); return enomem(); } static int XlatMsyncFlags(int flags) { int sysflags; if (flags & ~(MS_ASYNC_LINUX | MS_SYNC_LINUX | MS_INVALIDATE_LINUX)) { LOGF("unsupported msync() flags %#x", flags); return einval(); } // According to POSIX, either MS_SYNC or MS_ASYNC must be specified // in flags, and indeed failure to include one of these flags will // cause msync() to fail on some systems. However, Linux permits a // call to msync() that specifies neither of these flags, with // semantics that are (currently) equivalent to specifying MS_ASYNC. // ──Quoth msync(2) of Linux Programmer's Manual if (flags & MS_ASYNC_LINUX) { sysflags = MS_ASYNC; } else if (flags & MS_SYNC_LINUX) { sysflags = MS_SYNC; } else { sysflags = MS_ASYNC; } if (flags & MS_INVALIDATE_LINUX) { sysflags |= MS_INVALIDATE; } #ifdef __FreeBSD__ // FreeBSD's manual says "The flags argument was both MS_ASYNC and // MS_INVALIDATE. Only one of these flags is allowed." which makes // following the POSIX recommendation somewhat difficult. if (sysflags == (MS_ASYNC | MS_INVALIDATE)) { sysflags = MS_INVALIDATE; } #endif return sysflags; } static int SysMsync(struct Machine *m, i64 virt, u64 size, int flags) { if (size > NUMERIC_MAX(size_t)) return eoverflow(); if ((flags = XlatMsyncFlags(flags)) == -1) return -1; return SyncVirtual(m->system, virt, size, flags); } static int SysDup1(struct Machine *m, i32 fildes) { int lim; int oflags; int newfildes; struct Fd *fd; if (fildes < 0) return ebadf(); if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); if ((newfildes = VfsDup(fildes)) != -1) { if (newfildes >= lim) { VfsClose(newfildes); return emfile(); } LOCK(&m->system->fds.lock); unassert(fd = GetFd(&m->system->fds, fildes)); oflags = fd->oflags & ~O_CLOEXEC; unassert(ForkFd(&m->system->fds, fd, newfildes, oflags)); UNLOCK(&m->system->fds.lock); } return newfildes; } static int Dup2(struct Machine *m, int fildes, int newfildes) { int rc; // POSIX.1-2007 lists dup2() as raising EINTR which seems impossible // so it'd be wonderful to learn what kernel(s) actually return this // noting Linux reproduces that in both its dup(2) and dup(3) manual RESTARTABLE(rc = VfsDup2(fildes, newfildes)); return rc; } #ifdef HAVE_DUP3 static int Dup3(struct Machine *m, int fildes, int newfildes, int flags) { int rc; // The Linux Programmer's Manual also lists this as interruptible. RESTARTABLE(rc = VfsDup3(fildes, newfildes, flags)); return rc; } #endif static int SysDup2(struct Machine *m, i32 fildes, i32 newfildes) { int rc, oflags; struct Fd *fd; if (newfildes < 0) { LOGF("dup2() ebadf"); return ebadf(); } if (fildes == newfildes) { // no-op system call, but still must validate LOCK(&m->system->fds.lock); if (GetFd(&m->system->fds, fildes)) { rc = fildes; } else { rc = -1; } UNLOCK(&m->system->fds.lock); } else if (newfildes >= GetFileDescriptorLimit(m->system)) { return ebadf(); } else if ((rc = Dup2(m, fildes, newfildes)) != -1) { LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, newfildes))) { dll_remove(&m->system->fds.list, &fd->elem); FreeFd(fd); } unassert(fd = GetFd(&m->system->fds, fildes)); oflags = fd->oflags & ~O_CLOEXEC; unassert(ForkFd(&m->system->fds, fd, newfildes, oflags)); UNLOCK(&m->system->fds.lock); } return rc; } static int SysDup3(struct Machine *m, i32 fildes, i32 newfildes, i32 flags) { int rc; int oflags; struct Fd *fd; if (newfildes < 0) return ebadf(); if (fildes == newfildes) return einval(); if (flags & ~O_CLOEXEC_LINUX) return einval(); if (newfildes >= GetFileDescriptorLimit(m->system)) return ebadf(); #ifdef HAVE_DUP3 if ((rc = Dup3(m, fildes, newfildes, XlatOpenFlags(flags))) != -1) { #else if ((rc = Dup2(m, fildes, newfildes)) != -1) { if (flags & O_CLOEXEC_LINUX) { unassert(!VfsFcntl(newfildes, F_SETFD, FD_CLOEXEC)); } #endif LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, newfildes))) { dll_remove(&m->system->fds.list, &fd->elem); FreeFd(fd); } unassert(fd = GetFd(&m->system->fds, fildes)); oflags = fd->oflags & ~O_CLOEXEC; if (flags & O_CLOEXEC_LINUX) { oflags |= O_CLOEXEC; } unassert(ForkFd(&m->system->fds, fd, newfildes, oflags)); UNLOCK(&m->system->fds.lock); } return rc; } static int SysDupf(struct Machine *m, i32 fildes, i32 minfildes, int cmd) { struct Fd *fd; int lim, oflags, newfildes; if (minfildes >= (lim = GetFileDescriptorLimit(m->system))) return emfile(); if ((newfildes = VfsFcntl(fildes, cmd, minfildes)) != -1) { if (newfildes >= lim) { VfsClose(newfildes); return emfile(); } LOCK(&m->system->fds.lock); unassert(fd = GetFd(&m->system->fds, fildes)); oflags = fd->oflags & ~O_CLOEXEC; if (cmd == F_DUPFD_CLOEXEC) { oflags |= O_CLOEXEC; } unassert(ForkFd(&m->system->fds, fd, newfildes, oflags)); UNLOCK(&m->system->fds.lock); } return newfildes; } static void FixupSock(int fd, int flags) { if (flags & SOCK_CLOEXEC_LINUX) { unassert(!VfsFcntl(fd, F_SETFD, FD_CLOEXEC)); } if (flags & SOCK_NONBLOCK_LINUX) { unassert(!VfsFcntl(fd, F_SETFL, O_NDELAY)); } } #ifndef BUILD_TIMESTAMP #define BUILD_TIMESTAMP __TIMESTAMP__ #endif #ifndef BLINK_VERSION #define BLINK_VERSION "BLINK_VERSION_UNKNOWN" #warning "-DBLINK_VERSION=... should be passed to blink/syscall.c" #endif #ifndef LINUX_VERSION #define LINUX_VERSION "LINUX_VERSION_UNKNOWN" #warning "-DLINUX_VERSION=... should be passed to blink/syscall.c" #endif #ifndef BLINK_COMMITS #define BLINK_COMMITS "BLINK_COMMITS_UNKNOWN" #warning "-DBLINK_COMMITS=... should be passed to blink/syscall.c" #endif #ifndef BLINK_UNAME_V #define BLINK_UNAME_V "BLINK_UNAME_V_UNKNOWN" #warning "-DBLINK_UNAME_V=... should be passed to blink/syscall.c" #endif static int SysUname(struct Machine *m, i64 utsaddr) { // glibc binaries won't run unless we report blink as a // modern linux kernel on top of genuine intel hardware struct utsname_linux uts; union { char host[sizeof(uts.nodename)]; char domain[sizeof(uts.domainname)]; } u; memset(&uts, 0, sizeof(uts)); strcpy(uts.machine, "x86_64"); strcpy(uts.sysname, "Linux"); strcpy(uts.release, LINUX_VERSION "-blink-" BLINK_VERSION); strcpy(uts.version, "#" BLINK_COMMITS " " BLINK_UNAME_V " " BUILD_TIMESTAMP); memset(u.host, 0, sizeof(u.host)); gethostname(u.host, sizeof(u.host) - 1); strcpy(uts.nodename, u.host); #ifdef HAVE_GETDOMAINNAME memset(u.domain, 0, sizeof(u.domain)); if (getdomainname(u.domain, sizeof(u.domain) - 1) != 0 || !*u.domain) #endif { strcpy(u.domain, "(none)"); } strcpy(uts.domainname, u.domain); return CopyToUser(m, utsaddr, &uts, sizeof(uts)); } static int SysSocket(struct Machine *m, i32 family, i32 type, i32 protocol) { struct Fd *fd; int lim, flags, fildes; flags = type & (SOCK_NONBLOCK_LINUX | SOCK_CLOEXEC_LINUX); type &= ~(SOCK_NONBLOCK_LINUX | SOCK_CLOEXEC_LINUX); if ((type = XlatSocketType(type)) == -1) return -1; if ((family = XlatSocketFamily(family)) == -1) return -1; if ((protocol = XlatSocketProtocol(protocol)) == -1) return -1; if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); if (flags) LOCK(&m->system->exec_lock); if ((fildes = VfsSocket(family, type, protocol)) != -1) { if (fildes >= lim) { VfsClose(fildes); fildes = emfile(); } else { FixupSock(fildes, flags); LOCK(&m->system->fds.lock); fd = AddFd(&m->system->fds, fildes, O_RDWR | (flags & SOCK_CLOEXEC_LINUX ? O_CLOEXEC : 0) | (flags & SOCK_NONBLOCK_LINUX ? O_NDELAY : 0)); fd->socktype = type; UNLOCK(&m->system->fds.lock); } } if (flags) UNLOCK(&m->system->exec_lock); return fildes; } static int SysSocketpair(struct Machine *m, i32 family, i32 type, i32 protocol, i64 pipefds_addr) { struct Fd *fd; u8 fds_linux[2][4]; int rc, lim, flags, sysflags, fds[2]; flags = type & (SOCK_NONBLOCK_LINUX | SOCK_CLOEXEC_LINUX); type &= ~(SOCK_NONBLOCK_LINUX | SOCK_CLOEXEC_LINUX); if ((type = XlatSocketType(type)) == -1) return -1; if ((family = XlatSocketFamily(family)) == -1) return -1; if ((protocol = XlatSocketProtocol(protocol)) == -1) return -1; if (!IsValidMemory(m, pipefds_addr, sizeof(fds_linux), PROT_WRITE)) return -1; if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); if (flags) LOCK(&m->system->exec_lock); if ((rc = VfsSocketpair(family, type, protocol, fds)) != -1) { if (fds[0] >= lim || fds[1] >= lim) { VfsClose(fds[0]); VfsClose(fds[1]); rc = emfile(); } else { FixupSock(fds[0], flags); FixupSock(fds[1], flags); LOCK(&m->system->fds.lock); sysflags = O_RDWR; if (flags & SOCK_CLOEXEC_LINUX) sysflags |= O_CLOEXEC; if (flags & SOCK_NONBLOCK_LINUX) sysflags |= O_NDELAY; unassert(fd = AddFd(&m->system->fds, fds[0], sysflags)); fd->socktype = type; unassert(fd = AddFd(&m->system->fds, fds[1], sysflags)); fd->socktype = type; UNLOCK(&m->system->fds.lock); Write32(fds_linux[0], fds[0]); Write32(fds_linux[1], fds[1]); unassert(!CopyToUserWrite(m, pipefds_addr, fds_linux, sizeof(fds_linux))); } } if (flags) UNLOCK(&m->system->exec_lock); return rc; } static u32 LoadAddrSize(struct Machine *m, i64 asa) { const u8 *p; if (asa && (p = (const u8 *)SchlepR(m, asa, 4))) { return Read32(p); } else { return 0; } } static int StoreAddrSize(struct Machine *m, i64 asa, socklen_t len) { u8 buf[4]; if (!asa) return 0; Write32(buf, len); return CopyToUserWrite(m, asa, buf, sizeof(buf)); } static int LoadSockaddr(struct Machine *m, i64 sockaddr_addr, u32 sockaddr_size, struct sockaddr_storage *out_sockaddr) { const struct sockaddr_linux *sockaddr_linux; if ((sockaddr_linux = (const struct sockaddr_linux *)SchlepR( m, sockaddr_addr, sockaddr_size))) { return XlatSockaddrToHost(out_sockaddr, sockaddr_linux, sockaddr_size); } else { return -1; } } static int CheckSockaddr(struct Machine *m, i64 sockaddr_addr, i64 sockaddr_size_addr) { const u8 *size; if (!sockaddr_size_addr) return 0; if (!(size = (const u8 *)SchlepRW(m, sockaddr_size_addr, 4))) return -1; if ((i32)Read32(size) < 0) return einval(); return 0; } static int StoreSockaddr(struct Machine *m, i64 sockaddr_addr, i64 sockaddr_size_addr, const struct sockaddr *sa, socklen_t salen) { int got; u32 avail; struct sockaddr_storage_linux ss; if (!sockaddr_addr) return 0; if (!sockaddr_size_addr) return 0; avail = LoadAddrSize(m, sockaddr_size_addr); if ((got = XlatSockaddrToLinux(&ss, sa, salen)) == -1) return -1; if (StoreAddrSize(m, sockaddr_size_addr, got) == -1) return -1; return CopyToUserWrite(m, sockaddr_addr, &ss, MIN(got, avail)); } static int SysSocketName(struct Machine *m, i32 fildes, i64 sockaddr_addr, i64 sockaddr_size_addr, int SocketName(int, struct sockaddr *, socklen_t *)) { int rc; socklen_t addrlen; struct sockaddr_storage addr; addrlen = sizeof(addr); rc = SocketName(fildes, (struct sockaddr *)&addr, &addrlen); if (rc != -1) { if (StoreSockaddr(m, sockaddr_addr, sockaddr_size_addr, (struct sockaddr *)&addr, addrlen) == -1) { rc = -1; } } return rc; } static int SysGetsockname(struct Machine *m, int fd, i64 aa, i64 asa) { return SysSocketName(m, fd, aa, asa, VfsGetsockname); } static int SysGetpeername(struct Machine *m, int fd, i64 aa, i64 asa) { return SysSocketName(m, fd, aa, asa, VfsGetpeername); } static int GetNoRestart(struct Machine *m, int fildes, bool *norestart) { struct Fd *fd; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { *norestart = fd->norestart; } UNLOCK(&m->system->fds.lock); if (!fd) return ebadf(); return 0; } static int SysAccept4(struct Machine *m, i32 fildes, i64 sockaddr_addr, i64 sockaddr_size_addr, i32 flags) { struct Fd *fd; socklen_t addrlen; bool restartable = false; int lim, newfd, socktype; struct sockaddr_storage addr; if (flags & ~(SOCK_CLOEXEC_LINUX | SOCK_NONBLOCK_LINUX)) return einval(); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { socktype = fd->socktype; restartable = !fd->norestart; } UNLOCK(&m->system->fds.lock); if (!fd) { return -1; } if (!socktype) { errno = ENOTSOCK; return -1; } if (socktype != SOCK_STREAM) { // POSIX.1 and Linux require EOPNOTSUPP when called on a file // descriptor that doesn't support accepting, i.e. SOCK_STREAM, // but FreeBSD incorrectly returns EINVAL. return eopnotsupp(); } if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); addrlen = sizeof(addr); INTERRUPTIBLE(restartable, newfd = VfsAccept(fildes, (struct sockaddr *)&addr, &addrlen)); if (newfd != -1) { if (newfd >= lim) { VfsClose(newfd); newfd = emfile(); } else { FixupSock(newfd, flags); LOCK(&m->system->fds.lock); if (!(fd = GetFd(&m->system->fds, fildes)) || !ForkFd(&m->system->fds, fd, newfd, O_RDWR | (flags & SOCK_CLOEXEC_LINUX ? O_CLOEXEC : 0) | (flags & SOCK_NONBLOCK_LINUX ? O_NDELAY : 0))) { VfsClose(newfd); newfd = -1; } UNLOCK(&m->system->fds.lock); if (newfd != -1) { StoreSockaddr(m, sockaddr_addr, sockaddr_size_addr, (struct sockaddr *)&addr, addrlen); } } } return newfd; } static int XlatSendFlags(int flags, int socktype) { int supported, hostflags; supported = MSG_OOB_LINUX | // MSG_DONTROUTE_LINUX | // MSG_NOSIGNAL_LINUX | // #ifdef MSG_EOR MSG_EOR_LINUX | #endif MSG_DONTWAIT_LINUX; if (flags & ~supported) { LOGF("unsupported %s flags %#x", "send", flags & ~supported); return einval(); } hostflags = 0; if (flags & MSG_OOB_LINUX) { if (socktype != SOCK_STREAM) { return eopnotsupp(); } hostflags |= MSG_OOB; } if (flags & MSG_DONTROUTE_LINUX) hostflags |= MSG_DONTROUTE; if (flags & MSG_DONTWAIT_LINUX) hostflags |= MSG_DONTWAIT; #ifdef MSG_EOR if (flags & MSG_EOR_LINUX) hostflags |= MSG_EOR; #endif return hostflags; } static int XlatRecvFlags(int flags) { int supported, hostflags; supported = MSG_OOB_LINUX | // MSG_PEEK_LINUX | // MSG_TRUNC_LINUX | // #ifndef DISABLE_NONPOSIX MSG_DONTWAIT_LINUX | // MSG_CMSG_CLOEXEC_LINUX | // #endif MSG_WAITALL_LINUX; if (flags & ~supported) { LOGF("unsupported %s flags %#x", "recv", flags & ~supported); return einval(); } hostflags = 0; if (flags & MSG_OOB_LINUX) hostflags |= MSG_OOB; if (flags & MSG_PEEK_LINUX) hostflags |= MSG_PEEK; if (flags & MSG_TRUNC_LINUX) hostflags |= MSG_TRUNC; if (flags & MSG_WAITALL_LINUX) hostflags |= MSG_WAITALL; if (flags & MSG_DONTWAIT_LINUX) hostflags |= MSG_DONTWAIT; #ifdef MSG_CMSG_CLOEXEC if (flags & MSG_CMSG_CLOEXEC_LINUX) hostflags |= MSG_CMSG_CLOEXEC; #endif return hostflags; } static int UnXlatMsgFlags(int flags) { int guestflags = 0; if (flags & MSG_OOB) { guestflags |= MSG_OOB_LINUX; flags &= ~MSG_OOB; } if (flags & MSG_PEEK) { guestflags |= MSG_PEEK_LINUX; flags &= ~MSG_PEEK; } if (flags & MSG_TRUNC) { guestflags |= MSG_TRUNC_LINUX; flags &= ~MSG_TRUNC; } if (flags & MSG_CTRUNC) { guestflags |= MSG_CTRUNC_LINUX; flags &= ~MSG_CTRUNC; } if (flags & MSG_WAITALL) { guestflags |= MSG_WAITALL_LINUX; flags &= ~MSG_WAITALL; } if (flags & MSG_DONTROUTE) { guestflags |= MSG_DONTROUTE_LINUX; flags &= ~MSG_DONTROUTE; } #ifdef MSG_EOR if (flags & MSG_EOR) { guestflags |= MSG_EOR_LINUX; flags &= ~MSG_EOR; } #endif #ifdef MSG_CMSG_CLOEXEC #ifndef DISABLE_NONPOSIX if (flags & MSG_CMSG_CLOEXEC) { guestflags |= MSG_CMSG_CLOEXEC_LINUX; flags &= ~MSG_CMSG_CLOEXEC; } #endif #endif if (flags) { LOGF("unsupported %s flags %#x", "msg", flags); } return guestflags; } // we need to handle any shutdown via pipeline explicitly // because blink always puts SIGPIPE in the SIG_IGN state static i64 HandleSigpipe(struct Machine *m, i64 rc, int flags) { #ifndef __linux // TODO(jart): Should we just intercept shutdown() state instead? if (rc == -1 && errno == ENOTCONN) { errno = EPIPE; } #endif if (rc == -1 && errno == EPIPE && !((flags & MSG_NOSIGNAL_LINUX) || (m->sigmask & ((u64)1 << (SIGPIPE_LINUX - 1))))) { LOCK(&m->system->sig_lock); switch (Read64(m->system->hands[SIGPIPE_LINUX - 1].handler)) { case SIG_IGN_LINUX: break; case SIG_DFL_LINUX: TerminateSignal(m, SIGPIPE_LINUX, 0); errno = EPIPE; break; default: m->interrupted = true; Put64(m->ax, -EPIPE_LINUX); DeliverSignal(m, SIGPIPE_LINUX, SI_KERNEL_LINUX); break; } UNLOCK(&m->system->sig_lock); } return rc; } static bool IsSockAddrEmpty(const struct sockaddr *sa) { return (sa->sa_family == AF_INET && !((const struct sockaddr_in *)sa)->sin_addr.s_addr) || (sa->sa_family == AF_INET6 && !Read64(((u8 *)&((struct sockaddr_in6 *)sa)->sin6_addr) + 0) && !Read64(((u8 *)&((struct sockaddr_in6 *)sa)->sin6_addr) + 8)); } // Operating systems like Linux let you sendmsg(buf, dest=0.0.0.0) where // the empty destination address implies the source address. Other OSes, // e.g. OpenBSD, do not implement this behavior. See also this Stack // Exchange question: https://unix.stackexchange.com/a/419881/451352 static void EnsureSockAddrHasDestination(struct Machine *m, int fildes, struct sockaddr_storage *ss) { #ifndef HAVE_SENDTO_ZERO struct Fd *fd; if (!IsSockAddrEmpty((const struct sockaddr *)ss)) return; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { if (ss->ss_family == fd->saddr.sa.sa_family) { if (ss->ss_family == AF_INET) { memcpy(&((struct sockaddr_in *)ss)->sin_addr, &fd->saddr.sin.sin_addr, sizeof(fd->saddr.sin.sin_addr)); } else if (ss->ss_family == AF_INET6) { memcpy(&((struct sockaddr_in6 *)ss)->sin6_addr, &fd->saddr.sin6.sin6_addr, sizeof(fd->saddr.sin6.sin6_addr)); } else { unassert(!"inconsistent code"); __builtin_unreachable(); } } else if (ss->ss_family == AF_INET) { // if we do socket() followed by connect(0.0.0.0) assume 127.0.0.1 ((struct sockaddr_in *)ss)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); } } UNLOCK(&m->system->fds.lock); #endif } static i64 SysSendto(struct Machine *m, // i32 fildes, // i64 bufaddr, // u64 buflen, // i32 flags, // i64 sockaddr_addr, // i32 sockaddr_size) { ssize_t rc; int socktype; struct Fd *fd; struct Iovs iv; bool norestart; struct msghdr msg; int len, hostflags; struct sockaddr_storage ss; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { socktype = fd->socktype; norestart = fd->norestart; } else { socktype = 0; norestart = false; } UNLOCK(&m->system->fds.lock); if (!fd) return ebadf(); if (sockaddr_size < 0) return einval(); if ((hostflags = XlatSendFlags(flags, socktype)) == -1) return -1; memset(&msg, 0, sizeof(msg)); // "If sendto() is used on a connection-mode socket, the arguments // dest_addr and addrlen are ignored." ──Quoth the Linux Programmer's // Manual § send(2). However FreeBSD behaves differently. if (socktype != SOCK_STREAM && sockaddr_size) { if ((len = LoadSockaddr(m, sockaddr_addr, sockaddr_size, &ss)) != -1) { msg.msg_namelen = len; EnsureSockAddrHasDestination(m, fildes, &ss); } else { return -1; } msg.msg_name = &ss; } InitIovs(&iv); if ((rc = AppendIovsReal(m, &iv, bufaddr, buflen, PROT_READ)) != -1) { msg.msg_iov = iv.p; msg.msg_iovlen = iv.i; INTERRUPTIBLE(!norestart, rc = VfsSendmsg(fildes, &msg, hostflags)); } FreeIovs(&iv); return HandleSigpipe(m, rc, flags); } static i64 SysRecvfrom(struct Machine *m, // i32 fildes, // i64 bufaddr, // u64 buflen, // i32 flags, // i64 sockaddr_addr, // i64 sockaddr_size_addr) { ssize_t rc; int hostflags; struct Iovs iv; struct msghdr msg; bool norestart = false; struct sockaddr_storage addr; if ((hostflags = XlatRecvFlags(flags)) == -1) return -1; if (GetNoRestart(m, fildes, &norestart) == -1) return -1; if (CheckSockaddr(m, sockaddr_addr, sockaddr_size_addr) == -1) return -1; memset(&msg, 0, sizeof(msg)); if (sockaddr_addr && sockaddr_size_addr) { msg.msg_name = &addr; msg.msg_namelen = sizeof(addr); } InitIovs(&iv); if ((rc = AppendIovsReal(m, &iv, bufaddr, buflen, PROT_WRITE)) != -1) { msg.msg_iov = iv.p; msg.msg_iovlen = iv.i; INTERRUPTIBLE(!norestart, rc = VfsRecvmsg(fildes, &msg, hostflags)); if (rc != -1) { StoreSockaddr(m, sockaddr_addr, sockaddr_size_addr, (struct sockaddr *)msg.msg_name, msg.msg_namelen); } } FreeIovs(&iv); return rc; } static i64 SysSendmsg(struct Machine *m, i32 fildes, i64 msgaddr, i32 flags) { i32 len; u64 iovlen; ssize_t rc; i64 iovaddr; int socktype; struct Fd *fd; struct Iovs iv; bool norestart; struct msghdr msg; struct sockaddr_storage ss; const struct msghdr_linux *gm; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { socktype = fd->socktype; norestart = fd->norestart; } else { socktype = 0; norestart = false; } UNLOCK(&m->system->fds.lock); if (!fd) return ebadf(); if ((flags = XlatSendFlags(flags, socktype)) == -1) return -1; if (!(gm = (const struct msghdr_linux *)SchlepR(m, msgaddr, sizeof(*gm)))) { return -1; } memset(&msg, 0, sizeof(msg)); if (socktype != SOCK_STREAM && (len = Read32(gm->namelen)) > 0) { if ((len = LoadSockaddr(m, Read64(gm->name), len, &ss)) == -1) { return -1; } EnsureSockAddrHasDestination(m, fildes, &ss); msg.msg_name = &ss; msg.msg_namelen = len; } #ifndef DISABLE_ANCILLARY if (SendAncillary(m, &msg, gm) == -1) { return -1; } #else if (Read64(gm->controllen)) { LOGF("ancillary support disabled"); return einval(); } #endif iovaddr = Read64(gm->iov); iovlen = Read64(gm->iovlen); if (!iovlen || iovlen > IOV_MAX_LINUX) { errno = EMSGSIZE; return -1; } InitIovs(&iv); if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen, PROT_READ)) != -1) { msg.msg_iov = iv.p; msg.msg_iovlen = iv.i; INTERRUPTIBLE(!norestart, rc = VfsSendmsg(fildes, &msg, flags)); } FreeIovs(&iv); return HandleSigpipe(m, rc, flags); } static i64 SysRecvmsg(struct Machine *m, i32 fildes, i64 msgaddr, i32 flags) { ssize_t rc; u64 iovlen; i64 iovaddr; struct Iovs iv; struct msghdr msg; bool norestart = false; struct msghdr_linux gm; struct sockaddr_storage addr; if ((flags = XlatRecvFlags(flags)) == -1) return -1; if (GetNoRestart(m, fildes, &norestart) == -1) return -1; if (CopyFromUserRead(m, &gm, msgaddr, sizeof(gm)) == -1) return -1; memset(&msg, 0, sizeof(msg)); iovaddr = Read64(gm.iov); iovlen = Read64(gm.iovlen); if (!iovlen || iovlen > IOV_MAX_LINUX) { errno = EMSGSIZE; return -1; } if (Read64(gm.controllen)) { #ifndef DISABLE_ANCILLARY msg.msg_control = AddToFreeList(m, calloc(1, kMaxAncillary)); msg.msg_controllen = kMaxAncillary; #else LOGF("ancillary support disabled"); return einval(); #endif } InitIovs(&iv); if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen, PROT_WRITE)) != -1) { msg.msg_iov = iv.p; msg.msg_iovlen = iv.i; if (Read64(gm.name)) { memset(&addr, 0, sizeof(addr)); msg.msg_name = &addr; msg.msg_namelen = sizeof(addr); } INTERRUPTIBLE(!norestart, rc = VfsRecvmsg(fildes, &msg, flags)); if (rc != -1) { Write32(gm.flags, UnXlatMsgFlags(msg.msg_flags)); unassert(CopyToUserWrite(m, msgaddr, &gm, sizeof(gm)) != -1); #ifndef DISABLE_ANCILLARY if (ReceiveAncillary(m, &gm, &msg, flags) == -1) { return -1; } #endif if (Read64(gm.name)) { StoreSockaddr(m, Read64(gm.name), msgaddr + offsetof(struct msghdr_linux, namelen), (struct sockaddr *)&addr, msg.msg_namelen); } } } FreeIovs(&iv); return rc; } static i64 SysSendmmsg(struct Machine *m, i32 fildes, i64 msgsaddr, u32 msgcnt, i32 flags) { u32 i; i64 rc; u8 word[4]; const struct mmsghdr_linux *msgs; if (!(msgs = (const struct mmsghdr_linux *)SchlepRW( m, msgsaddr, msgcnt * sizeof(*msgs)))) { return -1; } for (i = 0; i < msgcnt; ++i) { if ((rc = SysSendmsg(m, fildes, msgsaddr + i * sizeof(*msgs), flags)) != -1) { Write32(word, rc); unassert(CopyToUserWrite(m, msgsaddr + i * sizeof(*msgs) + offsetof(struct mmsghdr_linux, len), word, 4) != -1); } else { if (!i) return -1; if (errno == EINTR || errno == EWOULDBLOCK) break; LOGF("%s raised %s after doing work", "sendmmsg", DescribeHostErrno(errno)); break; } } return i; } static i64 SysRecvmmsg(struct Machine *m, i32 fildes, i64 msgsaddr, u32 msgcnt, i32 flags, i64 timeoutaddr) { u32 i; i64 rc; u8 word[4]; i32 flags2; struct timespec_linux gt; const struct mmsghdr_linux *msgs; struct timespec ts, now, remain, deadline = {0}; if (!(msgs = (const struct mmsghdr_linux *)SchlepRW( m, msgsaddr, msgcnt * sizeof(*msgs)))) { return -1; } if (timeoutaddr) { if (LoadTimespecR(m, timeoutaddr, &ts) == -1) return -1; deadline = AddTime(GetTime(), ts); } for (i = 0; i < msgcnt; ++i) { flags2 = flags & ~MSG_WAITFORONE_LINUX; if ((flags & MSG_WAITFORONE_LINUX) && i) { flags2 |= MSG_DONTWAIT_LINUX; } if ((rc = SysRecvmsg(m, fildes, msgsaddr + i * sizeof(*msgs), flags2)) != -1) { Write32(word, rc); unassert(CopyToUserWrite(m, msgsaddr + i * sizeof(*msgs) + offsetof(struct mmsghdr_linux, len), word, 4) != -1); } else { if (!i) return -1; if (errno == EAGAIN || errno == EWOULDBLOCK) break; // If an error occurs after at least one message has been // received, the call succeeds, and returns the number of messages // received. The error code is expected to be returned on a // subsequent call to recvmmsg(). In the current implementation, // however, the error code can be overwritten in the meantime by // an unrelated network event on a socket, for example an incoming // ICMP packet. ──Quoth the Linux Programmer's Manual § recvmmsg() LOGF("%s raised %s after doing work", "recvmmsg", DescribeHostErrno(errno)); break; } // The timeout argument does not work as intended. The timeout is // checked only after the receipt of each datagram, so that if up to // vlen-1 datagrams are received before the timeout expires, but // then no further datagrams are received, the call will block // forever. ──Quoth the Linux Programmer's Manual § recvmmsg() if (timeoutaddr && CompareTime(GetTime(), deadline) >= 0) { break; } } if (timeoutaddr) { now = GetTime(); if (CompareTime(now, deadline) >= 0) { remain = GetZeroTime(); } else { remain = SubtractTime(deadline, now); } Write64(gt.sec, remain.tv_sec); Write64(gt.nsec, remain.tv_nsec); CopyToUserWrite(m, timeoutaddr, >, sizeof(gt)); } return i; } static int SysConnectBind(struct Machine *m, i32 fildes, i64 sockaddr_addr, u32 sockaddr_size, int impl(int, const struct sockaddr *, socklen_t)) { int rc, len; struct Fd *fd; socklen_t addrlen; bool norestart = false; struct sockaddr_storage addr; if (GetNoRestart(m, fildes, &norestart) == -1) return -1; if ((len = LoadSockaddr(m, sockaddr_addr, sockaddr_size, &addr)) != -1) { addrlen = len; if (impl == VfsConnect) { EnsureSockAddrHasDestination(m, fildes, &addr); } } else { return -1; } INTERRUPTIBLE(!norestart, (rc = impl(fildes, (const struct sockaddr *)&addr, addrlen))); if (rc != -1 && impl == VfsBind) { LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { memcpy(&fd->saddr, &addr, sizeof(fd->saddr)); } UNLOCK(&m->system->fds.lock); } return rc; } static int SysBind(struct Machine *m, int fd, i64 aa, u32 as) { return SysConnectBind(m, fd, aa, as, VfsBind); } static int SysConnect(struct Machine *m, int fd, i64 aa, u32 as) { return SysConnectBind(m, fd, aa, as, VfsConnect); } static int UnXlatSocketType(int x) { if (x == SOCK_STREAM) return SOCK_STREAM_LINUX; if (x == SOCK_DGRAM) return SOCK_DGRAM_LINUX; LOGF("%s %d not supported yet", "socket type", x); return einval(); } static int GetsockoptInt32(struct Machine *m, i32 fd, int level, int optname, i64 optvaladdr, i64 optvalsizeaddr, int xlat(int)) { u8 *psize; u8 gval[4]; int rc, val; socklen_t optvalsize; u32 optvalsize_linux; if (!(psize = (u8 *)SchlepRW(m, optvalsizeaddr, 4))) return -1; optvalsize_linux = Read32(psize); if (!IsValidMemory(m, optvaladdr, optvalsize_linux, PROT_WRITE)) return -1; optvalsize = sizeof(val); if ((rc = VfsGetsockopt(fd, level, optname, &val, &optvalsize)) != -1) { if ((val = xlat(val)) == -1) return -1; Write32(gval, val); CopyToUserWrite(m, optvaladdr, &gval, MIN(sizeof(gval), optvalsize_linux)); Write32(psize, sizeof(gval)); } return rc; } static int SetsockoptLinger(struct Machine *m, i32 fildes, i64 optvaladdr, u32 optvalsize) { struct linger hl; const struct linger_linux *gl; if (optvalsize < sizeof(*gl)) return einval(); if (!(gl = (const struct linger_linux *)SchlepR(m, optvaladdr, sizeof(*gl)))) { return -1; } hl.l_onoff = (i32)Read32(gl->onoff); hl.l_linger = (i32)Read32(gl->linger); return VfsSetsockopt(fildes, SOL_SOCKET, SO_LINGER_, &hl, sizeof(hl)); } static int GetsockoptLinger(struct Machine *m, i32 fd, i64 optvaladdr, i64 optvalsizeaddr) { int rc; u8 *psize; struct linger hl; socklen_t optvalsize; u32 optvalsize_linux; struct linger_linux gl; if (!(psize = (u8 *)SchlepRW(m, optvalsizeaddr, 4))) return -1; optvalsize_linux = Read32(psize); if (!IsValidMemory(m, optvaladdr, optvalsize_linux, PROT_WRITE)) return -1; optvalsize = sizeof(hl); if ((rc = VfsGetsockopt(fd, SOL_SOCKET, SO_LINGER_, &hl, &optvalsize)) != -1) { Write32(gl.onoff, hl.l_onoff); Write32(gl.linger, hl.l_linger); CopyToUserWrite(m, optvaladdr, &gl, MIN(sizeof(gl), optvalsize_linux)); Write32(psize, sizeof(gl)); } return rc; } static int SysSetsockopt(struct Machine *m, i32 fildes, i32 level, i32 optname, i64 optvaladdr, u32 optvalsize) { int rc; void *optval; struct Fd *fd; int syslevel, sysoptname; switch (level) { case SOL_SOCKET_LINUX: switch (optname) { case SO_LINGER_LINUX: return SetsockoptLinger(m, fildes, optvaladdr, optvalsize); default: break; } break; default: break; } if (optvalsize > 256) return einval(); if (XlatSocketLevel(level, &syslevel) == -1) return -1; if ((sysoptname = XlatSocketOptname(level, optname)) == -1) return -1; if (!(optval = SchlepR(m, optvaladdr, optvalsize))) return -1; rc = VfsSetsockopt(fildes, syslevel, sysoptname, optval, optvalsize); if (rc != -1 && // level == SOL_SOCKET_LINUX && // optname == SO_RCVTIMEO_LINUX && // optvalsize >= 4) { LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { fd->norestart = !!Read32((u8 *)optval); } UNLOCK(&m->system->fds.lock); } return rc; } static int SysGetsockopt(struct Machine *m, i32 fildes, i32 level, i32 optname, i64 optvaladdr, i64 optvalsizeaddr) { int rc; void *optval; socklen_t optvalsize; u8 optvalsize_linux[4]; int syslevel, sysoptname; switch (level) { case SOL_SOCKET_LINUX: switch (optname) { case SO_TYPE_LINUX: return GetsockoptInt32(m, fildes, SOL_SOCKET, SO_TYPE, optvaladdr, optvalsizeaddr, UnXlatSocketType); case SO_ERROR_LINUX: return GetsockoptInt32(m, fildes, SOL_SOCKET, SO_ERROR, optvaladdr, optvalsizeaddr, XlatErrno); case SO_LINGER_LINUX: return GetsockoptLinger(m, fildes, optvaladdr, optvalsizeaddr); default: break; } break; default: break; } if (XlatSocketLevel(level, &syslevel) == -1) return -1; if ((sysoptname = XlatSocketOptname(level, optname)) == -1) return -1; if (CopyFromUserRead(m, optvalsize_linux, optvalsizeaddr, sizeof(optvalsize_linux)) == -1) { return -1; } optvalsize = Read32(optvalsize_linux); if (optvalsize > 256) return einval(); if (!(optval = AddToFreeList(m, calloc(1, optvalsize)))) return -1; rc = VfsGetsockopt(fildes, syslevel, sysoptname, optval, &optvalsize); Write32(optvalsize_linux, optvalsize); CopyToUserWrite(m, optvaladdr, optval, optvalsize); CopyToUserWrite(m, optvalsizeaddr, optvalsize_linux, sizeof(optvalsize_linux)); return rc; } static i64 SysRead(struct Machine *m, i32 fildes, i64 addr, u64 size) { i64 rc; int oflags; struct Fd *fd; struct Iovs iv; ssize_t (*readv_impl)(int, const struct iovec *, int); if (size > NUMERIC_MAX(size_t)) return eoverflow(); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { unassert(fd->cb); unassert(readv_impl = fd->cb->readv); oflags = fd->oflags; } else { readv_impl = 0; oflags = 0; } UNLOCK(&m->system->fds.lock); if (!fd) return -1; if ((oflags & O_ACCMODE) == O_WRONLY) return ebadf(); if (size) { InitIovs(&iv); if ((rc = AppendIovsReal(m, &iv, addr, size, PROT_WRITE)) != -1) { RESTARTABLE(rc = readv_impl(fildes, iv.p, iv.i)); if (rc != -1) SetWriteAddr(m, addr, rc); } FreeIovs(&iv); } else { rc = 0; } return rc; } static i64 SysWrite(struct Machine *m, i32 fildes, i64 addr, u64 size) { i64 rc; int oflags; struct Fd *fd; struct Iovs iv; ssize_t (*writev_impl)(int, const struct iovec *, int); if (size > NUMERIC_MAX(size_t)) return eoverflow(); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { unassert(fd->cb); unassert(writev_impl = fd->cb->writev); oflags = fd->oflags; } else { writev_impl = 0; oflags = 0; } UNLOCK(&m->system->fds.lock); if (!fd) return -1; if ((oflags & O_ACCMODE) == O_RDONLY) return ebadf(); if (size) { InitIovs(&iv); if ((rc = AppendIovsReal(m, &iv, addr, size, PROT_READ)) != -1) { RESTARTABLE(rc = writev_impl(fildes, iv.p, iv.i)); if (rc != -1) SetReadAddr(m, addr, rc); } FreeIovs(&iv); } else { rc = 0; } return HandleSigpipe(m, rc, 0); } // FreeBSD doesn't do access mode check on read/write to pipes. // Cygwin generally doesn't do access checks or is inconsistent. static long CheckFdAccess(struct Machine *m, i32 fildes, bool writable, int errno_if_check_fails) { int oflags; struct Fd *fd; LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { oflags = fd->oflags; } else { oflags = 0; } UNLOCK(&m->system->fds.lock); if (!fd) return -1; if ((writable && ((oflags & O_ACCMODE) == O_RDONLY)) || (!writable && ((oflags & O_ACCMODE) == O_WRONLY))) { errno = errno_if_check_fails; return -1; } return 0; } static i64 SysPread(struct Machine *m, i32 fildes, i64 addr, u64 size, u64 offset) { ssize_t rc; struct Iovs iv; if (size > NUMERIC_MAX(size_t)) return eoverflow(); if (CheckFdAccess(m, fildes, false, EBADF) == -1) return -1; if (size) { InitIovs(&iv); if ((rc = AppendIovsReal(m, &iv, addr, size, PROT_WRITE)) != -1) { RESTARTABLE(rc = VfsPreadv(fildes, iv.p, iv.i, offset)); if (rc != -1) SetWriteAddr(m, addr, rc); } FreeIovs(&iv); } else { rc = 0; } return rc; } static i64 SysPwrite(struct Machine *m, i32 fildes, i64 addr, u64 size, u64 offset) { ssize_t rc; struct Iovs iv; if (size > NUMERIC_MAX(size_t)) return eoverflow(); if (CheckFdAccess(m, fildes, true, EBADF) == -1) return -1; if (size) { InitIovs(&iv); if ((rc = AppendIovsReal(m, &iv, addr, size, PROT_READ)) != -1) { RESTARTABLE(rc = VfsPwritev(fildes, iv.p, iv.i, offset)); if (rc != -1) SetReadAddr(m, addr, rc); } FreeIovs(&iv); } else { rc = 0; } return rc; } static i64 SysPreadv2(struct Machine *m, i32 fildes, i64 iovaddr, u32 iovlen, i64 offset, i32 flags) { i64 rc; int oflags; struct Fd *fd; struct Iovs iv; ssize_t (*readv_impl)(int, const struct iovec *, int); if (flags) { LOGF("%s flags not supported yet: %#" PRIx32, "preadv2", flags); return einval(); } if (iovlen > IOV_MAX_LINUX) return einval(); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { unassert(fd->cb); unassert(readv_impl = fd->cb->readv); oflags = fd->oflags; } else { readv_impl = 0; oflags = 0; } UNLOCK(&m->system->fds.lock); if (!fd) return -1; if ((oflags & O_ACCMODE) == O_WRONLY) return ebadf(); if (iovlen) { InitIovs(&iv); if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen, PROT_WRITE)) != -1) { if (iv.i) { if (offset == -1) { RESTARTABLE(rc = readv_impl(fildes, iv.p, iv.i)); } else if (offset < 0) { return einval(); } else if (offset > NUMERIC_MAX(off_t)) { return eoverflow(); } else { RESTARTABLE(rc = VfsPreadv(fildes, iv.p, iv.i, offset)); } } else { rc = 0; } } FreeIovs(&iv); } else { rc = 0; } return rc; } static i64 SysPwritev2(struct Machine *m, i32 fildes, i64 iovaddr, u32 iovlen, i64 offset, i32 flags) { i64 rc; int oflags; struct Fd *fd; struct Iovs iv; ssize_t (*writev_impl)(int, const struct iovec *, int); if (flags) { LOGF("%s flags not supported yet: %#" PRIx32, "pwritev2", flags); return einval(); } if (iovlen > IOV_MAX_LINUX) return einval(); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { unassert(fd->cb); unassert(writev_impl = fd->cb->writev); oflags = fd->oflags; } else { writev_impl = 0; oflags = 0; } UNLOCK(&m->system->fds.lock); if (!fd) return -1; if ((oflags & O_ACCMODE) == O_RDONLY) return ebadf(); if (iovlen) { InitIovs(&iv); if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen, PROT_READ)) != -1) { if (iv.i) { if (offset == -1) { RESTARTABLE(rc = writev_impl(fildes, iv.p, iv.i)); rc = HandleSigpipe(m, rc, 0); } else if (offset < 0) { return einval(); } else if (offset > NUMERIC_MAX(off_t)) { return eoverflow(); } else { RESTARTABLE(rc = VfsPwritev(fildes, iv.p, iv.i, offset)); } } else { rc = 0; } } FreeIovs(&iv); } else { rc = 0; } return rc; } static i64 SysReadv(struct Machine *m, i32 fildes, i64 iovaddr, u32 iovlen) { return SysPreadv2(m, fildes, iovaddr, iovlen, -1, 0); } static i64 SysWritev(struct Machine *m, i32 fildes, i64 iovaddr, u32 iovlen) { return SysPwritev2(m, fildes, iovaddr, iovlen, -1, 0); } static i64 SysPreadv(struct Machine *m, i32 fildes, i64 iovaddr, u32 iovlen, i64 offset) { if (offset < 0) return einval(); return SysPreadv2(m, fildes, iovaddr, iovlen, offset, 0); } static i64 SysPwritev(struct Machine *m, i32 fildes, i64 iovaddr, u32 iovlen, i64 offset) { if (offset < 0) return einval(); return SysPwritev2(m, fildes, iovaddr, iovlen, offset, 0); } static i64 SysSendfile(struct Machine *m, i32 out_fd, i32 in_fd, i64 offsetaddr, u64 count) { u64 toto, offset; ssize_t got, wrote; u8 *buf, *offsetp = 0; size_t chunk, maxchunk = 16384; if (CheckFdAccess(m, out_fd, true, EBADF) == -1) return -1; if (CheckFdAccess(m, in_fd, false, EBADF) == -1) return -1; if (offsetaddr && !(offsetp = (u8 *)SchlepRW(m, offsetaddr, 8))) return -1; if (!(buf = (u8 *)AddToFreeList(m, malloc(maxchunk)))) return -1; if (offsetp) { offset = Read64(offsetp); if ((i64)offset < 0) return einval(); if (Read64(offsetp) + count < count || Read64(offsetp) + count > NUMERIC_MAX(off_t)) { return eoverflow(); } } for (toto = 0; toto < count;) { chunk = MIN(count - toto, maxchunk); if (offsetp) { got = VfsPread(in_fd, buf, chunk, offset + toto); } else { got = VfsRead(in_fd, buf, chunk); } if (got == -1) goto OnFailure; if (offsetp) Write64(offsetp, offset + toto + got); if (got == 0) break; while (got > 0) { if ((wrote = VfsWrite(out_fd, buf, got)) == -1) goto OnFailure; toto += wrote; got -= wrote; } } return toto; OnFailure: if (toto) { LOGF("sendfile() partial failure: %s", DescribeHostErrno(errno)); return toto; } else { return -1; } } static int UnXlatDt(int x) { #ifndef DT_UNKNOWN return DT_UNKNOWN_LINUX; #else switch (x) { XLAT(DT_UNKNOWN, DT_UNKNOWN_LINUX); XLAT(DT_FIFO, DT_FIFO_LINUX); XLAT(DT_CHR, DT_CHR_LINUX); XLAT(DT_DIR, DT_DIR_LINUX); XLAT(DT_BLK, DT_BLK_LINUX); XLAT(DT_REG, DT_REG_LINUX); XLAT(DT_LNK, DT_LNK_LINUX); XLAT(DT_SOCK, DT_SOCK_LINUX); default: __builtin_unreachable(); } #endif } static i64 Getdents(struct Machine *m, i32 fildes, i64 addr, i64 size, struct Fd *fd) { i64 i; int type; off_t off; int reclen; size_t len; struct stat st; struct dirent *ent; struct dirent_linux rec; if (size < sizeof(rec) - sizeof(rec.name)) return einval(); if ((fd->oflags & O_DIRECTORY) != O_DIRECTORY) return enotdir(); if (!IsValidMemory(m, addr, size, PROT_WRITE)) return -1; if (VfsFstat(fildes, &st) || !st.st_nlink) return enoent(); if (!fd->dirstream && !(fd->dirstream = VfsOpendir(fd->fildes))) { return -1; } for (i = 0; i + sizeof(rec) <= size; i += reclen) { // telldir() can actually return negative on ARM/MIPS/i386 #ifdef HAVE_SEEKDIR long tell; errno = 0; tell = VfsTelldir(fd->dirstream); unassert(tell != -1 || errno == 0); off = tell; #else off = -1; #endif if (!(ent = VfsReaddir(fd->dirstream))) break; len = strlen(ent->d_name); if (len + 1 > sizeof(rec.name)) { LOGF("ignoring %zu byte d_name: %s", len, ent->d_name); reclen = 0; continue; } #ifdef DT_UNKNOWN type = UnXlatDt(ent->d_type); #else struct stat st; if (fstatat(fd->fildes, ent->d_name, &st, AT_SYMLINK_NOFOLLOW) == -1) { LOGF("getdents() fstatat(%d, %s) failed: %s", fd->fildes, ent->d_name, DescribeHostErrno(errno)); type = DT_UNKNOWN_LINUX; } else { if (S_ISDIR(st.st_mode)) { type = DT_DIR_LINUX; } else if (S_ISCHR(st.st_mode)) { type = DT_CHR_LINUX; } else if (S_ISBLK(st.st_mode)) { type = DT_BLK_LINUX; } else if (S_ISFIFO(st.st_mode)) { type = DT_FIFO_LINUX; } else if (S_ISLNK(st.st_mode)) { type = DT_LNK_LINUX; } else if (S_ISSOCK(st.st_mode)) { type = DT_SOCK_LINUX; } else if (S_ISREG(st.st_mode)) { type = DT_REG_LINUX; } else { LOGF("unknown st_mode %d", st.st_mode); type = DT_UNKNOWN_LINUX; } } #endif reclen = ROUNDUP(8 + 8 + 2 + 1 + len + 1, 8); memset(&rec, 0, sizeof(rec)); Write64(rec.ino, ent->d_ino); Write64(rec.off, off); Write16(rec.reclen, reclen); Write8(rec.type, type); strcpy(rec.name, ent->d_name); CopyToUserWrite(m, addr + i, &rec, reclen); } return i; } static i64 SysGetdents(struct Machine *m, i32 fildes, i64 addr, i64 size) { i64 rc; struct Fd *fd; if (!(fd = GetAndLockFd(m, fildes))) return -1; rc = Getdents(m, fildes, addr, size, fd); UnlockFd(fd); return rc; } static int SysSetTidAddress(struct Machine *m, i64 ctid) { m->ctid = ctid; return m->tid; } static int SysFadvise(struct Machine *m, u32 fd, u64 offset, u64 len, i32 advice) { return 0; } static i64 SysLseek(struct Machine *m, i32 fildes, i64 offset, int whence) { i64 rc; struct Fd *fd; if (offset > NUMERIC_MAX(off_t)) return eoverflow(); if (offset < -NUMERIC_MAX(off_t) - 1) return eoverflow(); if (!(fd = GetAndLockFd(m, fildes))) return -1; if (!fd->dirstream) { rc = VfsSeek(fd->fildes, offset, XlatWhence(whence)); } else if (whence == SEEK_SET_LINUX) { if (!offset) { VfsRewinddir(fd->dirstream); rc = 0; } else { #ifdef HAVE_SEEKDIR VfsSeekdir(fd->dirstream, offset); rc = 0; #else LOGF("host platform doesn't support seekdir()"); rc = enotsup(); #endif } } else { rc = einval(); } UnlockFd(fd); return rc; } static i64 SysFtruncate(struct Machine *m, i32 fildes, i64 length) { i64 rc; if (length < 0) return einval(); if (length > NUMERIC_MAX(off_t)) return eoverflow(); if (CheckFdAccess(m, fildes, true, EINVAL) == -1) return -1; RESTARTABLE(rc = VfsFtruncate(fildes, length)); return rc; } static int XlatFaccessatFlags(int x) { int res = 0; if (x & AT_EACCESS_LINUX) { #if !defined(__EMSCRIPTEN__) && !defined(__CYGWIN__) res |= AT_EACCESS; #endif x &= ~AT_EACCESS_LINUX; } if (x & AT_SYMLINK_FOLLOW_LINUX) { x &= ~AT_SYMLINK_FOLLOW_LINUX; // default behavior } if (x & AT_SYMLINK_NOFOLLOW_LINUX) { res |= AT_SYMLINK_NOFOLLOW; x &= ~AT_SYMLINK_NOFOLLOW_LINUX; } if (x) { LOGF("%s() flags %d not supported", "faccessat", x); return -1; } return res; } static int SysFaccessat2(struct Machine *m, i32 dirfd, i64 path, i32 mode, i32 flags) { return VfsAccess(GetDirFildes(dirfd), LoadStr(m, path), XlatAccess(mode), XlatFaccessatFlags(flags)); } static int SysFaccessat(struct Machine *m, i32 dirfd, i64 path, i32 mode) { return SysFaccessat2(m, dirfd, path, mode, 0); } static int SysFstat(struct Machine *m, i32 fd, i64 staddr) { int rc; struct stat st; struct stat_linux gst; if ((rc = VfsFstat(fd, &st)) != -1) { XlatStatToLinux(&gst, &st); if (CopyToUserWrite(m, staddr, &gst, sizeof(gst)) == -1) rc = -1; } return rc; } static int XlatFstatatFlags(int x) { int res = 0; if (x & AT_SYMLINK_FOLLOW_LINUX) { x &= ~AT_SYMLINK_FOLLOW_LINUX; // default behavior } if (x & AT_SYMLINK_NOFOLLOW_LINUX) { res |= AT_SYMLINK_NOFOLLOW; x &= ~AT_SYMLINK_NOFOLLOW_LINUX; } #ifndef DISABLE_NONPOSIX if (x & AT_NO_AUTOMOUNT_LINUX) { #if defined(AT_NO_AUTOMOUNT) && defined(DISABLE_VFS) res |= AT_NO_AUTOMOUNT; #endif x &= ~AT_NO_AUTOMOUNT_LINUX; } #endif if (x) { LOGF("%s() flags %d not supported", "fstatat", x); return -1; } return res; } static int SysFstatat(struct Machine *m, i32 dirfd, i64 pathaddr, i64 staddr, i32 flags) { int rc; struct stat st; const char *path; struct stat_linux gst; if (!(path = LoadStr(m, pathaddr))) return -1; #ifndef DISABLE_NONPOSIX if (flags & AT_EMPTY_PATH_LINUX) { flags &= ~AT_EMPTY_PATH_LINUX; if (!*path) { if (flags) { LOGF("%s() flags %d not supported", "fstatat(AT_EMPTY_PATH)", flags); return -1; } return SysFstat(m, dirfd, staddr); } } #endif if ((rc = VfsStat(GetDirFildes(dirfd), path, &st, XlatFstatatFlags(flags))) != -1) { XlatStatToLinux(&gst, &st); if (CopyToUserWrite(m, staddr, &gst, sizeof(gst)) == -1) rc = -1; } return rc; } static int XlatFchownatFlags(int x) { int res = 0; if (x & AT_SYMLINK_FOLLOW_LINUX) { x &= ~AT_SYMLINK_FOLLOW_LINUX; // default behavior } if (x & AT_SYMLINK_NOFOLLOW_LINUX) { res |= AT_SYMLINK_NOFOLLOW; x &= ~AT_SYMLINK_NOFOLLOW_LINUX; } #ifdef AT_EMPTY_PATH #ifndef DISABLE_NONPOSIX if (x & AT_EMPTY_PATH_LINUX) { res |= AT_EMPTY_PATH; x &= ~AT_EMPTY_PATH_LINUX; } #endif #endif if (x) { LOGF("%s() flags %#x not supported", "fchownat", x); return -1; } return res; } static int SysFchown(struct Machine *m, i32 fildes, u32 uid, u32 gid) { return VfsFchown(fildes, uid, gid); } static int SysFchownat(struct Machine *m, i32 dirfd, i64 pathaddr, u32 uid, u32 gid, i32 flags) { const char *path; if (!(path = LoadStr(m, pathaddr))) return -1; #ifndef DISABLE_NONPOSIX if (flags & AT_EMPTY_PATH_LINUX) { flags &= AT_EMPTY_PATH_LINUX; if (!*path) { if (flags) { LOGF("%s() flags %d not supported", "fchownat(AT_EMPTY_PATH)", flags); return -1; } return SysFchown(m, dirfd, uid, gid); } } #endif return VfsChown(GetDirFildes(dirfd), path, uid, gid, XlatFchownatFlags(flags)); } static int SysChown(struct Machine *m, i64 pathaddr, u32 uid, u32 gid) { return SysFchownat(m, AT_FDCWD_LINUX, pathaddr, uid, gid, 0); } static int SysLchown(struct Machine *m, i64 pathaddr, u32 uid, u32 gid) { return SysFchownat(m, AT_FDCWD_LINUX, pathaddr, uid, gid, AT_SYMLINK_NOFOLLOW_LINUX); } #if !defined(DISABLE_OVERLAYS) static int SysChroot(struct Machine *m, i64 path) { return SetOverlays(LoadStr(m, path), false); } #elif !defined(DISABLE_VFS) static int SysChroot(struct Machine *m, i64 path) { return VfsChroot(LoadStr(m, path)); } #endif #ifndef DISABLE_VFS static int SysMount(struct Machine *m, i64 source, i64 target, i64 fstype, i64 mountflags, i64 data) { // No xlat, the VFS system will handle raw Linux options. return VfsMount(LoadStr(m, source), LoadStr(m, target), LoadStr(m, fstype), mountflags, (void *)(uintptr_t)data); } #endif static int SysSync(struct Machine *m) { #ifdef HAVE_SYNC sync(); return 0; #else // sync() is an xsi extension to posix. not having sync() puts us in a // difficult position because the libc wrapper for sync() can't report // errors. the best we can do is sync what we know and report an error struct Dll *e; int *p2, *p = 0; size_t i, n = 0; LOGF("host platform doesn't support sync()"); LOCK(&m->system->fds.lock); for (e = dll_first(m->system->fds.list); e; e = dll_next(m->system->fds.list, e)) { if ((p2 = (int *)realloc(p, (n + 1) * sizeof(*p)))) { (p = p2)[n++] = FD_CONTAINER(e)->fildes; } else { break; } } UNLOCK(&m->system->fds.lock); for (i = 0; i < n; ++i) { VfsFsync(p[i]); } free(p); return enosys(); #endif } static int CheckSyncable(int fildes) { #ifndef __linux // FreeBSD doesn't return EINVAL like Linux does when trying to // synchronize character devices, e.g. /dev/null. An unresolved // question though is if FreeBSD actually does something here. struct stat st; if (!VfsFstat(fildes, &st) && // (S_ISCHR(st.st_mode) || // S_ISFIFO(st.st_mode) || // S_ISLNK(st.st_mode) || // S_ISSOCK(st.st_mode))) { return einval(); } #endif return 0; } static int SysFsync(struct Machine *m, i32 fildes) { if (CheckSyncable(fildes) == -1) return -1; #ifdef F_FULLSYNC int rc; // MacOS fsync() provides weaker guarantees than Linux fsync() // https://mjtsai.com/blog/2022/02/17/apple-ssd-benchmarks-and-f_fullsync/ if ((rc = VfsFcntl(fildes, F_FULLFSYNC, 0))) { // If the FULLFSYNC failed, fall back to attempting an fsync(). It // shouldn't be possible for fullfsync to fail on the local file // system (on OSX), so failure indicates that FULLFSYNC isn't // supported for this file system. So, attempt an fsync and (for // now) ignore the overhead of a superfluous fcntl call. It'd be // better to detect fullfsync support once and avoid the fcntl call // every time sync is called. ──Quoth SQLite (os_unix.c) It's also // possible for F_FULLFSYNC to fail on Cosmopolitan Libc when our // binary isn't running on MacOS. rc = VfsFsync(fildes); } return rc; #else return VfsFsync(fildes); #endif } static int SysFdatasync(struct Machine *m, i32 fildes) { if (CheckSyncable(fildes) == -1) return -1; #ifdef F_FULLSYNC int rc; if ((rc = VfsFcntl(fildes, F_FULLFSYNC, 0))) { rc = VfsFsync(fildes); } return rc; #elif defined(__APPLE__) // fdatasync() on HFS+ doesn't yet flush the file size if it changed // correctly so currently we default to the macro that redefines // fdatasync() to fsync(). ──Quoth SQLite (os_unix.c) return VfsFsync(fildes); #elif defined(__HAIKU__) // Haiku doesn't have fdatasync() yet return VfsFsync(fildes); #else return VfsFdatasync(fildes); #endif } static int SysChdir(struct Machine *m, i64 path) { return VfsChdir(LoadStr(m, path)); } static int SysFchdir(struct Machine *m, i32 fildes) { return VfsFchdir(fildes); } static int XlatLock(int x) { switch (x) { case LOCK_UN_LINUX: return LOCK_UN; case LOCK_SH_LINUX: return LOCK_SH; case LOCK_SH_LINUX | LOCK_NB_LINUX: return LOCK_SH | LOCK_NB; case LOCK_EX_LINUX: return LOCK_EX; case LOCK_EX_LINUX | LOCK_NB_LINUX: return LOCK_EX | LOCK_NB; default: LOGF("bad flock() type: %#x", x); return einval(); } } static int SysFlock(struct Machine *m, i32 fd, i32 lock) { if ((lock = XlatLock(lock)) == -1) return -1; return VfsFlock(fd, lock); } static int SysShutdown(struct Machine *m, i32 fd, i32 how) { return VfsShutdown(fd, XlatShutdown(how)); } static int SysListen(struct Machine *m, i32 fd, i32 backlog) { return VfsListen(fd, backlog); } static int SysMkdirat(struct Machine *m, i32 dirfd, i64 path, i32 mode) { return VfsMkdir(GetDirFildes(dirfd), LoadStr(m, path), mode); } static int SysMkdir(struct Machine *m, i64 path, i32 mode) { return SysMkdirat(m, AT_FDCWD_LINUX, path, mode); } static int SysFchmod(struct Machine *m, i32 fd, u32 mode) { return VfsFchmod(fd, mode); } static int SysFchmodat(struct Machine *m, i32 dirfd, i64 path, u32 mode) { return VfsChmod(GetDirFildes(dirfd), LoadStr(m, path), mode, 0); } static int SysFcntlLock(struct Machine *m, int systemfd, int cmd, i64 arg) { int rc; int whence; int syscmd; struct flock flock; struct flock_linux flock_linux; if (CopyFromUserRead(m, &flock_linux, arg, sizeof(flock_linux))) { return -1; } if (cmd == F_SETLK_LINUX) { syscmd = F_SETLK; } else if (cmd == F_SETLKW_LINUX) { syscmd = F_SETLKW; } else { syscmd = F_GETLK; } memset(&flock, 0, sizeof(flock)); if (Read16(flock_linux.type) == F_RDLCK_LINUX) { flock.l_type = F_RDLCK; } else if (Read16(flock_linux.type) == F_WRLCK_LINUX) { flock.l_type = F_WRLCK; } else if (Read16(flock_linux.type) == F_UNLCK_LINUX) { flock.l_type = F_UNLCK; } else { return einval(); } if ((whence = XlatWhence(Read16(flock_linux.whence))) == -1) return -1; flock.l_whence = whence; flock.l_start = Read64(flock_linux.start); flock.l_len = Read64(flock_linux.len); RESTARTABLE(rc = VfsFcntl(systemfd, syscmd, &flock)); if (rc != -1 && syscmd == F_GETLK) { if (flock.l_type == F_RDLCK) { Write16(flock_linux.type, F_RDLCK_LINUX); } else if (flock.l_type == F_WRLCK) { Write16(flock_linux.type, F_WRLCK_LINUX); } else { Write16(flock_linux.type, F_UNLCK_LINUX); } if (flock.l_whence == SEEK_END) { Write16(flock_linux.whence, SEEK_END_LINUX); } else if (flock.l_whence == SEEK_CUR) { Write16(flock_linux.whence, SEEK_CUR_LINUX); } else { Write16(flock_linux.whence, SEEK_SET_LINUX); } Write64(flock_linux.start, flock.l_start); Write64(flock_linux.len, flock.l_len); Write32(flock_linux.pid, flock.l_pid); CopyToUserWrite(m, arg, &flock_linux, sizeof(flock_linux)); } return rc; } #ifdef HAVE_F_GETOWN_EX static int UnxlatFownerType(int type) { if (type == F_OWNER_TID) return F_OWNER_TID_LINUX; if (type == F_OWNER_PID) return F_OWNER_PID_LINUX; if (type == F_OWNER_PGRP) return F_OWNER_PGRP_LINUX; LOGF("unknown f_owner_ex::type %d", type); return einval(); } #endif #ifdef F_SETOWN static int SysFcntlSetownEx(struct Machine *m, i32 fildes, i64 addr) { const struct f_owner_ex_linux *gowner; if (!(gowner = (const struct f_owner_ex_linux *)SchlepR(m, addr, sizeof(*gowner)))) { return -1; } #ifdef HAVE_F_GETOWN_EX struct f_owner_ex howner; switch (Read32(gowner->type)) { case F_OWNER_TID_LINUX: howner.type = F_OWNER_TID; howner.pid = (i32)Read32(gowner->pid); break; case F_OWNER_PID_LINUX: howner.type = F_OWNER_PID; howner.pid = (i32)Read32(gowner->pid); break; case F_OWNER_PGRP_LINUX: howner.type = F_OWNER_PGRP; howner.pid = (i32)Read32(gowner->pid); break; default: LOGF("unknown f_owner_ex::type %" PRId32, Read32(gowner->type)); return einval(); } return VfsFcntl(fildes, F_SETOWN_EX, &howner); #else pid_t pid; switch (Read32(gowner->type)) { case F_OWNER_PID_LINUX: pid = (i32)Read32(gowner->pid); break; case F_OWNER_PGRP_LINUX: pid = (i32)-Read32(gowner->pid); break; case F_OWNER_TID_LINUX: // POSIX doesn't specify fcntl() as applying per-thread if (!(pid = (i32)Read32(gowner->pid)) || pid == m->system->pid) { break; } // fallthrough default: LOGF("unknown f_owner_ex::type %" PRId32, Read32(gowner->type)); return einval(); } return VfsFcntl(fildes, F_SETOWN, pid); #endif } #endif #ifdef F_GETOWN static int SysFcntlGetownEx(struct Machine *m, i32 fildes, i64 addr) { int rc; struct f_owner_ex_linux gowner; if (!IsValidMemory(m, addr, sizeof(gowner), PROT_WRITE)) return -1; #ifdef HAVE_F_GETOWN_EX int type; struct f_owner_ex howner; if ((rc = VfsFcntl(fildes, F_GETOWN_EX, &howner)) != -1) { if ((type = UnxlatFownerType(howner.type)) != -1) { Write32(gowner.type, type); Write32(gowner.pid, howner.pid); CopyToUserWrite(m, addr, &gowner, sizeof(gowner)); } else { rc = -1; } } #else if ((rc = VfsFcntl(fildes, F_GETOWN)) != -1) { if (rc >= 0) { Write32(gowner.type, F_OWNER_PID_LINUX); Write32(gowner.pid, rc); } else { Write32(gowner.type, F_OWNER_PGRP_LINUX); Write32(gowner.pid, -rc); } CopyToUserWrite(m, addr, &gowner, sizeof(gowner)); } #endif return rc; } #endif static int SysFcntl(struct Machine *m, i32 fildes, i32 cmd, i64 arg) { int rc, fl; struct Fd *fd; if (cmd == F_DUPFD_LINUX) { return SysDupf(m, fildes, arg, F_DUPFD); } else if (cmd == F_DUPFD_CLOEXEC_LINUX) { return SysDupf(m, fildes, arg, F_DUPFD_CLOEXEC); } if (!(fd = GetAndLockFd(m, fildes))) return -1; if (cmd == F_GETFD_LINUX) { rc = (fd->oflags & O_CLOEXEC) ? FD_CLOEXEC_LINUX : 0; } else if (cmd == F_GETFL_LINUX) { rc = UnXlatOpenFlags(fd->oflags); } else if (cmd == F_SETFD_LINUX) { if (!(arg & ~FD_CLOEXEC_LINUX)) { if (VfsFcntl(fd->fildes, F_SETFD, arg ? FD_CLOEXEC : 0) != -1) { fd->oflags &= ~O_CLOEXEC; if (arg) fd->oflags |= O_CLOEXEC; rc = 0; } else { rc = -1; } } else { rc = einval(); } } else if (cmd == F_SETFL_LINUX) { fl = XlatOpenFlags(arg & (O_APPEND_LINUX | O_ASYNC_LINUX | O_DIRECT_LINUX | O_NOATIME_LINUX | O_NDELAY_LINUX)); if (VfsFcntl(fd->fildes, F_SETFL, fl) != -1) { fd->oflags &= ~SETFL_FLAGS; fd->oflags |= fl; rc = 0; } else { rc = -1; } } else if (cmd == F_SETLK_LINUX || // cmd == F_SETLKW_LINUX || // cmd == F_GETLK_LINUX) { UnlockFd(fd); return SysFcntlLock(m, fildes, cmd, arg); #ifdef F_SETOWN } else if (cmd == F_SETOWN_LINUX) { rc = VfsFcntl(fd->fildes, F_SETOWN, arg); #endif #ifdef F_GETOWN } else if (cmd == F_GETOWN_LINUX) { rc = VfsFcntl(fd->fildes, F_GETOWN); #endif #ifndef DISABLE_NONPOSIX #ifdef HAVE_F_GETOWN_EX } else if (cmd == F_SETOWN_EX_LINUX) { rc = SysFcntlSetownEx(m, fd->fildes, arg); #endif #ifdef HAVE_F_GETOWN_EX } else if (cmd == F_GETOWN_EX_LINUX) { rc = SysFcntlGetownEx(m, fd->fildes, arg); #endif #endif } else { LOGF("missing fcntl() command %" PRId32, cmd); rc = einval(); } UnlockFd(fd); return rc; } static ssize_t SysReadlinkat(struct Machine *m, int dirfd, i64 path, i64 bufaddr, i64 bufsiz) { char *buf; ssize_t rc; // This system call raises EINVAL when "bufsiz is not positive." // ──Quoth the Linux Programmer's Manual § readlink(2). Some libc // implementations (e.g. Musl) consider it to be posixly incorrect. if (bufsiz <= 0) return einval(); if (!(buf = (char *)AddToFreeList(m, malloc(bufsiz)))) return -1; if ((rc = VfsReadlink(GetDirFildes(dirfd), LoadStr(m, path), buf, bufsiz)) != -1) { if (CopyToUserWrite(m, bufaddr, buf, rc) == -1) rc = -1; } return rc; } static int SysChmod(struct Machine *m, i64 path, u32 mode) { return SysFchmodat(m, AT_FDCWD_LINUX, path, mode); } static int SysTruncate(struct Machine *m, i64 pathaddr, i64 length) { int rc, fd; const char *path; if (length < 0) return einval(); if (length > NUMERIC_MAX(off_t)) return eoverflow(); if (!(path = LoadStr(m, pathaddr))) return -1; RESTARTABLE(fd = VfsOpen(AT_FDCWD, path, O_RDWR | O_CLOEXEC, 0)); if (fd == -1) return -1; rc = VfsFtruncate(fd, length); VfsClose(fd); return rc; } static int SysSymlinkat(struct Machine *m, i64 targetpath, i32 newdirfd, i64 linkpath) { return VfsSymlink(LoadStr(m, targetpath), GetDirFildes(newdirfd), LoadStr(m, linkpath)); } static int SysSymlink(struct Machine *m, i64 targetpath, i64 linkpath) { return SysSymlinkat(m, targetpath, AT_FDCWD_LINUX, linkpath); } static int SysReadlink(struct Machine *m, i64 path, i64 bufaddr, u64 size) { return SysReadlinkat(m, AT_FDCWD_LINUX, path, bufaddr, size); } static int SysMknodat(struct Machine *m, i32 dirfd, i64 path, i32 mode, u64 dev) { _Static_assert(S_IFIFO == 0010000, ""); // pipe _Static_assert(S_IFCHR == 0020000, ""); // character device _Static_assert(S_IFDIR == 0040000, ""); // directory _Static_assert(S_IFBLK == 0060000, ""); // block device _Static_assert(S_IFREG == 0100000, ""); // regular file _Static_assert(S_IFLNK == 0120000, ""); // symbolic link _Static_assert(S_IFSOCK == 0140000, ""); // socket _Static_assert(S_IFMT == 0170000, ""); // mask of file types above if ((mode & S_IFMT) == S_IFIFO) { return VfsMkfifo(GetDirFildes(dirfd), LoadStr(m, path), mode & ~S_IFMT); } else { LOGF("mknod mode %#o not supported yet", mode); return enosys(); } } static int SysMknod(struct Machine *m, i64 path, i32 mode, u64 dev) { return SysMknodat(m, AT_FDCWD_LINUX, path, mode, dev); } static int XlatPrio(int x) { switch (x) { XLAT(0, PRIO_PROCESS); XLAT(1, PRIO_PGRP); XLAT(2, PRIO_USER); default: return -1; } } static int SysGetpriority(struct Machine *m, i32 which, u32 who) { int rc; errno = 0; rc = getpriority(XlatPrio(which), who); if (rc == -1 && errno) return -1; return MAX(-20, MIN(19, rc)) + 20; } static int SysSetpriority(struct Machine *m, i32 which, u32 who, int prio) { return setpriority(XlatPrio(which), who, prio); } static int XlatUnlinkatFlags(int x) { int res = 0; if (x & AT_REMOVEDIR_LINUX) { res |= AT_REMOVEDIR; x &= ~AT_REMOVEDIR_LINUX; } if (x) { LOGF("%s() flags %#x not supported", "unlinkat", x); return einval(); } return res; } static int SysUnlinkat(struct Machine *m, i32 dirfd, i64 pathaddr, i32 flags) { int rc; const char *path; dirfd = GetDirFildes(dirfd); if ((flags = XlatUnlinkatFlags(flags)) == -1) return -1; if (!(path = LoadStr(m, pathaddr))) return -1; rc = VfsUnlink(dirfd, path, flags); #ifndef __linux // POSIX.1 says unlink(directory) raises EPERM but on Linux // it always raises EISDIR, which is so much less ambiguous if (rc == -1 && !flags && errno == EPERM) { struct stat st; if (!fstatat(dirfd, path, &st, 0) && S_ISDIR(st.st_mode)) { errno = EISDIR; } else { errno = EPERM; } } #endif return rc; } static int SysUnlink(struct Machine *m, i64 pathaddr) { return SysUnlinkat(m, AT_FDCWD_LINUX, pathaddr, 0); } static int SysRmdir(struct Machine *m, i64 path) { return SysUnlinkat(m, AT_FDCWD_LINUX, path, AT_REMOVEDIR_LINUX); } static int SysRenameat2(struct Machine *m, int srcdirfd, i64 srcpath, int dstdirfd, i64 dstpathaddr, i32 flags) { struct stat st; i32 unsupported; const char *dstpath; i32 supported = RENAME_NOREPLACE_LINUX; if ((unsupported = flags & ~supported)) { LOGF("%s flags not supported yet: %#" PRIx32, "renameat2", unsupported); return einval(); } if (!(dstpath = LoadStr(m, dstpathaddr))) return -1; // TODO: check for renameat2 in configure script if ((flags & RENAME_NOREPLACE_LINUX) && !VfsStat(GetDirFildes(dstdirfd), dstpath, &st, AT_SYMLINK_NOFOLLOW)) { errno = EEXIST; return -1; } return VfsRename(GetDirFildes(srcdirfd), LoadStr(m, srcpath), GetDirFildes(dstdirfd), dstpath); } static int SysRenameat(struct Machine *m, int srcdirfd, i64 srcpath, int dstdirfd, i64 dstpath) { return SysRenameat2(m, srcdirfd, srcpath, dstdirfd, dstpath, 0); } static int SysRename(struct Machine *m, i64 src, i64 dst) { return SysRenameat(m, AT_FDCWD_LINUX, src, AT_FDCWD_LINUX, dst); } static int XlatLinkatFlags(int x) { int res = 0; if (x & AT_SYMLINK_NOFOLLOW_LINUX) { x &= ~AT_SYMLINK_NOFOLLOW_LINUX; // default behavior } if (x & AT_SYMLINK_FOLLOW_LINUX) { res |= AT_SYMLINK_FOLLOW; x &= ~AT_SYMLINK_FOLLOW_LINUX; } if (x) { LOGF("%s() flags %d not supported", "linkat", x); return -1; } return res; } static i32 SysLinkat(struct Machine *m, // i32 olddirfd, // i64 oldpath, // i32 newdirfd, // i64 newpath, // i32 flags) { return VfsLink(GetDirFildes(olddirfd), LoadStr(m, oldpath), GetDirFildes(newdirfd), LoadStr(m, newpath), XlatLinkatFlags(flags)); } static int SysLink(struct Machine *m, i64 existingpath, i64 newpath) { return SysLinkat(m, AT_FDCWD_LINUX, existingpath, AT_FDCWD_LINUX, newpath, 0); } static bool IsBlinkSig(struct System *s, int sig) { unassert(1 <= sig && sig <= 64); return !!(s->blinksigs & ((u64)1 << (sig - 1))); } static void ResetTimerDispositions(struct System *s) { struct itimerval it; memset(&it, 0, sizeof(it)); setitimer(ITIMER_REAL, &it, 0); } static void ResetSignalDispositions(struct System *s) { int sig; int syssig; LOCK(&s->sig_lock); for (sig = 1; sig <= 64; ++sig) { if (!IsBlinkSig(s, sig) && Read64(s->hands[sig - 1].handler) != SIG_IGN_LINUX && Read64(s->hands[sig - 1].handler) != SIG_DFL_LINUX && (syssig = XlatSignal(sig)) != -1) { Write64(s->hands[sig - 1].handler, SIG_DFL_LINUX); signal(syssig, SIG_DFL); } } UNLOCK(&s->sig_lock); } static void ExecveBlink(struct Machine *m, char *prog, char **argv, char **envp) { char *execfn; sigset_t block; if (m->system->exec) { // it's worth blocking signals on the outside of the if statement // since open() during the executable check, might possibly EINTR // and the same could apply to calling close() on our cloexec fds execfn = prog; sigfillset(&block); unassert(!pthread_sigmask(SIG_BLOCK, &block, &m->system->exec_sigmask)); if (CanEmulateExecutable(m, &prog, &argv)) { // point of no return // prog/argv/envp are copied onto the freelist m->sysdepth = 0; CollectPageLocks(m); // TODO(jart): Prevent possibility of stack overflow. SYS_LOGF("m->system->exec(%s)", prog); SysCloseExec(m->system); ResetTimerDispositions(m->system); ResetSignalDispositions(m->system); _Exit(m->system->exec(execfn, prog, argv, envp)); } unassert(!pthread_sigmask(SIG_SETMASK, &m->system->exec_sigmask, 0)); } } static int SysExecve(struct Machine *m, i64 pa, i64 aa, i64 ea) { char *prog, **argv, **envp; if (!(prog = CopyStr(m, pa))) return -1; if (!(argv = CopyStrList(m, aa))) return -1; if (!(envp = CopyStrList(m, ea))) return -1; LOCK(&m->system->exec_lock); ExecveBlink(m, prog, argv, envp); SYS_LOGF("execve(%s)", prog); VfsExecve(prog, argv, envp); UNLOCK(&m->system->exec_lock); return -1; } static int SysWait4(struct Machine *m, int pid, i64 opt_out_wstatus_addr, int options, i64 opt_out_rusage_addr) { int rc; int wstatus; i32 gwstatus; u8 gwstatusb[4]; struct rusage hrusage; struct rusage_linux grusage; if ((options = XlatWait(options)) == -1) return -1; if ((opt_out_wstatus_addr && !IsValidMemory(m, opt_out_wstatus_addr, sizeof(gwstatusb), PROT_WRITE)) || (opt_out_rusage_addr && !IsValidMemory(m, opt_out_rusage_addr, sizeof(grusage), PROT_WRITE))) { return -1; } #ifdef HAVE_WAIT4 RESTARTABLE(rc = wait4(pid, &wstatus, options, &hrusage)); #else memset(&hrusage, 0, sizeof(hrusage)); if (opt_out_rusage_addr && (!pid || pid == -1)) { LOGF("wait4(rusage) with indeterminate pid not possible on this platform"); } else { getrusage(pid < 0 ? -pid : pid, &hrusage); } RESTARTABLE(rc = waitpid(pid, &wstatus, options)); #endif if (rc != -1 && rc != 0) { if (opt_out_wstatus_addr) { #ifdef WIFCONTINUED if (WIFCONTINUED(wstatus)) { gwstatus = 0xffff; SYS_LOGF("pid %d continued", rc); } else #endif if (WIFEXITED(wstatus)) { int exitcode; exitcode = WEXITSTATUS(wstatus) & 255; gwstatus = exitcode << 8; SYS_LOGF("pid %d exited %d", rc, exitcode); } else if (WIFSTOPPED(wstatus)) { int stopsig; stopsig = UnXlatSignal(WSTOPSIG(wstatus)); gwstatus = stopsig << 8 | 127; SYS_LOGF("pid %d stopped %s", rc, DescribeSignal(stopsig)); } else { int termsig; unassert(WIFSIGNALED(wstatus)); termsig = UnXlatSignal(WTERMSIG(wstatus)); SYS_LOGF("pid %d terminated %s", rc, DescribeSignal(termsig)); gwstatus = termsig & 127; } Write32(gwstatusb, gwstatus); CopyToUserWrite(m, opt_out_wstatus_addr, gwstatusb, sizeof(gwstatusb)); } if (opt_out_rusage_addr) { XlatRusageToLinux(&grusage, &hrusage); CopyToUserWrite(m, opt_out_rusage_addr, &grusage, sizeof(grusage)); } } return rc; } static int SysGetrusage(struct Machine *m, i32 resource, i64 rusageaddr) { int rc; struct rusage hrusage; struct rusage_linux grusage; if ((rc = getrusage(XlatRusage(resource), &hrusage)) != -1) { XlatRusageToLinux(&grusage, &hrusage); if (CopyToUserWrite(m, rusageaddr, &grusage, sizeof(grusage)) == -1) { rc = -1; } } return rc; } static bool IsSupportedResourceLimit(int resource) { return resource == RLIMIT_AS_LINUX || // resource == RLIMIT_DATA_LINUX || // resource == RLIMIT_NOFILE_LINUX; } static void GetResourceLimit_(struct Machine *m, int resource, struct rlimit_linux *lux) { LOCK(&m->system->mmap_lock); memcpy(lux, m->system->rlim + resource, sizeof(*lux)); UNLOCK(&m->system->mmap_lock); } static int SetResourceLimit(struct Machine *m, int resource, const struct rlimit_linux *lux) { int rc; LOCK(&m->system->mmap_lock); if (Read64(lux->cur) <= Read64(m->system->rlim[resource].max) && Read64(lux->max) <= Read64(m->system->rlim[resource].max)) { memcpy(m->system->rlim + resource, lux, sizeof(*lux)); rc = 0; } else { rc = eperm(); } UNLOCK(&m->system->mmap_lock); return rc; } static int SysGetrlimit(struct Machine *m, i32 resource, i64 rlimitaddr) { int rc; struct rlimit rlim; struct rlimit_linux lux; if (IsSupportedResourceLimit(resource)) { GetResourceLimit_(m, resource, &lux); return CopyToUserWrite(m, rlimitaddr, &lux, sizeof(lux)); } if ((rc = getrlimit(XlatResource(resource), &rlim)) != -1) { XlatRlimitToLinux(&lux, &rlim); if (CopyToUserWrite(m, rlimitaddr, &lux, sizeof(lux)) == -1) rc = -1; } return rc; } static int SysSetrlimit(struct Machine *m, i32 resource, i64 rlimitaddr) { int sysresource; struct rlimit rlim; const struct rlimit_linux *lux; if (!(lux = (const struct rlimit_linux *)SchlepR(m, rlimitaddr, sizeof(*lux)))) { return -1; } if (IsSupportedResourceLimit(resource)) { return SetResourceLimit(m, resource, lux); } if ((sysresource = XlatResource(resource)) == -1) return -1; XlatLinuxToRlimit(sysresource, &rlim, lux); return setrlimit(sysresource, &rlim); } static int SysPrlimit(struct Machine *m, i32 pid, i32 resource, i64 new_rlimit_addr, i64 old_rlimit_addr) { if (pid && pid != m->system->pid) { return eperm(); } #ifndef TINY if ((old_rlimit_addr && !IsValidMemory(m, old_rlimit_addr, sizeof(struct rlimit_linux), PROT_WRITE)) && (new_rlimit_addr && !IsValidMemory(m, new_rlimit_addr, sizeof(struct rlimit_linux), PROT_READ))) { return -1; } #endif if ((old_rlimit_addr && SysGetrlimit(m, resource, old_rlimit_addr) == -1) || (new_rlimit_addr && SysSetrlimit(m, resource, new_rlimit_addr) == -1)) { return -1; } return 0; } static int SysSysinfo(struct Machine *m, i64 siaddr) { struct sysinfo_linux si; if (sysinfo_linux(&si) == -1) return -1; CopyToUserWrite(m, siaddr, &si, sizeof(si)); return 0; } static i64 SysGetcwd(struct Machine *m, i64 bufaddr, i64 size) { i64 res; size_t n; char buf[PATH_MAX + 1]; if (size < 0) return enomem(); if (VfsGetcwd(buf, sizeof(buf))) { n = strlen(buf) + 1; if (size < n) { res = erange(); } else if (CopyToUserWrite(m, bufaddr, buf, n) != -1) { res = n; } else { res = -1; } } else { res = -1; } return res; } static ssize_t SysGetrandom(struct Machine *m, i64 a, size_t n, int f) { char *p; ssize_t rc; int besteffort, unsupported; besteffort = GRND_NONBLOCK_LINUX | GRND_RANDOM_LINUX; if ((unsupported = f & ~besteffort)) { LOGF("%s() flags %d not supported", "getrandom", unsupported); return einval(); } if (n) { if (!(p = (char *)AddToFreeList(m, malloc(n)))) return -1; RESTARTABLE(rc = GetRandom(p, n, f)); if (rc != -1) { if (CopyToUserWrite(m, a, p, rc) == -1) { rc = -1; } } } else { rc = 0; } return rc; } void OnSignal(int sig, siginfo_t *si, void *uc) { SIG_LOGF("OnSignal(%s)", DescribeSignal(UnXlatSignal(sig))); EnqueueSignal(g_machine, UnXlatSignal(sig)); } static int SysSigaction(struct Machine *m, int sig, i64 act, i64 old, u64 sigsetsize) { int syssig; u64 flags = 0; i64 handler = 0; bool isignored = false; struct sigaction syshand; struct sigaction_linux hand; u32 supported = SA_SIGINFO_LINUX | // SA_RESTART_LINUX | // SA_ONSTACK_LINUX | // SA_NODEFER_LINUX | // SA_RESTORER_LINUX | // SA_RESETHAND_LINUX | // #ifdef SA_NOCLDWAIT SA_NOCLDWAIT_LINUX | // #endif SA_NOCLDSTOP_LINUX; if (sigsetsize != 8) return einval(); if (!(1 <= sig && sig <= 64)) return einval(); if (sig == SIGKILL_LINUX || sig == SIGSTOP_LINUX) return einval(); if (old && !IsValidMemory(m, old, sizeof(hand), PROT_WRITE)) return -1; memset(&hand, 0, sizeof(hand)); if (act) { if (CopyFromUserRead(m, &hand, act, sizeof(hand)) == -1) return -1; flags = Read64(hand.flags); handler = Read64(hand.handler); if (handler == SIG_IGN_LINUX) { flags &= ~SA_NOCLDWAIT_LINUX; } if (flags & ~supported) { LOGF("unrecognized sigaction() flags: %#" PRIx64, flags & ~supported); return einval(); } switch (handler) { case SIG_DFL_LINUX: isignored = IsSignalIgnoredByDefault(sig); break; case SIG_IGN_LINUX: isignored = true; break; default: if (!(flags & SA_RESTORER_LINUX)) { LOGF("sigaction() flags missing SA_RESTORER"); return einval(); } if (!IsValidMemory(m, Read64(hand.restorer), 1, PROT_EXEC)) { LOGF("sigaction() SA_RESTORER at %" PRIx64 " isn't executable", Read64(hand.restorer)); return -1; } break; } } LOCK(&m->system->sig_lock); if (old) { CopyToUserWrite(m, old, &m->system->hands[sig - 1], sizeof(hand)); } if (act) { m->system->hands[sig - 1] = hand; if (isignored) { m->signals &= ~((u64)1 << (sig - 1)); } if ((syssig = XlatSignal(sig)) != -1 && !IsBlinkSig(m->system, sig)) { sigfillset(&syshand.sa_mask); syshand.sa_flags = SA_SIGINFO; if (flags & SA_NOCLDSTOP_LINUX) syshand.sa_flags |= SA_NOCLDSTOP; #ifdef SA_NOCLDWAIT if (flags & SA_NOCLDWAIT_LINUX) syshand.sa_flags |= SA_NOCLDWAIT; #endif switch (handler) { case SIG_DFL_LINUX: syshand.sa_handler = SIG_DFL; break; case SIG_IGN_LINUX: syshand.sa_handler = SIG_IGN; break; default: syshand.sa_sigaction = OnSignal; break; } if (sigaction(syssig, &syshand, 0)) { LOGF("system sigaction(%s) returned %s", DescribeSignal(sig), DescribeHostErrno(errno)); } } } UNLOCK(&m->system->sig_lock); return 0; } static int SysGetitimer(struct Machine *m, int which, i64 curvaladdr) { int rc; struct itimerval it; struct itimerval_linux git; if ((rc = getitimer(UnXlatItimer(which), &it)) != -1) { XlatItimervalToLinux(&git, &it); CopyToUserWrite(m, curvaladdr, &git, sizeof(git)); } return rc; } static int SysSetitimer(struct Machine *m, int which, i64 neuaddr, i64 oldaddr) { int rc; struct itimerval_linux gold; struct itimerval neu, *neup, old; const struct itimerval_linux *git = 0; if ((neuaddr && !(git = (const struct itimerval_linux *)SchlepR( m, neuaddr, sizeof(*git)))) || (oldaddr && !IsValidMemory(m, oldaddr, sizeof(gold), PROT_WRITE))) { return -1; } if (git) { XlatLinuxToItimerval(&neu, git); neup = &neu; } else { neup = 0; } if ((rc = setitimer(UnXlatItimer(which), neup, &old)) != -1) { if (oldaddr) { XlatItimervalToLinux(&gold, &old); CopyToUserWrite(m, oldaddr, &gold, sizeof(gold)); } } return rc; } static int SysNanosleep(struct Machine *m, i64 req, i64 rem) { struct timespec_linux gt; const struct timespec_linux *gtp; struct timespec ts, now, deadline; now = GetTime(); if ((rem && !IsValidMemory(m, rem, sizeof(gtp), PROT_WRITE)) || !(gtp = (const struct timespec_linux *)SchlepR(m, req, sizeof(*gtp)))) { return -1; } ts.tv_sec = Read64(gtp->sec); ts.tv_nsec = Read64(gtp->nsec); if (ts.tv_sec < 0) return einval(); if (!(0 <= ts.tv_nsec && ts.tv_nsec < 1000000000)) return einval(); deadline = AddTime(now, ts); for (;;) { if (CompareTime(now, deadline) >= 0) return 0; ts = SubtractTime(deadline, now); if (nanosleep(&ts, 0)) { unassert(errno == EINTR); // this may run a guest signal handler before returning if (CheckInterrupt(m, false)) { // a signal was delivered or is about to be delivered if (rem) { // rem is only updated when -1 w/ eintr is returned now = GetTime(); if (CompareTime(now, deadline) < 0) { ts = SubtractTime(deadline, now); } else { ts = GetZeroTime(); } Write64(gt.sec, ts.tv_sec); Write64(gt.nsec, ts.tv_nsec); CopyToUserWrite(m, rem, >, sizeof(gt)); } return -1; } } // sleep apis aren't nearly as fast and reliable as time apis // even if nanosleep() claims it slept the full time we check now = GetTime(); } } static int SysClockNanosleep(struct Machine *m, int clock, int flags, i64 reqaddr, i64 remaddr) { int rc; clock_t sysclock; struct timespec req, rem; struct timespec_linux gtimespec; if (XlatClock(clock, &sysclock) == -1) return -1; if (flags & ~TIMER_ABSTIME_LINUX) return einval(); if (CopyFromUserRead(m, >imespec, reqaddr, sizeof(gtimespec)) == -1) { return -1; } req.tv_sec = Read64(gtimespec.sec); req.tv_nsec = Read64(gtimespec.nsec); TryAgain: #if defined(TIMER_ABSTIME) && !defined(__OpenBSD__) flags = flags & TIMER_ABSTIME_LINUX ? TIMER_ABSTIME : 0; if ((rc = clock_nanosleep(sysclock, flags, &req, &rem))) { errno = rc; rc = -1; } #else if (!flags) { if (sysclock == CLOCK_REALTIME) { rc = nanosleep(&req, &rem); } else { rc = einval(); } } else { struct timespec now; if (!(rc = clock_gettime(sysclock, &now))) { if (CompareTime(now, req) < 0) { req = SubtractTime(req, now); rc = nanosleep(&req, &rem); } else { rc = 0; } } } #endif if (rc == -1 && errno == EINTR) { if (CheckInterrupt(m, false)) { if (!flags && remaddr) { Write64(gtimespec.sec, rem.tv_sec); Write64(gtimespec.nsec, rem.tv_nsec); CopyToUserWrite(m, remaddr, >imespec, sizeof(gtimespec)); } } else { if (!flags) { req = rem; } goto TryAgain; } } return rc; } static int SigsuspendActual(struct Machine *m, u64 mask) { int rc; u64 oldmask; sigset_t block_host, oldmask_host; oldmask = m->sigmask; unassert(!sigfillset(&block_host)); unassert(!pthread_sigmask(SIG_BLOCK, &block_host, &oldmask_host)); m->sigmask = mask; SIG_LOGF("sigmask push %" PRIx64, m->sigmask); m->issigsuspend = true; NORESTART(rc, sigsuspend(&oldmask_host)); m->issigsuspend = false; unassert(!pthread_sigmask(SIG_SETMASK, &oldmask_host, 0)); m->sigmask = oldmask; SIG_LOGF("sigmask pop %" PRIx64, m->sigmask); return rc; } static int SigsuspendPolyfill(struct Machine *m, u64 mask) { long nanos; u64 oldmask; struct timespec ts; oldmask = m->sigmask; m->sigmask = mask; nanos = 1; while (!CheckInterrupt(m, false)) { if (nanos > 256) { if (nanos < 10 * 1000) { #ifdef HAVE_SCHED_YIELD sched_yield(); #endif } else { ts = FromNanoseconds(nanos); if (nanosleep(&ts, 0)) { unassert(errno == EINTR); continue; } } } if (nanos < 100 * 1000 * 1000) { nanos <<= 1; } } m->sigmask = oldmask; return -1; } static int SysSigsuspend(struct Machine *m, i64 maskaddr, i64 sigsetsize) { u8 word[8]; if (sigsetsize != 8) return einval(); if (CopyFromUserRead(m, word, maskaddr, 8) == -1) return -1; #ifdef __EMSCRIPTEN__ return SigsuspendPolyfill(m, Read64(word)); #else return SigsuspendActual(m, Read64(word)); #endif } static int SysSigaltstack(struct Machine *m, i64 newaddr, i64 oldaddr) { bool isonstack; int supported, unsupported; const struct sigaltstack_linux *ss = 0; supported = SS_ONSTACK_LINUX | SS_DISABLE_LINUX | SS_AUTODISARM_LINUX; isonstack = (~Read32(m->sigaltstack.flags) & SS_DISABLE_LINUX) && Read64(m->sp) >= Read64(m->sigaltstack.sp) && Read64(m->sp) <= Read64(m->sigaltstack.sp) + Read64(m->sigaltstack.size); if (newaddr) { if (isonstack) { LOGF("can't change sigaltstack whilst on sigaltstack"); return eperm(); } if (!(ss = (const struct sigaltstack_linux *)SchlepR(m, newaddr, sizeof(*ss)))) { LOGF("couldn't schlep new sigaltstack: %#" PRIx64, newaddr); return -1; } if ((unsupported = Read32(ss->flags) & ~supported)) { LOGF("unsupported %s flags: %#x", "sigaltstack", unsupported); return einval(); } if (~Read32(ss->flags) & SS_DISABLE_LINUX) { if (Read64(ss->size) < MINSIGSTKSZ_LINUX) { LOGF("sigaltstack ss_size=%#" PRIx64 " must be at least %#x", Read64(ss->size), MINSIGSTKSZ_LINUX); return enomem(); } if (!IsValidMemory(m, Read64(ss->sp), Read64(ss->size), PROT_READ | PROT_WRITE)) { LOGF("sigaltstack ss_sp=%#" PRIx64 " ss_size=%#" PRIx64 " didn't exist with read+write permission", Read64(ss->sp), Read64(ss->size)); return -1; } } } if (oldaddr) { Write32(m->sigaltstack.flags, Read32(m->sigaltstack.flags) & ~SS_ONSTACK_LINUX); if (isonstack) { Write32(m->sigaltstack.flags, Read32(m->sigaltstack.flags) | SS_ONSTACK_LINUX); } CopyToUserWrite(m, oldaddr, &m->sigaltstack, sizeof(m->sigaltstack)); } if (ss) { memcpy(&m->sigaltstack, ss, sizeof(*ss)); } return 0; } static int SysClockGettime(struct Machine *m, int clock, i64 ts) { int rc; clock_t sysclock; struct timespec htimespec; struct timespec_linux gtimespec; if (clock == CLOCK_REALTIME_LINUX) { sysclock = CLOCK_REALTIME; } else if (XlatClock(clock, &sysclock) == -1) { return -1; } if ((rc = clock_gettime(sysclock, &htimespec)) != -1) { if (ts) { Write64(gtimespec.sec, htimespec.tv_sec); Write64(gtimespec.nsec, htimespec.tv_nsec); CopyToUserWrite(m, ts, >imespec, sizeof(gtimespec)); } } return rc; } #ifdef HAVE_CLOCK_SETTIME static int SysClockSettime(struct Machine *m, int clock, i64 ts) { clock_t sysclock; struct timespec ht; const struct timespec_linux *gt; if (XlatClock(clock, &sysclock) == -1) return -1; if ((gt = (const struct timespec_linux *)SchlepR(m, ts, sizeof(*gt)))) { ht.tv_sec = Read64(gt->sec); ht.tv_nsec = Read64(gt->nsec); } return clock_settime(sysclock, &ht); } #endif static int SysClockGetres(struct Machine *m, int clock, i64 ts) { int rc; clock_t sysclock; struct timespec htimespec; struct timespec_linux gtimespec; if (XlatClock(clock, &sysclock) == -1) return -1; if ((rc = clock_getres(sysclock, &htimespec)) != -1) { if (ts) { Write64(gtimespec.sec, htimespec.tv_sec); Write64(gtimespec.nsec, htimespec.tv_nsec); CopyToUserWrite(m, ts, >imespec, sizeof(gtimespec)); } } return rc; } static int SysGettimeofday(struct Machine *m, i64 tv, i64 tz) { int rc; void *htimezonep; struct timeval htimeval; struct timeval_linux gtimeval; #ifdef HAVE_STRUCT_TIMEZONE struct timezone htimezone; struct timezone_linux gtimezone; memset(&htimezone, 0, sizeof(htimezone)); htimezonep = tz ? &htimezone : 0; #else htimezonep = 0; #endif if ((rc = gettimeofday(&htimeval, htimezonep)) != -1) { Write64(gtimeval.sec, htimeval.tv_sec); Write64(gtimeval.usec, htimeval.tv_usec); if (CopyToUserWrite(m, tv, >imeval, sizeof(gtimeval)) == -1) { return -1; } // "If tzp is not a null pointer, the behavior is unspecified." // ──Quoth the POSIX.1 IEEE Std 1003.1-2017 for gettimeofday(). if (tz) { #ifdef HAVE_STRUCT_TIMEZONE Write32(gtimezone.minuteswest, htimezone.tz_minuteswest); Write32(gtimezone.dsttime, htimezone.tz_dsttime); if (CopyToUserWrite(m, tz, >imezone, sizeof(gtimezone)) == -1) { return -1; } #else rc = enotsup(); #endif } } return rc; } static i64 SysTime(struct Machine *m, i64 addr) { u8 buf[8]; time_t secs; if ((secs = time(0)) == (time_t)-1) return -1; if (addr) { Write64(buf, secs); if (CopyToUserWrite(m, addr, buf, sizeof(buf)) == -1) return -1; } return secs; } static i64 SysTimes(struct Machine *m, i64 bufaddr) { // no conversion needed thanks to getauxval(AT_CLKTCK) clock_t res; struct tms tms; struct tms_linux gtms; if ((res = times(&tms)) == (clock_t)-1) return -1; Write64(gtms.utime, tms.tms_utime); Write64(gtms.stime, tms.tms_stime); Write64(gtms.cutime, tms.tms_cutime); Write64(gtms.cstime, tms.tms_cstime); if (CopyToUserWrite(m, bufaddr, >ms, sizeof(gtms)) == -1) return -1; return res; } static struct timespec ConvertUtimeTimespec(const struct timespec_linux *tv) { struct timespec ts; switch (Read64(tv->nsec)) { case UTIME_NOW_LINUX: ts.tv_sec = 0; ts.tv_nsec = UTIME_NOW; return ts; case UTIME_OMIT_LINUX: ts.tv_sec = 0; ts.tv_nsec = UTIME_OMIT; return ts; default: ts.tv_sec = Read64(tv->sec); ts.tv_nsec = Read64(tv->nsec); return ts; } } static struct timespec ConvertUtimeTimeval(const struct timeval_linux *tv) { i64 x; struct timespec ts; switch ((x = Read64(tv->usec))) { case UTIME_NOW_LINUX: ts.tv_sec = 0; ts.tv_nsec = UTIME_NOW; return ts; case UTIME_OMIT_LINUX: ts.tv_sec = 0; ts.tv_nsec = UTIME_OMIT; return ts; default: ts.tv_sec = Read64(tv->sec); if (0 <= x && x < 1000000) { ts.tv_nsec = x * 1000; } else { // make sure system call will einval // should not overlap with magnums above ts.tv_nsec = 1000000666; } return ts; } } static void ConvertUtimeTimespecs(struct timespec *ts, const struct timespec_linux *tv) { ts[0] = ConvertUtimeTimespec(tv + 0); ts[1] = ConvertUtimeTimespec(tv + 1); } static void ConvertUtimeTimevals(struct timespec *ts, const struct timeval_linux *tv) { ts[0] = ConvertUtimeTimeval(tv + 0); ts[1] = ConvertUtimeTimeval(tv + 1); } static int XlatUtimensatFlags(int x) { int res = 0; if (x & AT_SYMLINK_FOLLOW_LINUX) { x &= ~AT_SYMLINK_FOLLOW_LINUX; // default behavior } if (x & AT_SYMLINK_NOFOLLOW_LINUX) { res |= AT_SYMLINK_NOFOLLOW; x &= ~AT_SYMLINK_NOFOLLOW_LINUX; } if (x) { LOGF("%s() flags %d not supported", "utimensat", x); return -1; } return res; } static int SysUtime(struct Machine *m, i64 pathaddr, i64 timesaddr) { const char *path; struct timespec ts[2]; const struct utimbuf_linux *t; if (!(path = LoadStr(m, pathaddr))) return -1; if (!timesaddr) return VfsUtime(AT_FDCWD, path, 0, 0); if ((t = (const struct utimbuf_linux *)SchlepR(m, timesaddr, sizeof(*t)))) { ts[0].tv_sec = Read64(t->actime); ts[0].tv_nsec = 0; ts[1].tv_sec = Read64(t->modtime); ts[1].tv_nsec = 0; return VfsUtime(AT_FDCWD, path, ts, 0); } else { return -1; } } static int SysUtimes(struct Machine *m, i64 pathaddr, i64 tvsaddr) { const char *path; struct timespec ts[2]; const struct timeval_linux *tv; if (!(path = LoadStr(m, pathaddr))) return -1; if (!tvsaddr) return VfsUtime(AT_FDCWD, path, 0, 0); if ((tv = (const struct timeval_linux *)SchlepR( m, tvsaddr, sizeof(struct timeval_linux) * 2))) { ConvertUtimeTimevals(ts, tv); return VfsUtime(AT_FDCWD, path, ts, 0); } else { return -1; } } static int SysFutimesat(struct Machine *m, i32 dirfd, i64 pathaddr, i64 tvsaddr) { const char *path; struct timespec ts[2]; const struct timeval_linux *tv; if (!(path = LoadStr(m, pathaddr))) return -1; if (!tvsaddr) return VfsUtime(GetDirFildes(dirfd), path, 0, 0); if ((tv = (const struct timeval_linux *)SchlepR( m, tvsaddr, sizeof(struct timeval_linux) * 2))) { ConvertUtimeTimevals(ts, tv); return VfsUtime(GetDirFildes(dirfd), path, ts, 0); } else { return -1; } } static int SysUtimensat(struct Machine *m, i32 fd, i64 pathaddr, i64 tvsaddr, i32 flags) { const char *path; struct timespec ts[2], *tsp; const struct timespec_linux *tv; if (!pathaddr) { path = 0; } else if (!(path = LoadStr(m, pathaddr))) { return -1; } if (tvsaddr) { if ((tv = (const struct timespec_linux *)SchlepR( m, tvsaddr, sizeof(struct timespec_linux) * 2))) { ConvertUtimeTimespecs(ts, tv); tsp = ts; } else { return -1; } } else { tsp = 0; } if ((flags = XlatUtimensatFlags(flags)) == -1) return -1; if (path) { return VfsUtime(GetDirFildes(fd), path, tsp, flags); } else { if (flags) { LOGF("%s() flags %d not supported", "utimensat(path=null)", flags); return einval(); } return VfsFutime(fd, tsp); } } static int LoadFdSet(struct Machine *m, int nfds, fd_set *fds, i64 addr) { u64 w; int fd; unsigned o; const u64 *p; if ((p = (const u64 *)SchlepRW(m, addr, FD_SETSIZE_LINUX / 8))) { FD_ZERO(fds); for (fd = 0; fd < nfds; fd += 64) { w = p[fd >> 6]; while (w) { o = bsr(w); w &= ~((u64)1 << o); if (fd + o < nfds) { FD_SET(fd + o, fds); } } } return 0; } else { return -1; } } static int SaveFdSet(struct Machine *m, int nfds, const fd_set *fds, i64 addr) { int fd; u8 p[FD_SETSIZE_LINUX / 8] = {0}; for (fd = 0; fd < nfds; ++fd) { if (FD_ISSET(fd, fds)) { p[fd >> 3] |= 1 << (fd & 7); } } return CopyToUserWrite(m, addr, p, FD_SETSIZE_LINUX / 8); } static i32 Select(struct Machine *m, // i32 nfds, // i64 readfds_addr, // i64 writefds_addr, // i64 exceptfds_addr, // struct timespec *timeoutp, // const u64 *sigmaskp_guest) { int fildes, rc; i32 setsize; u64 oldmask_guest = 0; fd_set readfds, writefds, exceptfds, readyreadfds, readywritefds, readyexceptfds; struct pollfd hfds[1]; struct timespec now, wait, remain, deadline = {0}; struct Fd *fd; int (*poll_impl)(struct pollfd *, nfds_t, int); if (timeoutp) { deadline = AddTime(GetTime(), *timeoutp); } setsize = MIN(FD_SETSIZE, FD_SETSIZE_LINUX); if (nfds < 0 || nfds > setsize) { LOGF("select() nfds=%d can't exceed %d on this platform", nfds, setsize); return einval(); } if (readfds_addr) { if (LoadFdSet(m, nfds, &readfds, readfds_addr) == -1) { return -1; } } else { FD_ZERO(&readfds); } if (writefds_addr) { if (LoadFdSet(m, nfds, &writefds, writefds_addr) == -1) { return -1; } } else { FD_ZERO(&writefds); } if (exceptfds_addr) { if (LoadFdSet(m, nfds, &exceptfds, exceptfds_addr) == -1) { return -1; } } else { FD_ZERO(&exceptfds); } FD_ZERO(&readyreadfds); FD_ZERO(&readywritefds); FD_ZERO(&readyexceptfds); if (sigmaskp_guest) { oldmask_guest = m->sigmask; m->sigmask = *sigmaskp_guest; SIG_LOGF("sigmask push %" PRIx64, m->sigmask); } for (;;) { if (CheckInterrupt(m, false)) { rc = eintr(); break; } rc = 0; for (fildes = 0; fildes < nfds; ++fildes) { if (!FD_ISSET(fildes, &readfds) && !FD_ISSET(fildes, &writefds) && !FD_ISSET(fildes, &exceptfds)) { continue; } TryAgain: if (CheckInterrupt(m, false)) { rc = eintr(); break; } LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { unassert(fd->cb); unassert(poll_impl = fd->cb->poll); } else { poll_impl = 0; } UNLOCK(&m->system->fds.lock); if (fd) { hfds[0].fd = fildes; hfds[0].events = ((FD_ISSET(fildes, &readfds) ? POLLIN : 0) | (FD_ISSET(fildes, &writefds) ? POLLOUT : 0) | (FD_ISSET(fildes, &exceptfds) ? POLLPRI : 0)); switch (poll_impl(hfds, 1, 0)) { case 0: break; case 1: if (FD_ISSET(fildes, &readfds) && (hfds[0].revents & POLLIN)) { ++rc; FD_SET(fildes, &readyreadfds); FD_CLR(fildes, &readfds); } if (FD_ISSET(fildes, &writefds) && (hfds[0].revents & POLLOUT)) { ++rc; FD_SET(fildes, &readywritefds); FD_CLR(fildes, &writefds); } if (FD_ISSET(fildes, &exceptfds) && (hfds[0].revents & POLLPRI)) { ++rc; FD_SET(fildes, &readyexceptfds); FD_CLR(fildes, &exceptfds); } break; case -1: if (errno == EINTR) { goto TryAgain; } rc = -1; goto BreakLoop; } } else { rc = ebadf(); break; } } BreakLoop: if (rc || (timeoutp && CompareTime(now = GetTime(), deadline) >= 0)) { break; } if (timeoutp) { wait = FromMilliseconds(kPollingMs); remain = SubtractTime(deadline, now); if (CompareTime(remain, wait) < 0) { wait = remain; } } else { wait = FromMilliseconds(kPollingMs); } nanosleep(&wait, 0); } if (sigmaskp_guest) { m->sigmask = oldmask_guest; SIG_LOGF("sigmask pop %" PRIx64, m->sigmask); } if (rc != -1) { if ((readfds_addr && SaveFdSet(m, nfds, &readyreadfds, readfds_addr) == -1) || (writefds_addr && SaveFdSet(m, nfds, &readywritefds, writefds_addr) == -1) || (exceptfds_addr && SaveFdSet(m, nfds, &readyexceptfds, exceptfds_addr) == -1)) { return -1; } } #ifndef DISABLE_NONPOSIX if (timeoutp) { now = GetTime(); if (CompareTime(now, deadline) < 0) { *timeoutp = SubtractTime(deadline, now); } else { *timeoutp = GetZeroTime(); } } #endif return rc; } static i32 SysSelect(struct Machine *m, i32 nfds, i64 readfds_addr, i64 writefds_addr, i64 exceptfds_addr, i64 timeout_addr) { i32 rc; struct timespec timeout, *timeoutp; #ifndef DISABLE_NONPOSIX struct timeval_linux timeout_linux; #endif const struct timeval_linux *timeoutp_linux; if (timeout_addr) { if ((timeoutp_linux = (const struct timeval_linux *)SchlepRW( m, timeout_addr, sizeof(*timeoutp_linux)))) { timeout.tv_sec = Read64(timeoutp_linux->sec); timeout.tv_nsec = Read64(timeoutp_linux->usec); if (0 <= timeout.tv_sec && (0 <= timeout.tv_nsec && timeout.tv_nsec < 1000000)) { timeout.tv_nsec *= 1000; timeoutp = &timeout; } else { return einval(); } } else { return -1; } } else { timeoutp = 0; memset(&timeout, 0, sizeof(timeout)); } rc = Select(m, nfds, readfds_addr, writefds_addr, exceptfds_addr, timeoutp, 0); #ifndef DISABLE_NONPOSIX if (timeout_addr) { Write64(timeout_linux.sec, timeout.tv_sec); Write64(timeout_linux.usec, (timeout.tv_nsec + 999) / 1000); CopyToUserWrite(m, timeout_addr, &timeout_linux, sizeof(timeout_linux)); } #endif return rc; } static i32 SysPselect(struct Machine *m, i32 nfds, i64 readfds_addr, i64 writefds_addr, i64 exceptfds_addr, i64 timeout_addr, i64 pselect6_addr) { i32 rc; u64 sigmask, *sigmaskp; const struct sigset_linux *sm; const struct pselect6_linux *ps; struct timespec timeout, *timeoutp; #ifndef DISABLE_NONPOSIX struct timespec_linux timeout_linux; #endif if (timeout_addr) { if (LoadTimespecRW(m, timeout_addr, &timeout) == -1) return -1; timeoutp = &timeout; } else { timeoutp = 0; memset(&timeout, 0, sizeof(timeout)); } if (pselect6_addr) { if ((ps = (const struct pselect6_linux *)SchlepR(m, pselect6_addr, sizeof(*ps)))) { if (Read64(ps->sigmaskaddr)) { if (Read64(ps->sigmasksize) == 8) { if ((sm = (const struct sigset_linux *)SchlepR( m, Read64(ps->sigmaskaddr), sizeof(*sm)))) { sigmask = Read64(sm->sigmask); sigmaskp = &sigmask; } else { return -1; } } else { return einval(); } } else { sigmaskp = 0; } } else { return -1; } } else { sigmaskp = 0; } rc = Select(m, nfds, readfds_addr, writefds_addr, exceptfds_addr, timeoutp, sigmaskp); #ifndef DISABLE_NONPOSIX if (timeout_addr) { Write64(timeout_linux.sec, timeout.tv_sec); Write64(timeout_linux.nsec, timeout.tv_nsec); CopyToUserWrite(m, timeout_addr, &timeout_linux, sizeof(timeout_linux)); } #endif return rc; } static int Poll(struct Machine *m, i64 fdsaddr, u64 nfds, struct timespec deadline) { long i; u64 gfdssize; struct Fd *fd; int fildes, rc, ev; struct pollfd hfds[1]; struct pollfd_linux *gfds; struct timespec now, wait, remain; int (*poll_impl)(struct pollfd *, nfds_t, int); if (!ckd_mul(&gfdssize, nfds, sizeof(struct pollfd_linux)) && gfdssize <= 0x7ffff000) { if ((gfds = (struct pollfd_linux *)AddToFreeList(m, malloc(gfdssize)))) { rc = 0; CopyFromUserRead(m, gfds, fdsaddr, gfdssize); for (;;) { for (i = 0; i < nfds; ++i) { TryAgain: if (CheckInterrupt(m, false)) { rc = eintr(); break; } fildes = Read32(gfds[i].fd); LOCK(&m->system->fds.lock); if ((fd = GetFd(&m->system->fds, fildes))) { unassert(fd->cb); unassert(poll_impl = fd->cb->poll); } else { poll_impl = 0; } UNLOCK(&m->system->fds.lock); if (fd) { hfds[0].fd = fildes; ev = Read16(gfds[i].events); hfds[0].events = (((ev & POLLIN_LINUX) ? POLLIN : 0) | ((ev & POLLOUT_LINUX) ? POLLOUT : 0) | ((ev & POLLPRI_LINUX) ? POLLPRI : 0)); switch (poll_impl(hfds, 1, 0)) { case 0: Write16(gfds[i].revents, 0); break; case 1: ++rc; ev = 0; if (hfds[0].revents & POLLIN) ev |= POLLIN_LINUX; if (hfds[0].revents & POLLPRI) ev |= POLLPRI_LINUX; if (hfds[0].revents & POLLOUT) ev |= POLLOUT_LINUX; if (hfds[0].revents & POLLERR) ev |= POLLERR_LINUX; if (hfds[0].revents & POLLHUP) ev |= POLLHUP_LINUX; if (hfds[0].revents & POLLNVAL) ev |= POLLERR_LINUX; if (!ev) ev |= POLLERR_LINUX; Write16(gfds[i].revents, ev); break; case -1: if (errno == EINTR) { goto TryAgain; } ++rc; Write16(gfds[i].revents, POLLERR_LINUX); break; default: break; } } else { Write16(gfds[i].revents, POLLNVAL_LINUX); } } if (rc || CompareTime((now = GetTime()), deadline) >= 0) { break; } wait = FromMilliseconds(kPollingMs); remain = SubtractTime(deadline, now); if (CompareTime(remain, wait) < 0) { wait = remain; } nanosleep(&wait, 0); } if (rc != -1) { CopyToUserWrite(m, fdsaddr, gfds, nfds * sizeof(*gfds)); } } else { rc = enomem(); } return rc; } else { return einval(); } } static int SysPoll(struct Machine *m, i64 fdsaddr, u64 nfds, i32 timeout_ms) { struct timespec deadline; if (timeout_ms < 0) { deadline = GetMaxTime(); } else { deadline = AddTime(GetTime(), FromMilliseconds(timeout_ms)); } return Poll(m, fdsaddr, nfds, deadline); } static int SysPpoll(struct Machine *m, i64 fdsaddr, u64 nfds, i64 timeoutaddr, i64 sigmaskaddr, u64 sigsetsize) { int rc; u64 oldmask = 0; const struct sigset_linux *sm; struct timespec_linux timeout_linux; struct timespec now, timeout, remain, deadline; if (sigmaskaddr) { if (sigsetsize != 8) return einval(); if ((sm = (const struct sigset_linux *)SchlepR(m, sigmaskaddr, sizeof(*sm)))) { oldmask = m->sigmask; m->sigmask = Read64(sm->sigmask); SIG_LOGF("sigmask push %" PRIx64, m->sigmask); } else { return -1; } } if (!CheckInterrupt(m, false)) { if (timeoutaddr) { if (LoadTimespecRW(m, timeoutaddr, &timeout) == -1) return -1; deadline = AddTime(GetTime(), timeout); rc = Poll(m, fdsaddr, nfds, deadline); now = GetTime(); if (CompareTime(now, deadline) >= 0) { remain = FromMilliseconds(0); } else { remain = SubtractTime(deadline, now); } Write64(timeout_linux.sec, remain.tv_sec); Write64(timeout_linux.nsec, remain.tv_nsec); CopyToUserWrite(m, timeoutaddr, &timeout_linux, sizeof(timeout_linux)); } else { rc = Poll(m, fdsaddr, nfds, GetMaxTime()); } } else { rc = -1; } if (sigmaskaddr) { m->sigmask = oldmask; SIG_LOGF("sigmask pop %" PRIx64, m->sigmask); } return rc; } static int SysSigprocmask(struct Machine *m, int how, i64 setaddr, i64 oldsetaddr, u64 sigsetsize) { u64 set; u8 word[8]; sigset_t ss; const u8 *neu; int sig, delivered; if (sigsetsize != 8) { return einval(); } if (how != SIG_BLOCK_LINUX && // how != SIG_UNBLOCK_LINUX && // how != SIG_SETMASK_LINUX) { return einval(); } if (setaddr) { if (!(neu = (const u8 *)SchlepR(m, setaddr, 8))) { return -1; } } else { neu = 0; } if (oldsetaddr) { SIG_LOGF("sigmask read %" PRIx64, m->sigmask); Write64(word, m->sigmask); if (CopyToUserWrite(m, oldsetaddr, word, 8) == -1) { return -1; } } if (setaddr) { set = Read64(neu); if (how == SIG_BLOCK_LINUX) { m->sigmask |= set; } else if (how == SIG_UNBLOCK_LINUX) { m->sigmask &= ~set; } else if (how == SIG_SETMASK_LINUX) { m->sigmask = set; } else { __builtin_unreachable(); } XlatLinuxToSigset(&ss, m->sigmask & ((u64)1 << (SIGTSTP_LINUX - 1) | (u64)1 << (SIGTTIN_LINUX - 1) | (u64)1 << (SIGTTOU_LINUX - 1))); sigprocmask(SIG_BLOCK, &ss, 0); } Put64(m->ax, 0); do { if ((sig = ConsumeSignal(m, &delivered, 0))) { TerminateSignal(m, sig, 0); } } while (delivered && DeliverSignalRecursively(m, delivered)); return 0; } static int SysSigpending(struct Machine *m, i64 setaddr) { u8 word[8]; Write64(word, m->signals); return CopyToUserWrite(m, setaddr, word, 8); } static int SysKill(struct Machine *m, int pid, int sig) { return kill(pid, sig ? XlatSignal(sig) : 0); } static bool IsValidThreadId(struct System *s, int tid) { return tid == s->pid || (kMinThreadId <= tid && tid < kMinThreadId + kMaxThreadIds); } static int SysTkill(struct Machine *m, int tid, int sig) { #if defined(HAVE_FORK) || defined(HAVE_THREADS) bool found; int rc, err; if (tid < 0) return einval(); if (!(0 <= sig && sig <= 64)) { LOGF("tkill(%d, %d) failed due to bogus signal", tid, sig); return einval(); } // trigger signal immediately if possible if (tid == m->tid) { if (sig == SIGSTOP_LINUX || sig == SIGKILL_LINUX) { return raise(XlatSignal(sig)); } else if (~m->sigmask & ((u64)1 << (sig - 1))) { LOCK(&m->system->sig_lock); switch (Read64(m->system->hands[sig - 1].handler)) { case SIG_DFL_LINUX: if (!IsSignalIgnoredByDefault(sig)) { UNLOCK(&m->system->sig_lock); TerminateSignal(m, sig, 0); return 0; } // fallthrough case SIG_IGN_LINUX: rc = 0; break; default: Put64(m->ax, 0); m->interrupted = true; DeliverSignal(m, sig, SI_TKILL_LINUX); rc = -1; break; } UNLOCK(&m->system->sig_lock); return rc; } else { m->signals |= (u64)1 << (sig - 1); return 0; } } if (!IsValidThreadId(m->system, tid)) { LOGF("tkill(%d, %d) failed due to bogus thread id", tid, sig); return esrch(); } err = 0; found = 0; #ifndef DISABLE_THREADS { struct Dll *e; LOCK(&m->system->machines_lock); for (e = dll_first(m->system->machines); e; e = dll_next(m->system->machines, e)) { struct Machine *m2; m2 = MACHINE_CONTAINER(e); if (m2->tid == tid) { if (sig) { EnqueueSignal(m2, sig); err = pthread_kill(m2->thread, SIGSYS); } else { err = pthread_kill(m2->thread, 0); } found = true; break; } } UNLOCK(&m->system->machines_lock); } #endif if (!found) { return SysKill(m, tid, sig); } if (!err) { return 0; } else { errno = err; return -1; } #else return SysKill(m, tid, sig); #endif /* HAVE_THREADS */ } static int SysTgkill(struct Machine *m, int pid, int tid, int sig) { if (pid < 1 || tid < 1) return einval(); if (pid != m->system->pid) return eperm(); #ifdef HAVE_THREADS return SysTkill(m, tid, sig); #else if (tid != pid) return esrch(); return SysKill(m, tid, sig); #endif } static int SysPause(struct Machine *m) { int rc; NORESTART(rc, pause()); return rc; } static int SysSetsid(struct Machine *m) { return setsid(); } static i32 SysGetsid(struct Machine *m, i32 pid) { return getsid(pid); } static int SysGetpid(struct Machine *m) { return m->system->pid; } static int SysGettid(struct Machine *m) { return m->tid; } static int SysGetppid(struct Machine *m) { return getppid(); } static int SysGetuid(struct Machine *m) { return getuid(); } static int SysGetgid(struct Machine *m) { return getgid(); } static int SysGeteuid(struct Machine *m) { return geteuid(); } static int SysGetegid(struct Machine *m) { return getegid(); } static i32 SysGetgroups(struct Machine *m, i32 size, i64 addr) { gid_t *group; u8 i32buf[4]; int i, ngroups; long ngroups_max; if (!size) { return getgroups(0, 0); } else { // POSIX.1 recommends adding 1 to ngroups_max but the Linux manual // says this can result in EINVAL. Apple M1 says NGROUPS_MAX is 16 // even though it usually returns 18 groups or more... #ifdef __APPLE__ ngroups_max = size; #else ngroups_max = sysconf(_SC_NGROUPS_MAX); #endif size = MIN(size, ngroups_max); if (!IsValidMemory(m, addr, (size_t)size * 4, PROT_WRITE)) return -1; if (!(group = (gid_t *)AddToFreeList(m, malloc(size * sizeof(gid_t))))) { return -1; } if ((ngroups = getgroups(size, group)) != -1) { for (i = 0; i < ngroups; ++i) { Write32(i32buf, group[i]); CopyToUserWrite(m, addr + (size_t)i * 4, i32buf, 4); } } return ngroups; } } static i32 SysSetgroups(struct Machine *m, i32 size, i64 addr) { #ifdef HAVE_SETGROUPS int i; gid_t *group; const u8 *group_linux; if (!(group_linux = (const u8 *)SchlepR(m, addr, (size_t)size * 4)) || !(group = (gid_t *)AddToFreeList(m, malloc(size * sizeof(gid_t))))) { return -1; } for (i = 0; i < size; ++i) { group[i] = Read32(group_linux + (size_t)i * 4); } return setgroups(size, group); #else return enosys(); #endif } static i32 SysSetresuid(struct Machine *m, // u32 real, // u32 effective, // u32 saved) { #ifdef HAVE_SETRESUID return setresuid(real, effective, saved); #elif defined(HAVE_SETREUID) // we're going to assume "saved uids" don't exist if the platform // doesn't provide the api for changing them. this lets us ignore // complexity regarding how setruid() vs. setresuid() impact uids return setreuid(real, effective); #else if (real == -1 && effective == -1) return 0; if (real == -1) return seteuid(effective); if (real != effective) return enosys(); return setuid(real); #endif } static i32 SysSetresgid(struct Machine *m, // u32 real, // u32 effective, // u32 saved) { #ifdef HAVE_SETRESGID return setresgid(real, effective, saved); #elif defined(HAVE_SETREGID) // we're going to assume "saved gids" don't exist if the platform // doesn't provide the api for changing them. this lets us ignore // complexity regarding how setrgid() vs. setresgid() impact gids return setregid(real, effective); #else if (real == -1 && effective == -1) return 0; if (real == -1) return setegid(effective); if (real != effective) return enosys(); return setgid(real); #endif } static int SysSetreuid(struct Machine *m, u32 real, u32 effective) { #ifdef HAVE_SETRESUID // If the real user ID is set (i.e., ruid is not -1) or the effective // user ID is set to a value not equal to the previous real user ID, // the saved set-user-ID will be set to the new effective user ID. // ──Quoth the Linux Programmer's Manual § setreuid() if (real != -1 || (effective != -1 && effective != getuid())) { if (effective == -1) effective = geteuid(); return setresuid(real, effective, effective); } else { return setresuid(real, effective, -1); } #else return SysSetresuid(m, real, effective, -1); #endif } static int SysSetregid(struct Machine *m, u32 real, u32 effective) { #ifdef HAVE_SETRESUID if (real != -1 || (effective != -1 && effective != getgid())) { if (effective == -1) effective = getegid(); return setresgid(real, effective, effective); } else { return setresgid(real, effective, -1); } #else return SysSetresgid(m, real, effective, -1); #endif } static i32 SysGetresuid(struct Machine *m, // i64 realaddr, // i64 effectiveaddr, // i64 savedaddr) { u8 *real = 0; u8 *saved = 0; u8 *effective = 0; uid_t uid, euid, suid; if ((realaddr && !(real = (u8 *)SchlepW(m, realaddr, 4))) || (savedaddr && !(saved = (u8 *)SchlepW(m, savedaddr, 4))) || (effectiveaddr && !(effective = (u8 *)SchlepW(m, effectiveaddr, 4)))) { return -1; } #ifdef HAVE_SETRESUID if (getresuid(&uid, &euid, &suid) == -1) return -1; #else uid = getuid(); euid = geteuid(); suid = euid; #endif if (real) Write32(real, uid); if (saved) Write32(saved, suid); if (effective) Write32(effective, euid); return 0; } static i32 SysGetresgid(struct Machine *m, // i64 realaddr, // i64 effectiveaddr, // i64 savedaddr) { u8 *real = 0; u8 *saved = 0; u8 *effective = 0; gid_t gid, egid, sgid; if ((realaddr && !(real = (u8 *)SchlepW(m, realaddr, 4))) || (savedaddr && !(saved = (u8 *)SchlepW(m, savedaddr, 4))) || (effectiveaddr && !(effective = (u8 *)SchlepW(m, effectiveaddr, 4)))) { return -1; } #ifdef HAVE_SETRESUID if (getresgid(&gid, &egid, &sgid) == -1) return -1; #else gid = getgid(); egid = getegid(); sgid = egid; #endif if (real) Write32(real, gid); if (saved) Write32(saved, sgid); if (effective) Write32(effective, egid); return 0; } static int SysSchedYield(struct Machine *m) { #ifdef HAVE_SCHED_YIELD return sched_yield(); #else return 0; #endif } static int SysUmask(struct Machine *m, int mask) { return umask(mask); } static int SysSetuid(struct Machine *m, int uid) { return setuid(uid); } static int SysSetgid(struct Machine *m, int gid) { return setgid(gid); } static int SysGetpgid(struct Machine *m, int pid) { return getpgid(pid); } static int SysGetpgrp(struct Machine *m) { return getpgid(0); } static int SysAlarm(struct Machine *m, unsigned seconds) { return alarm(seconds); } static int SysSetpgid(struct Machine *m, int pid, int gid) { return setpgid(pid, gid); } static int SysCreat(struct Machine *m, i64 path, int mode) { return SysOpenat(m, AT_FDCWD_LINUX, path, O_WRONLY_LINUX | O_CREAT_LINUX | O_TRUNC_LINUX, mode); } static int SysAccess(struct Machine *m, i64 path, int mode) { return SysFaccessat(m, AT_FDCWD_LINUX, path, mode); } static int SysStat(struct Machine *m, i64 path, i64 st) { return SysFstatat(m, AT_FDCWD_LINUX, path, st, 0); } static int SysLstat(struct Machine *m, i64 path, i64 st) { return SysFstatat(m, AT_FDCWD_LINUX, path, st, AT_SYMLINK_NOFOLLOW_LINUX); } static int SysOpen(struct Machine *m, i64 path, int flags, int mode) { return SysOpenat(m, AT_FDCWD_LINUX, path, flags, mode); } static int SysAccept(struct Machine *m, int fd, i64 sa, i64 sas) { return SysAccept4(m, fd, sa, sas, 0); } static int SysSchedSetparam(struct Machine *m, int pid, i64 paramaddr) { if (pid < 0 || !paramaddr) return einval(); return 0; } static int SysSchedGetparam(struct Machine *m, int pid, i64 paramaddr) { u8 param[8]; if (pid < 0 || !paramaddr) return einval(); Write32(param, 0); CopyToUserWrite(m, paramaddr, param, 8); return 0; } static int SysSchedSetscheduler(struct Machine *m, int pid, int policy, i64 paramaddr) { if (pid < 0 || !paramaddr) return einval(); return 0; } static int SysSchedGetscheduler(struct Machine *m, int pid) { if (pid < 0) return einval(); return SCHED_OTHER_LINUX; } static int SysSchedGetPriorityMax(struct Machine *m, int policy) { return 0; } static int SysSchedGetPriorityMin(struct Machine *m, int policy) { return 0; } static int SysPipe(struct Machine *m, i64 pipefds_addr) { return SysPipe2(m, pipefds_addr, 0); } #ifdef HAVE_EPOLL_PWAIT1 static i32 SysEpollCreate1(struct Machine *m, i32 flags) { int lim, fildes, oflags, sysflags; oflags = 0; sysflags = 0; if (flags & EPOLL_CLOEXEC_LINUX) { oflags |= O_CLOEXEC; sysflags |= EPOLL_CLOEXEC; flags &= ~EPOLL_CLOEXEC_LINUX; } if (flags) { LOGF("unsupported %s flags: %#x", "epoll_create1", flags); return einval(); } if (!(lim = GetFileDescriptorLimit(m->system))) return emfile(); if ((fildes = epoll_create1(sysflags)) != -1) { if (fildes >= lim) { close(fildes); fildes = emfile(); } else { LOCK(&m->system->fds.lock); unassert(AddFd(&m->system->fds, fildes, oflags)); UNLOCK(&m->system->fds.lock); } } return fildes; } static i32 SysEpollCreate(struct Machine *m, i32 size) { if (size <= 0) return einval(); return SysEpollCreate1(m, 0); } static i32 SysEpollCtl(struct Machine *m, i32 epfd, i32 op, i32 fd, i64 eventaddr) { struct epoll_event epe, *pepe; const struct epoll_event_linux *gepe; switch (op) { case EPOLL_CTL_DEL_LINUX: pepe = 0; break; case EPOLL_CTL_ADD_LINUX: case EPOLL_CTL_MOD_LINUX: if (!(gepe = (const struct epoll_event_linux *)SchlepR(m, eventaddr, sizeof(*gepe)))) { return -1; } epe.events = Read32(gepe->events); epe.data.u64 = Read64(gepe->data); pepe = &epe; break; default: return einval(); } return epoll_ctl(epfd, op, fd, pepe); } static i32 EpollPwait(struct Machine *m, i32 epfd, i64 eventsaddr, i32 maxevents, struct timespec deadline, i64 sigmaskaddr, u64 sigsetsize) { i32 i, rc; u64 oldmask_guest = 0; sigset_t block, oldmask; struct epoll_event *events; struct timespec now, waitfor; struct epoll_event_linux *gevents; const struct sigset_linux *sigmaskp_guest = 0; if (maxevents <= 0) return einval(); if (sigmaskaddr) { if (sigsetsize != 8) return einval(); if (!(sigmaskp_guest = (const struct sigset_linux *)SchlepR( m, sigmaskaddr, sizeof(*sigmaskp_guest)))) { return -1; } } if (!IsValidMemory(m, eventsaddr, maxevents * sizeof(struct epoll_event_linux), PROT_WRITE) || !(events = (struct epoll_event *)AddToFreeList( m, calloc(maxevents, sizeof(struct epoll_event)))) || !(gevents = (struct epoll_event_linux *)AddToFreeList( m, calloc(maxevents, sizeof(struct epoll_event_linux))))) { return -1; } unassert(!sigfillset(&block)); unassert(!pthread_sigmask(SIG_BLOCK, &block, &oldmask)); if (sigmaskp_guest) { oldmask_guest = m->sigmask; m->sigmask = Read64(sigmaskp_guest->sigmask); SIG_LOGF("sigmask push %" PRIx64, m->sigmask); } if (!CheckInterrupt(m, false)) { do { now = GetTime(); if (CompareTime(now, deadline) < 0) { waitfor = SubtractTime(deadline, now); } else { waitfor = GetZeroTime(); } #if defined(HAVE_EPOLL_PWAIT2) && !defined(MUSL_CROSS_MAKE) rc = epoll_pwait2(epfd, events, maxevents, &waitfor, &oldmask); #else rc = epoll_pwait(epfd, events, maxevents, ConvertTimeToInt(ToMilliseconds(waitfor)), &oldmask); #endif if (rc == -1 && errno == EINTR) { if (CheckInterrupt(m, false)) { break; } } else { break; } } while (1); } else { rc = -1; } if (sigmaskp_guest) { m->sigmask = oldmask_guest; SIG_LOGF("sigmask pop %" PRIx64, m->sigmask); } unassert(!pthread_sigmask(SIG_SETMASK, &oldmask, 0)); if (rc != -1) { for (i = 0; i < rc; ++i) { Write32(gevents[i].events, events[i].events); Write64(gevents[i].data, events[i].data.u64); } unassert(!CopyToUserWrite(m, eventsaddr, gevents, rc * sizeof(struct epoll_event_linux))); } return rc; } static i32 SysEpollPwait(struct Machine *m, i32 epfd, i64 eventsaddr, i32 maxevents, i32 timeout, i64 sigmaskaddr, u64 sigsetsize) { struct timespec deadline; if (timeout >= 0) { deadline = AddTime(GetTime(), FromMilliseconds(timeout)); } else { deadline = GetMaxTime(); } return EpollPwait(m, epfd, eventsaddr, maxevents, deadline, sigmaskaddr, sigsetsize); } static i32 SysEpollPwait2(struct Machine *m, i32 epfd, i64 eventsaddr, i32 maxevents, i64 timeoutaddr, i64 sigmaskaddr, u64 sigsetsize) { struct timespec ts, deadline; if (timeoutaddr) { if (LoadTimespecR(m, timeoutaddr, &ts) == -1) return -1; deadline = AddTime(GetTime(), ts); } else { deadline = GetMaxTime(); } return EpollPwait(m, epfd, eventsaddr, maxevents, deadline, sigmaskaddr, sigsetsize); } static int SysEpollWait(struct Machine *m, i32 epfd, i64 eventsaddr, i32 maxevents, i32 timeout) { return SysEpollPwait(m, epfd, eventsaddr, maxevents, timeout, 0, 8); } #endif /* HAVE_EPOLL_PWAIT1 */ void OpSyscall(P) { size_t mark; u64 ax, di, si, dx, r0, r8, r9; unassert(!m->nofault); if (Get64(m->ax) == 0xE4) { // clock_gettime() is // 1) called frequently, // 2) latency sensitive, and // 3) usually implemented as a VDSO. // Therefore we exempt it from system call tracing. ax = SysClockGettime(m, Get64(m->di), Get64(m->si)); Put64(m->ax, ax != -1 ? ax : -(XlatErrno(errno) & 0xfff)); return; } STATISTIC(++syscalls); // make sure blinkenlights display is up to date before performing any // potentially blocking operations which would otherwise freeze things if (m->system->redraw && m->tid == m->system->pid) { m->system->redraw(true); } // unlike pure opcodes where we'll confidently longjmp out of segfault // handlers, system calls are too complex to do that safely, and it is // therefore of the highest importance that they never crash under any // circumstances. in order to do ensure that we need to lock any pages // the system call accesses, so the user can't munmap() them away from // some other thread. since we don't want to slow down instructions by // adding locking logic to the tranlation lookaside buffer, we need to // ensure any memory references the system call performs will tlb miss m->insyscall = true; if (!m->sysdepth++) { atomic_store_explicit(&m->invalidated, true, memory_order_relaxed); } // to make system calls simpler and safer, any temporary memory that's // allocated will be added to a free list to be collected later. since // OpSyscall() is potentially recursive when SA_RESTART signals happen // we need to save the current mark, so we don't collect parent's data mark = m->freelist.n; m->interrupted = false; ax = Get64(m->ax); di = Get64(m->di); si = Get64(m->si); dx = Get64(m->dx); r0 = Get64(m->r10); r8 = Get64(m->r8); r9 = Get64(m->r9); switch (ax & 0xfff) { SYSCALL(3, 0x000, "read", SysRead, STRACE_READ); SYSCALL(3, 0x001, "write", SysWrite, STRACE_WRITE); SYSCALL(3, 0x002, "open", SysOpen, STRACE_OPEN); SYSCALL(1, 0x003, "close", SysClose, STRACE_CLOSE); SYSCALL(2, 0x004, "stat", SysStat, STRACE_STAT); SYSCALL(2, 0x005, "fstat", SysFstat, STRACE_FSTAT); SYSCALL(2, 0x006, "lstat", SysLstat, STRACE_LSTAT); SYSCALL(3, 0x007, "poll", SysPoll, STRACE_3); SYSCALL(3, 0x008, "lseek", SysLseek, STRACE_LSEEK); SYSCALL(6, 0x009, "mmap", SysMmap, STRACE_MMAP); SYSCALL(4, 0x011, "pread", SysPread, STRACE_PREAD); SYSCALL(4, 0x012, "pwrite", SysPwrite, STRACE_PWRITE); SYSCALL(5, 0x017, "select", SysSelect, STRACE_SELECT); SYSCALL(5, 0x019, "mremap", SysMremap, STRACE_5); SYSCALL(6, 0x10E, "pselect6", SysPselect, STRACE_6); SYSCALL(3, 0x01A, "msync", SysMsync, STRACE_3); SYSCALL(3, 0x00A, "mprotect", SysMprotect, STRACE_MPROTECT); SYSCALL(2, 0x00B, "munmap", SysMunmap, STRACE_MUNMAP); SYSCALL(4, 0x00D, "rt_sigaction", SysSigaction, STRACE_SIGACTION); SYSCALL(4, 0x00E, "rt_sigprocmask", SysSigprocmask, STRACE_SIGPROCMASK); SYSCALL(3, 0x010, "ioctl", SysIoctl, STRACE_3); SYSCALL(3, 0x013, "readv", SysReadv, STRACE_READV); SYSCALL(3, 0x014, "writev", SysWritev, STRACE_WRITEV); SYSCALL(2, 0x015, "access", SysAccess, STRACE_ACCESS); SYSCALL(3, 0x10D, "faccessat", SysFaccessat, STRACE_FACCESSAT); SYSCALL(4, 0x1b7, "faccessat2", SysFaccessat2, STRACE_FACCESSAT2); SYSCALL(0, 0x018, "sched_yield", SysSchedYield, STRACE_0); SYSCALL(3, 0x01C, "madvise", SysMadvise, STRACE_3); SYSCALL(1, 0x020, "dup", SysDup1, STRACE_DUP); SYSCALL(2, 0x021, "dup2", SysDup2, STRACE_DUP2); SYSCALL(0, 0x022, "pause", SysPause, STRACE_PAUSE); SYSCALL(2, 0x023, "nanosleep", SysNanosleep, STRACE_NANOSLEEP); SYSCALL(2, 0x024, "getitimer", SysGetitimer, STRACE_2); SYSCALL(1, 0x025, "alarm", SysAlarm, STRACE_ALARM); SYSCALL(3, 0x026, "setitimer", SysSetitimer, STRACE_3); SYSCALL(0, 0x027, "getpid", SysGetpid, STRACE_GETPID); SYSCALL(0, 0x0BA, "gettid", SysGettid, STRACE_GETTID); SYSCALL(1, 0x03F, "uname", SysUname, STRACE_1); SYSCALL(3, 0x048, "fcntl", SysFcntl, STRACE_FCNTL); SYSCALL(2, 0x049, "flock", SysFlock, STRACE_2); SYSCALL(1, 0x04A, "fsync", SysFsync, STRACE_FSYNC); SYSCALL(1, 0x04B, "fdatasync", SysFdatasync, STRACE_FDATASYNC); SYSCALL(2, 0x04C, "truncate", SysTruncate, STRACE_TRUNCATE); SYSCALL(2, 0x04D, "ftruncate", SysFtruncate, STRACE_FTRUNCATE); SYSCALL(2, 0x04F, "getcwd", SysGetcwd, STRACE_GETCWD); SYSCALL(1, 0x050, "chdir", SysChdir, STRACE_CHDIR); SYSCALL(1, 0x051, "fchdir", SysFchdir, STRACE_FCHOWN); SYSCALL(2, 0x052, "rename", SysRename, STRACE_RENAME); SYSCALL(2, 0x053, "mkdir", SysMkdir, STRACE_MKDIR); SYSCALL(1, 0x054, "rmdir", SysRmdir, STRACE_RMDIR); SYSCALL(2, 0x055, "creat", SysCreat, STRACE_CREAT); SYSCALL(2, 0x056, "link", SysLink, STRACE_LINK); SYSCALL(1, 0x057, "unlink", SysUnlink, STRACE_UNLINK); SYSCALL(2, 0x058, "symlink", SysSymlink, STRACE_SYMLINK); SYSCALL(3, 0x059, "readlink", SysReadlink, STRACE_READLINK); SYSCALL(2, 0x05A, "chmod", SysChmod, STRACE_CHMOD); SYSCALL(2, 0x05B, "fchmod", SysFchmod, STRACE_FCHOWN); SYSCALL(3, 0x05C, "chown", SysChown, STRACE_CHOWN); SYSCALL(3, 0x05D, "fchown", SysFchown, STRACE_FCHOWN); SYSCALL(3, 0x05E, "lchown", SysLchown, STRACE_LCHOWN); SYSCALL(5, 0x104, "fchownat", SysFchownat, STRACE_CHOWNAT); SYSCALL(1, 0x05F, "umask", SysUmask, STRACE_UMASK); SYSCALL(2, 0x060, "gettimeofday", SysGettimeofday, STRACE_2); SYSCALL(2, 0x061, "getrlimit", SysGetrlimit, STRACE_GETRLIMIT); SYSCALL(2, 0x062, "getrusage", SysGetrusage, STRACE_2); SYSCALL(1, 0x064, "times", SysTimes, STRACE_1); SYSCALL(0, 0x06F, "getpgrp", SysGetpgrp, STRACE_GETPGRP); SYSCALL(0, 0x070, "setsid", SysSetsid, STRACE_SETSID); SYSCALL(2, 0x073, "getgroups", SysGetgroups, STRACE_2); SYSCALL(1, 0x079, "getpgid", SysGetpgid, STRACE_GETPGID); SYSCALL(1, 0x07C, "getsid", SysGetsid, STRACE_1); SYSCALL(1, 0x07F, "rt_sigpending", SysSigpending, STRACE_1); SYSCALL(2, 0x089, "statfs", SysStatfs, STRACE_2); SYSCALL(2, 0x08A, "fstatfs", SysFstatfs, STRACE_2); SYSCALL(2, 0x06D, "setpgid", SysSetpgid, STRACE_2); SYSCALL(0, 0x066, "getuid", SysGetuid, STRACE_GETUID); SYSCALL(0, 0x068, "getgid", SysGetgid, STRACE_GETGID); SYSCALL(1, 0x069, "setuid", SysSetuid, STRACE_SETUID); SYSCALL(1, 0x06A, "setgid", SysSetgid, STRACE_SETGID); SYSCALL(0, 0x06B, "geteuid", SysGeteuid, STRACE_GETEUID); SYSCALL(0, 0x06C, "getegid", SysGetegid, STRACE_GETEGID); SYSCALL(0, 0x06E, "getppid", SysGetppid, STRACE_GETPPID); SYSCALL(2, 0x071, "setreuid", SysSetreuid, STRACE_SETREUID); SYSCALL(2, 0x072, "setregid", SysSetregid, STRACE_SETREGID); SYSCALL(2, 0x082, "rt_sigsuspend", SysSigsuspend, STRACE_SIGSUSPEND); SYSCALL(2, 0x083, "sigaltstack", SysSigaltstack, STRACE_2); SYSCALL(3, 0x085, "mknod", SysMknod, STRACE_3); SYSCALL(2, 0x09E, "arch_prctl", SysArchPrctl, STRACE_2); SYSCALL(2, 0x0A0, "setrlimit", SysSetrlimit, STRACE_SETRLIMIT); SYSCALL(0, 0x0A2, "sync", SysSync, STRACE_SYNC); SYSCALL(3, 0x0D9, "getdents", SysGetdents, STRACE_3); SYSCALL(1, 0x0DA, "set_tid_address", SysSetTidAddress, STRACE_1); SYSCALL(4, 0x0DD, "fadvise", SysFadvise, STRACE_4); #ifdef HAVE_CLOCK_SETTIME SYSCALL(2, 0x0E3, "clock_settime", SysClockSettime, STRACE_2); #endif SYSCALL(2, 0x0E5, "clock_getres", SysClockGetres, STRACE_2); SYSCALL(4, 0x0E6, "clock_nanosleep", SysClockNanosleep, STRACE_CLOCK_SLEEP); SYSCALL(2, 0x084, "utime", SysUtime, STRACE_2); SYSCALL(2, 0x0EB, "utimes", SysUtimes, STRACE_2); SYSCALL(3, 0x105, "futimesat", SysFutimesat, STRACE_3); SYSCALL(4, 0x118, "utimensat", SysUtimensat, STRACE_UTIMENSAT); SYSCALL(4, 0x101, "openat", SysOpenat, STRACE_OPENAT); SYSCALL(3, 0x102, "mkdirat", SysMkdirat, STRACE_MKDIRAT); SYSCALL(4, 0x106, "fstatat", SysFstatat, STRACE_FSTATAT); SYSCALL(3, 0x107, "unlinkat", SysUnlinkat, STRACE_UNLINKAT); SYSCALL(4, 0x108, "renameat", SysRenameat, STRACE_RENAMEAT); SYSCALL(5, 0x109, "linkat", SysLinkat, STRACE_LINKAT); SYSCALL(3, 0x10A, "symlinkat", SysSymlinkat, STRACE_SYMLINKAT); SYSCALL(4, 0x10B, "readlinkat", SysReadlinkat, STRACE_READLINKAT); SYSCALL(3, 0x10C, "fchmodat", SysFchmodat, STRACE_FCHMODAT); #ifndef DISABLE_SOCKETS SYSCALL(3, 0x029, "socket", SysSocket, STRACE_SOCKET); SYSCALL(3, 0x02A, "connect", SysConnect, STRACE_CONNECT); SYSCALL(3, 0x02B, "accept", SysAccept, STRACE_ACCEPT); SYSCALL(4, 0x120, "accept4", SysAccept4, STRACE_ACCEPT4); SYSCALL(6, 0x02C, "sendto", SysSendto, STRACE_SENDTO); SYSCALL(6, 0x02D, "recvfrom", SysRecvfrom, STRACE_RECVFROM); SYSCALL(3, 0x02E, "sendmsg", SysSendmsg, STRACE_3); SYSCALL(3, 0x02F, "recvmsg", SysRecvmsg, STRACE_3); #ifndef DISABLE_NONPOSIX SYSCALL(4, 0x133, "sendmmsg", SysSendmmsg, STRACE_4); SYSCALL(5, 0x12B, "recvmmsg", SysRecvmmsg, STRACE_5); #endif SYSCALL(2, 0x030, "shutdown", SysShutdown, STRACE_2); SYSCALL(3, 0x031, "bind", SysBind, STRACE_BIND); SYSCALL(2, 0x032, "listen", SysListen, STRACE_LISTEN); SYSCALL(3, 0x033, "getsockname", SysGetsockname, STRACE_GETSOCKNAME); SYSCALL(3, 0x034, "getpeername", SysGetpeername, STRACE_GETPEERNAME); SYSCALL(5, 0x036, "setsockopt", SysSetsockopt, STRACE_5); SYSCALL(5, 0x037, "getsockopt", SysGetsockopt, STRACE_5); #endif /* DISABLE_SOCKETS */ #ifdef HAVE_FORK SYSCALL(0, 0x039, "fork", SysFork, STRACE_FORK); #ifndef DISABLE_NONPOSIX SYSCALL(0, 0x03A, "vfork", SysVfork, STRACE_VFORK); #endif SYSCALL(4, 0x03D, "wait4", SysWait4, STRACE_WAIT4); SYSCALL(2, 0x03E, "kill", SysKill, STRACE_KILL); #endif /* HAVE_FORK */ #ifdef HAVE_THREADS SYSCALL(6, 0x0CA, "futex", SysFutex, STRACE_FUTEX); #endif #if defined(HAVE_FORK) || defined(HAVE_THREADS) SYSCALL(1, 0x016, "pipe", SysPipe, STRACE_PIPE); #ifndef DISABLE_NONPOSIX SYSCALL(2, 0x125, "pipe2", SysPipe2, STRACE_PIPE2); #endif SYSCALL(6, 0x038, "clone", SysClone, STRACE_CLONE); SYSCALL(2, 0x0C8, "tkill", SysTkill, STRACE_TKILL); SYSCALL(3, 0x0EA, "tgkill", SysTgkill, STRACE_3); SYSCALL(3, 0x03B, "execve", SysExecve, STRACE_3); SYSCALL(4, 0x035, "socketpair", SysSocketpair, STRACE_SOCKETPAIR); SYSCALL(2, 0x111, "set_robust_list", SysSetRobustList, STRACE_2); SYSCALL(3, 0x112, "get_robust_list", SysGetRobustList, STRACE_3); SYSCALL(2, 0x08C, "getpriority", SysGetpriority, STRACE_2); SYSCALL(3, 0x08D, "setpriority", SysSetpriority, STRACE_3); SYSCALL(2, 0x08E, "sched_set_param", SysSchedSetparam, STRACE_2); SYSCALL(2, 0x08F, "sched_get_param", SysSchedGetparam, STRACE_2); SYSCALL(3, 0x090, "sched_set_scheduler", SysSchedSetscheduler, STRACE_3); SYSCALL(1, 0x091, "sched_get_scheduler", SysSchedGetscheduler, STRACE_1); SYSCALL(1, 0x092, "sched_get_priority_max", SysSchedGetPriorityMax, STRACE_1); SYSCALL(1, 0x093, "sched_get_priority_min", SysSchedGetPriorityMin, STRACE_1); #ifndef DISABLE_NONPOSIX SYSCALL(3, 0x0CB, "sched_set_affinity", SysSchedSetaffinity, STRACE_3); #endif #endif /* defined(HAVE_FORK) || defined(HAVE_THREADS) */ #ifndef DISABLE_NONPOSIX SYSCALL(4, 0x028, "sendfile", SysSendfile, STRACE_4); SYSCALL(3, 0x0CC, "sched_get_affinity", SysSchedGetaffinity, STRACE_3); SYSCALL(1, 0x00C, "brk", SysBrk, STRACE_1); SYSCALL(1, 0x063, "sysinfo", SysSysinfo, STRACE_1); SYSCALL(2, 0x074, "setgroups", SysSetgroups, STRACE_2); SYSCALL(3, 0x075, "setresuid", SysSetresuid, STRACE_SETRESUID); SYSCALL(3, 0x076, "getresuid", SysGetresuid, STRACE_3); SYSCALL(3, 0x077, "setresgid", SysSetresgid, STRACE_SETRESGID); SYSCALL(3, 0x078, "getresgid", SysGetresgid, STRACE_3); SYSCALL(5, 0x09D, "prctl", SysPrctl, STRACE_5); #if !defined(DISABLE_OVERLAYS) || !defined(DISABLE_VFS) SYSCALL(1, 0x0A1, "chroot", SysChroot, STRACE_CHROOT); #endif #ifndef DISABLE_VFS SYSCALL(5, 0x0A5, "mount", SysMount, STRACE_MOUNT); #endif SYSCALL(3, 0x124, "dup3", SysDup3, STRACE_DUP3); SYSCALL(4, 0x103, "mknodat", SysMknodat, STRACE_4); SYSCALL(4, 0x127, "preadv", SysPreadv, STRACE_PREADV); SYSCALL(4, 0x128, "pwritev", SysPwritev, STRACE_PWRITEV); SYSCALL(4, 0x12E, "prlimit", SysPrlimit, STRACE_PRLIMIT); SYSCALL(5, 0x10F, "ppoll", SysPpoll, STRACE_5); SYSCALL(5, 0x13C, "renameat2", SysRenameat2, STRACE_RENAMEAT2); SYSCALL(3, 0x13E, "getrandom", SysGetrandom, STRACE_GETRANDOM); SYSCALL(5, 0x147, "preadv2", SysPreadv2, STRACE_PREADV2); SYSCALL(5, 0x148, "pwritev2", SysPwritev2, STRACE_PWRITEV2); SYSCALL(3, 0x1B4, "close_range", SysCloseRange, STRACE_3); #ifdef HAVE_EPOLL_PWAIT1 SYSCALL(1, 0x0D5, "epoll_create", SysEpollCreate, STRACE_1); SYSCALL(1, 0x123, "epoll_create1", SysEpollCreate1, STRACE_1); SYSCALL(4, 0x0E9, "epoll_ctl", SysEpollCtl, STRACE_4); SYSCALL(4, 0x0E8, "epoll_wait", SysEpollWait, STRACE_4); SYSCALL(6, 0x119, "epoll_pwait", SysEpollPwait, STRACE_6); SYSCALL(6, 0x1B9, "epoll_pwait2", SysEpollPwait2, STRACE_6); #endif /* HAVE_EPOLL_PWAIT1 */ #endif /* DISABLE_NONPOSIX */ case 0x3C: SYS_LOGF("%s(%#" PRIx64 ")", "exit", di); SysExit(m, di); case 0xE7: SYS_LOGF("%s(%#" PRIx64 ")", "exit_group", di); SysExitGroup(m, di); case 0x00F: SigRestore(m); m->interrupted = true; // preevnt ax clobber break; case 0x146: // avoid noisy copy_file_range() feature check in cosmo case 0x1BC: // avoid noisy landlock_create_ruleset() feature check in cosmo case 0x500: // Cosmopolitan uses this number to trigger ENOSYS for testing. if (!m->system->iscosmo) goto DefaultCase; ax = enosys(); break; case 0x0C9: // time() is also noisy in some environments. ax = SysTime(m, di); break; default: DefaultCase: LOGF("missing syscall 0x%03" PRIx64, ax); ax = enosys(); break; } if (!m->interrupted) { Put64(m->ax, ax != -1 ? ax : -(XlatErrno(errno) & 0xfff)); } unassert(--m->sysdepth >= 0); CollectPageLocks(m); unassert(!m->pagelocks.i || m->sysdepth); CollectGarbage(m, mark); m->insyscall = false; } ================================================ FILE: blink/syscall.h ================================================ #ifndef BLINK_SYSCALL_H_ #define BLINK_SYSCALL_H_ #include #include #include #include "blink/builtin.h" #include "blink/fds.h" #include "blink/machine.h" #include "blink/ndelay.h" #include "blink/types.h" #ifdef O_ASYNC #define O_ASYNC_SETFL O_ASYNC #else #define O_ASYNC_SETFL 0 #endif #ifdef O_DIRECT #define O_DIRECT_SETFL O_DIRECT #else #define O_DIRECT_SETFL 0 #endif #ifdef O_NOATIME #define O_NOATIME_SETFL O_NOATIME #else #define O_NOATIME_SETFL 0 #endif #define SETFL_FLAGS \ (O_APPEND | O_NDELAY | O_ASYNC_SETFL | O_DIRECT_SETFL | O_NOATIME_SETFL) #define INTERRUPTIBLE(restartable, x) \ do { \ int rc_; \ rc_ = (x); \ if (rc_ == -1 && errno == EINTR) { \ if (CheckInterrupt(m, restartable)) { \ break; \ } \ } else { \ break; \ } \ } while (1) #define RESTARTABLE(x) INTERRUPTIBLE(true, x) #define NORESTART(rc, x) \ do { \ if (!CheckInterrupt(m, false)) { \ INTERRUPTIBLE(false, rc = x); \ } else { \ rc = -1; \ } \ } while (0) extern char *g_blink_path; void OpSyscall(P); void SysCloseExec(struct System *); int SysClose(struct Machine *, i32); int SysCloseRange(struct Machine *, u32, u32, u32); int SysDup(struct Machine *, i32, i32, i32, i32); int SysOpenat(struct Machine *, i32, i64, i32, i32); int SysPipe2(struct Machine *, i64, i32); int SysIoctl(struct Machine *, int, u64, i64); _Noreturn void SysExitGroup(struct Machine *, int); _Noreturn void SysExit(struct Machine *, int); int GetDirFildes(int); void AddStdFd(struct Fds *, int); int GetOflags(struct Machine *, int); int GetFildes(struct Machine *, int); struct Fd *GetAndLockFd(struct Machine *, int); bool CheckInterrupt(struct Machine *, bool); int SysStatfs(struct Machine *, i64, i64); int SysFstatfs(struct Machine *, i32, i64); int mkfifoat_(int, const char *, mode_t); int mkfifo_(const char *, mode_t); void Strace(struct Machine *, const char *, bool, const char *, ...); #ifndef HAVE_MKFIFOAT #ifdef mkfifoat #undef mkfifoat #endif #define mkfifoat mkfifoat_ #endif #ifndef HAVE_MKFIFO #ifdef mkfifo #undef mkfifo #endif #define mkfifo mkfifo_ #endif #endif /* BLINK_SYSCALL_H_ */ ================================================ FILE: blink/sysinfo.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include "blink/builtin.h" #include "blink/endian.h" #include "blink/linux.h" #include "blink/macros.h" #include "blink/timespec.h" #include "blink/types.h" #ifdef HAVE_SYSINFO #include #endif #ifdef HAVE_SYSCTL #include #endif #ifdef HAVE_SYSCTL static i64 GetUptime(void) { struct timeval x; size_t n = sizeof(x); int mib[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return 0; return GetTime().tv_sec - x.tv_sec; } static i64 GetPhysmem(void) { u64 x = 0; size_t n = sizeof(x); int mib[] = { CTL_HW, #ifdef HW_MEMSIZE HW_MEMSIZE, // u64 version of HW_PHYSMEM on Apple platforms #else HW_PHYSMEM, #endif }; if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return 0; return x; } #endif /* HAVE_SYSCTL */ int sysinfo_linux(struct sysinfo_linux *si) { memset(si, 0, sizeof(*si)); #ifdef HAVE_SYSINFO struct sysinfo syssi; if (sysinfo(&syssi) == -1) return -1; Write64(si->uptime, syssi.uptime); Write64(si->loads[0], syssi.loads[0]); Write64(si->loads[1], syssi.loads[1]); Write64(si->loads[2], syssi.loads[2]); Write64(si->totalram, syssi.totalram); Write64(si->freeram, syssi.freeram); Write64(si->sharedram, syssi.sharedram); Write64(si->bufferram, syssi.bufferram); Write64(si->totalswap, syssi.totalswap); Write64(si->freeswap, syssi.freeswap); Write16(si->procs, syssi.procs); Write64(si->totalhigh, syssi.totalhigh); Write64(si->freehigh, syssi.freehigh); Write32(si->mem_unit, syssi.mem_unit); #elif defined(HAVE_SYSCTL) Write64(si->uptime, GetUptime()); Write64(si->totalram, GetPhysmem()); Write16(si->procs, 1); Write32(si->mem_unit, 1); #else Write64(si->totalram, 1 * 1024 * 1024 * 1024); Write16(si->procs, 1); Write32(si->mem_unit, 1); #endif return 0; } ================================================ FILE: blink/tainted.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #ifdef __linux #include #endif #include "blink/util.h" long IsProcessTainted(void) { #if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__APPLE__) || defined(__COSMOPOLITAN__)) && \ !defined(_POSIX_C_SOURCE) return issetugid(); #elif defined(__linux) && !defined(_POSIX_C_SOURCE) return getauxval(AT_SECURE); #else return 0; #endif } ================================================ FILE: blink/thompike.h ================================================ #ifndef BLINK_THOMPIKE_H_ #define BLINK_THOMPIKE_H_ #include "blink/bitscan.h" #define ThomPikeCont(x) (((x)&0300) == 0200) #define ThomPikeByte(x) ((x) & (((1 << ThomPikeMsb(x)) - 1) | 3)) #define ThomPikeLen(x) (7 - ThomPikeMsb(x)) #define ThomPikeMsb(x) (((x)&0xff) < 252 ? bsr(~(x)&0xff) : 1) #define ThomPikeMerge(x, y) ((x) << 6 | ((y)&077)) #endif /* BLINK_THOMPIKE_H_ */ ================================================ FILE: blink/thread.h ================================================ #ifndef BLINK_LOCK_H_ #define BLINK_LOCK_H_ #include "blink/builtin.h" #ifndef DISABLE_THREADS #define HAVE_THREADS #include #include "blink/assert.h" #include "blink/log.h" #define LOCK(x) unassert(!pthread_mutex_lock(x)) #define UNLOCK(x) unassert(!pthread_mutex_unlock(x)) #ifdef __HAIKU__ #include #undef UNLOCK #define UNLOCK(x) \ do { \ (x)->owner = find_thread(NULL); \ unassert(!pthread_mutex_unlock(x)); \ } while (0) #endif #define PTHREAD_ONCE_INIT_ PTHREAD_ONCE_INIT #define PTHREAD_MUTEX_INITIALIZER_ PTHREAD_MUTEX_INITIALIZER #define pthread_once_ pthread_once #define pthread_once_t_ pthread_once_t #define pthread_cond_t_ pthread_cond_t #define pthread_mutex_t_ pthread_mutex_t #define pthread_condattr_t_ pthread_condattr_t #define pthread_mutexattr_t_ pthread_mutexattr_t #else /* HAVE_THREADS */ #include #ifdef _Thread_local #undef _Thread_local #endif #define _Thread_local #define LOCK(x) (void)0 #define UNLOCK(x) (void)0 #define PTHREAD_ONCE_INIT_ 0 #define PTHREAD_MUTEX_INITIALIZER_ 0 #define pthread_once_t_ char #define pthread_cond_t_ char #define pthread_mutex_t_ char #define pthread_condattr_t_ char #define pthread_mutexattr_t_ char #define pthread_self() 0 #define pthread_sigmask(x, y, z) sigprocmask(x, y, z) #define pthread_setcancelstate(x, y) ((void)(y), 0) #define pthread_mutex_init(x, y) ((void)(y), 0) #define pthread_mutex_destroy(x) 0 #define pthread_cond_init(x, y) ((void)(y), 0) #define pthread_cond_wait(x, y) 0 #define pthread_cond_signal(x) 0 #define pthread_cond_broadcast(x) 0 #define pthread_cond_timedwait(x, y, z) ((void)(z), 0) #define pthread_cond_destroy(x) 0 #define pthread_condattr_init(x) 0 #define pthread_condattr_setpshared(x, y) 0 #define pthread_condattr_destroy(x) 0 #define pthread_mutexattr_init(x) 0 #define pthread_mutexattr_setpshared(x, y) 0 #define pthread_mutexattr_destroy(x) 0 #define pthread_mutexattr_settype(x, y) 0 #define pthread_atfork(a, b, c) 0 #define pthread_create(a, b, c, d) 0 #define pthread_join(a, b) 0 static inline int pthread_once_(pthread_once_t_ *once_control, void (*init_routine)(void)) { if (!*once_control) { init_routine(); *once_control = 1; } return 0; } #endif /* DISABLE_THREADS */ #endif /* BLINK_LOCK_H_ */ ================================================ FILE: blink/throw.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include "blink/assert.h" #include "blink/debug.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/signal.h" void RestoreIp(struct Machine *m) { if (m) { m->ip -= m->oplen; m->oplen = 0; } } void DeliverSignalToUser(struct Machine *m, int sig, int code) { if (m->sigmask & ((u64)1 << (sig - 1))) { TerminateSignal(m, sig, code); } LOCK(&m->system->sig_lock); switch (Read64(m->system->hands[sig - 1].handler)) { case SIG_IGN_LINUX: case SIG_DFL_LINUX: UNLOCK(&m->system->sig_lock); TerminateSignal(m, sig, code); return; default: DeliverSignal(m, sig, code); break; } UNLOCK(&m->system->sig_lock); if ((sig = ConsumeSignal(m, 0, 0))) { TerminateSignal(m, sig, code); } } void HaltMachine(struct Machine *m, int code) { SIG_LOGF("HaltMachine(%d) at %#" PRIx64, code, m->ip); switch ((m->trapno = code)) { case kMachineDivideError: RestoreIp(m); m->faultaddr = m->ip; DeliverSignalToUser(m, SIGFPE_LINUX, FPE_INTDIV_LINUX); break; case kMachineFpuException: case kMachineSimdException: RestoreIp(m); m->faultaddr = m->ip; DeliverSignalToUser(m, SIGFPE_LINUX, FPE_FLTINV_LINUX); break; case kMachineHalt: case kMachineDecodeError: case kMachineUndefinedInstruction: RestoreIp(m); m->faultaddr = m->ip; DeliverSignalToUser(m, SIGILL_LINUX, ILL_ILLOPC_LINUX); break; case kMachineProtectionFault: RestoreIp(m); m->faultaddr = m->ip; DeliverSignalToUser(m, SIGILL_LINUX, ILL_PRVOPC_LINUX); break; case kMachineSegmentationFault: RestoreIp(m); DeliverSignalToUser(m, SIGSEGV_LINUX, m->segvcode ? m->segvcode : SEGV_MAPERR_LINUX); break; case 1: case 3: m->faultaddr = m->ip - m->oplen; DeliverSignalToUser(m, SIGTRAP_LINUX, SI_KERNEL_LINUX); break; case 4: m->faultaddr = 0; DeliverSignalToUser(m, SIGSEGV_LINUX, SI_KERNEL_LINUX); break; case kMachineExitTrap: RestoreIp(m); break; default: if (code >= 0) { if (!m->metal) { RestoreIp(m); m->faultaddr = 0; DeliverSignalToUser(m, SIGSEGV_LINUX, SI_KERNEL_LINUX); } } else { unassert(!"not possible"); } } unassert(m->canhalt); siglongjmp(m->onhalt, code); } void RaiseDivideError(struct Machine *m) { HaltMachine(m, kMachineDivideError); } void ThrowProtectionFault(struct Machine *m) { HaltMachine(m, kMachineProtectionFault); } void ThrowSegmentationFault(struct Machine *m, i64 va) { RestoreIp(m); m->faultaddr = va; HaltMachine(m, kMachineSegmentationFault); } void OpUdImpl(struct Machine *m) { RestoreIp(m); HaltMachine(m, kMachineUndefinedInstruction); } void OpUd(P) { OpUdImpl(m); } void OpHlt(P) { if (Cpl(m) == 0 && GetFlag(m->flags, FLAGS_IF)) { sched_yield(); } else { HaltMachine(m, kMachineHalt); } } ================================================ FILE: blink/time.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/time.h" #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/jit.h" #include "blink/machine.h" #include "blink/modrm.h" #ifdef HAVE_SCHED_H #include #endif void OpPause(P) { #if defined(__GNUC__) && defined(__aarch64__) && !defined(__FILC__) asm volatile("yield"); #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) && \ !defined(__FILC__) asm volatile("pause"); #elif defined(HAVE_SCHED_YIELD) sched_yield(); #endif if (IsMakingPath(m)) { AppendJitPause(m->path.jb); } } void OpRdtsc(P) { u64 c; if (m->traprdtsc) { ThrowSegmentationFault(m, 0); } #if defined(__GNUC__) && defined(__aarch64__) && !defined(__FILC__) asm volatile("mrs %0, cntvct_el0" : "=r"(c)); c *= 48; // the fudge factor #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) && \ !defined(__FILC__) u32 ax, dx; asm volatile("rdtsc" : "=a"(ax), "=d"(dx)); c = (u64)dx << 32 | ax; #else struct timespec ts; unassert(!clock_gettime(CLOCK_MONOTONIC, &ts)); c = ts.tv_sec; c *= 1000000000; c += ts.tv_nsec; c *= 3; // the fudge factor #endif Put64(m->ax, (c & 0x00000000ffffffff) >> 000); Put64(m->dx, (c & 0xffffffff00000000) >> 040); } static i64 GetTscAux(struct Machine *m) { u32 core, node; core = 0; node = 0; return (node & 0xfff) << 12 | (core & 0xfff); } void OpRdtscp(P) { OpRdtsc(A); Put64(m->cx, GetTscAux(m)); } void OpRdpid(P) { Put64(RegRexbRm(m, rde), GetTscAux(m)); } ================================================ FILE: blink/time.h ================================================ #ifndef BLINK_TIME_H_ #define BLINK_TIME_H_ #include "blink/machine.h" void OpPause(P); void OpRdtsc(P); void OpRdtscp(P); void OpRdpid(P); #endif /* BLINK_TIME_H_ */ ================================================ FILE: blink/timespec.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/timespec.h" int CompareTime(struct timespec a, struct timespec b) { int cmp; if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) { cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec); } return cmp; } struct timespec AddTime(struct timespec x, struct timespec y) { x.tv_sec += y.tv_sec; x.tv_nsec += y.tv_nsec; if (x.tv_nsec >= 1000000000) { x.tv_nsec -= 1000000000; x.tv_sec += 1; } return x; } struct timespec SubtractTime(struct timespec a, struct timespec b) { a.tv_sec -= b.tv_sec; if (a.tv_nsec < b.tv_nsec) { a.tv_nsec += 1000000000; a.tv_sec--; } a.tv_nsec -= b.tv_nsec; return a; } ================================================ FILE: blink/timespec.h ================================================ #ifndef BLINK_TIMESPEC_H_ #define BLINK_TIMESPEC_H_ #include #include #include "blink/assert.h" #include "blink/limits.h" static inline struct timespec GetTime(void) { struct timespec ts; unassert(!clock_gettime(CLOCK_REALTIME, &ts)); return ts; } static inline struct timespec GetMonotonic(void) { struct timespec ts; unassert(!clock_gettime(CLOCK_MONOTONIC, &ts)); return ts; } static inline struct timespec GetMaxTime(void) { struct timespec ts; ts.tv_sec = NUMERIC_MAX(time_t); ts.tv_nsec = 999999999; return ts; } static inline struct timespec GetZeroTime(void) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 0; return ts; } static inline struct timespec FromSeconds(time_t x) { struct timespec ts; ts.tv_sec = x; ts.tv_nsec = 0; return ts; } static inline struct timespec FromMilliseconds(time_t x) { struct timespec ts; ts.tv_sec = x / 1000; ts.tv_nsec = x % 1000 * 1000000; return ts; } static inline struct timespec FromMicroseconds(time_t x) { struct timespec ts; ts.tv_sec = x / 1000000; ts.tv_nsec = x % 1000000 * 1000; return ts; } static inline struct timespec FromNanoseconds(time_t x) { struct timespec ts; ts.tv_sec = x / 1000000000; ts.tv_nsec = x % 1000000000; return ts; } static inline struct timespec SleepTime(struct timespec dur) { struct timespec unslept; if (!nanosleep(&dur, &unslept)) { unslept.tv_sec = 0; unslept.tv_nsec = 0; } else { unassert(errno == EINTR); } return unslept; } static inline int ConvertTimeToInt(time_t x) { if (x > INT_MAX) return INT_MAX; return x; } static inline time_t ToSeconds(struct timespec ts) { unassert(ts.tv_nsec < 1000000000); if (ts.tv_sec < NUMERIC_MAX(time_t)) { if (ts.tv_nsec) { ts.tv_sec += 1; } return ts.tv_sec; } else { return NUMERIC_MAX(time_t); } } static inline time_t ToMilliseconds(struct timespec ts) { unassert(ts.tv_nsec < 1000000000); if (ts.tv_sec < NUMERIC_MAX(time_t) / 1000 - 999) { if (ts.tv_nsec <= 999000000) { ts.tv_nsec = (ts.tv_nsec + 999999) / 1000000; } else { ts.tv_sec += 1; ts.tv_nsec = 0; } return ts.tv_sec * 1000 + ts.tv_nsec; } else { return NUMERIC_MAX(time_t); } } static inline time_t ToMicroseconds(struct timespec ts) { unassert(ts.tv_nsec < 1000000000); if (ts.tv_sec < NUMERIC_MAX(time_t) / 1000000 - 999999) { if (ts.tv_nsec <= 999999000) { ts.tv_nsec = (ts.tv_nsec + 999) / 1000; } else { ts.tv_sec += 1; ts.tv_nsec = 0; } return ts.tv_sec * 1000000 + ts.tv_nsec; } else { return NUMERIC_MAX(time_t); } } static inline time_t ToNanoseconds(struct timespec ts) { unassert(ts.tv_nsec < 1000000000); if (ts.tv_sec < NUMERIC_MAX(time_t) / 1000000000 - 999999999) { return ts.tv_sec * 1000000000 + ts.tv_nsec; } else { return NUMERIC_MAX(time_t); } } int CompareTime(struct timespec, struct timespec); struct timespec AddTime(struct timespec, struct timespec); struct timespec SubtractTime(struct timespec, struct timespec); #endif /* BLINK_TIMESPEC_H_ */ ================================================ FILE: blink/tpenc.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/bitscan.h" #include "blink/util.h" static const u16 kTpEnc[32 - 7] = { 1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, }; u64 tpenc(uint32_t c) { int e, n; u64 w; if (0 <= c && c <= 127) return c; e = kTpEnc[bsr(c) - 7]; n = e & 0xff; w = 0; do { w |= 0200 | (c & 077); w <<= 8; c >>= 6; } while (--n); return c | w | e >> 8; } ================================================ FILE: blink/tsan.h ================================================ #ifndef TSAN_H_ #define TSAN_H_ // Thread Safety Analysis, complements of Google #include "blink/builtin.h" #if defined(__cplusplus) && defined(__clang__) #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) #else #define THREAD_ANNOTATION_ATTRIBUTE__(x) #endif // GUARDED_BY() // // Documents if a shared field or global variable needs to be protected by a // mutex. GUARDED_BY() allows the user to specify a particular mutex that // should be held when accessing the annotated variable. // // Example: // // Mutex mu; // int p1 GUARDED_BY(mu); #define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) // PT_GUARDED_BY() // // Documents if the memory location pointed to by a pointer should be guarded // by a mutex when dereferencing the pointer. // // Example: // Mutex mu; // int *p1 PT_GUARDED_BY(mu); // // Note that a pointer variable to a shared memory location could itself be a // shared variable. // // Example: // // // `q`, guarded by `mu1`, points to a shared memory location that is // // guarded by `mu2`: // int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2); #define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) // ACQUIRED_AFTER() / ACQUIRED_BEFORE() // // Documents the acquisition order between locks that can be held // simultaneously by a thread. For any two locks that need to be annotated // to establish an acquisition order, only one of them needs the annotation. // (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER // and ACQUIRED_BEFORE.) // // Example: // // Mutex m1; // Mutex m2 ACQUIRED_AFTER(m1); #define ACQUIRED_AFTER(...) \ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) #define ACQUIRED_BEFORE(...) \ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) // EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED() // // Documents a function that expects a mutex to be held prior to entry. // The mutex is expected to be held both on entry to, and exit from, the // function. // // Example: // // Mutex mu1, mu2; // int a GUARDED_BY(mu1); // int b GUARDED_BY(mu2); // // void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }; #define EXCLUSIVE_LOCKS_REQUIRED(...) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) #define SHARED_LOCKS_REQUIRED(...) \ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) // LOCKS_EXCLUDED() // // Documents the locks acquired in the body of the function. These locks // cannot be held when calling this function (as Abseil's `Mutex` locks are // non-reentrant). #define LOCKS_EXCLUDED(...) \ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) // LOCK_RETURNED() // // Documents a function that returns a mutex without acquiring it. For example, // a public getter method that returns a pointer to a private mutex should // be annotated with LOCK_RETURNED. #define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) // LOCKABLE // // Documents if a class/type is a lockable type (such as the `Mutex` class). #define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable) // SCOPED_LOCKABLE // // Documents if a class does RAII locking (such as the `MutexLock` class). // The constructor should use `LOCK_FUNCTION()` to specify the mutex that is // acquired, and the destructor should use `UNLOCK_FUNCTION()` with no // arguments; the analysis will assume that the destructor unlocks whatever the // constructor locked. #define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) // EXCLUSIVE_LOCK_FUNCTION() // // Documents functions that acquire a lock in the body of a function, and do // not release it. #define EXCLUSIVE_LOCK_FUNCTION(...) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) // SHARED_LOCK_FUNCTION() // // Documents functions that acquire a shared (reader) lock in the body of a // function, and do not release it. #define SHARED_LOCK_FUNCTION(...) \ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) // UNLOCK_FUNCTION() // // Documents functions that expect a lock to be held on entry to the function, // and release it in the body of the function. #define UNLOCK_FUNCTION(...) \ THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) // EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION() // // Documents functions that try to acquire a lock, and return success or failure // (or a non-boolean value that can be interpreted as a boolean). // The first argument should be `true` for functions that return `true` on // success, or `false` for functions that return `false` on success. The second // argument specifies the mutex that is locked on success. If unspecified, this // mutex is assumed to be `this`. #define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) #define SHARED_TRYLOCK_FUNCTION(...) \ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) // ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK() // // Documents functions that dynamically check to see if a lock is held, and fail // if it is not held. #define ASSERT_EXCLUSIVE_LOCK(...) \ THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) #define ASSERT_SHARED_LOCK(...) \ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) // NO_THREAD_SAFETY_ANALYSIS // // Turns off thread safety checking within the body of a particular function. // This annotation is used to mark functions that are known to be correct, but // the locking behavior is more complicated than the analyzer can handle. #define NO_THREAD_SAFETY_ANALYSIS \ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) #ifdef __SANITIZE_THREAD__ #ifdef __cplusplus extern "C" { #endif void AnnotateIgnoreWritesBegin(const char *file, int line); void AnnotateIgnoreWritesEnd(const char *file, int line); void AnnotateIgnoreReadsBegin(const char *file, int line); void AnnotateIgnoreReadsEnd(const char *file, int line); #ifdef __cplusplus } #endif #define IGNORE_RACES_START() \ do { \ AnnotateIgnoreReadsBegin(__FILE__, __LINE__); \ AnnotateIgnoreWritesBegin(__FILE__, __LINE__); \ } while (0) #define IGNORE_RACES_END() \ do { \ AnnotateIgnoreWritesEnd(__FILE__, __LINE__); \ AnnotateIgnoreReadsEnd(__FILE__, __LINE__); \ } while (0) #else #define IGNORE_RACES_START() #define IGNORE_RACES_END() #endif #endif /* TSAN_H_ */ ================================================ FILE: blink/tunables.h ================================================ #ifndef BLINK_TUNABLES_H_ #define BLINK_TUNABLES_H_ #include #include "blink/builtin.h" #define BLINK_MAJOR 1 #define BLINK_MINOR 1 #define BLINK_PATCH 0 #define LINUX_MAJOR 4 #define LINUX_MINOR 5 #define LINUX_PATCH 0 #define MKVERSION_(x, y, z) #x "." #y "." #z #define MKVERSION(x, y, z) MKVERSION_(x, y, z) #define LINUX_VERSION MKVERSION(LINUX_MAJOR, LINUX_MINOR, LINUX_PATCH) #define BLINK_VERSION MKVERSION(BLINK_MAJOR, BLINK_MINOR, BLINK_PATCH) #if CAN_64BIT && defined(__APPLE__) #define kSkew 0x088800000000 #else #define kSkew 0x000000000000 #endif #define kAslrMask 0x03ffff000000 // 16mb before pointers get nasty #define kImageStart 0x110001000000 #define kAutomapStart 0x200000000000 #define kAutomapEnd 0x400000000000 #define kDynInterpAddr 0x454000000000 #define kStackTop 0x500000000000 #define kRealSize (16 * 1024 * 1024) // size of ram for real mode #define kStackSize (8 * 1024 * 1024) // size of stack for user mode #define kNullSize (2 * 1024 * 1024) // minimum user mode image address #define kMinBlinkFd 123 // fds owned by the vm start here #define kPollingMs 50 // busy loop for futex(), poll(), etc. #define kBusCount 256 // # load balanced semaphores in virtual bus #define kBusRegion 128 // 16 is sufficient for 8-byte loads/stores #define kFutexMax 100 #define kRedzoneSize 128 #define kSmcQueueSize 32 #define kMaxMapSize (UINT64_C(8) * 1024 * 1024 * 1024) #define kMaxResident (UINT64_C(8) * 1024 * 1024 * 1024) #define kMaxVirtual (kMaxResident * 8) #define kMaxAncillary 1000 #define kMaxShebang 512 #define kMaxSigDepth 8 #define kStraceArgMax 256 #define kStraceBufMax 32 #endif /* BLINK_TUNABLES_H_ */ ================================================ FILE: blink/types.h ================================================ #ifndef BLINK_TYPES_H_ #define BLINK_TYPES_H_ #include typedef int8_t i8; typedef uint8_t u8; typedef int16_t i16; typedef uint16_t u16; typedef int32_t i32; typedef uint32_t u32; typedef int64_t i64; typedef uint64_t u64; #endif /* BLINK_TYPES_H_ */ ================================================ FILE: blink/uart.h ================================================ #ifndef BLINK_UART_H_ #define BLINK_UART_H_ #define UART_DLAB (1 << 7) /* serial line conf mode bit */ #define UART_DLL 0 /* divisor latch register */ #define UART_DLM 1 /* divisor latch register */ #define UART_IIR 2 /* interrupt identification register */ #define UART_LCR 3 /* line control register */ #define UART_MCR 4 /* modem control register */ #define UART_LSR 5 /* line status register */ #define UART_TTYDA (1 << 0) /* data available (rx ready) */ #define UART_TTYOE (1 << 1) /* overrun error */ #define UART_TTYPE (1 << 2) /* parity error */ #define UART_TTYFE (1 << 3) /* framing error */ #define UART_TTYBSR (1 << 4) /* break signal received */ #define UART_TTYTXR (1 << 5) /* serial thr empty (tx ready) */ #define UART_TTYIDL (1 << 6) /* serial thr empty and line idle */ #define UART_TTYEDF (1 << 7) /* erroneous data in fifo */ #endif /* BLINK_UART_H_ */ ================================================ FILE: blink/uop.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/alu.h" #include "blink/assert.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/flags.h" #include "blink/intrin.h" #include "blink/jit.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/pun.h" #include "blink/rde.h" #include "blink/stats.h" #include "blink/swap.h" #include "blink/thread.h" #include "blink/types.h" #include "blink/x86.h" #include "blink/xmm.h" /** * @fileoverview X86 Micro-Operations w/ Printf RPN Glue-Generating DSL. */ #define kMaxOps 256 //////////////////////////////////////////////////////////////////////////////// // ESSENTIAL MICRO_OP static void Sax64(P) { Put64(m->ax, (i32)Get32(m->ax)); } MICRO_OP static void Sax32(P) { Put64(m->ax, (u32)(i16)Get16(m->ax)); } MICRO_OP static void Sax16(P) { Put16(m->ax, (i8)Get8(m->ax)); } const nexgen32e_f kSax[] = {Sax16, Sax32, Sax64}; MICRO_OP i64 Not8(struct Machine *m, u64 x, u64 y) { return ~x & 0xFF; } MICRO_OP i64 Not16(struct Machine *m, u64 x, u64 y) { return ~x & 0xFFFF; } MICRO_OP i64 Not32(struct Machine *m, u64 x, u64 y) { return ~x & 0xFFFFFFFF; } MICRO_OP i64 Not64(struct Machine *m, u64 x, u64 y) { return ~x & 0xFFFFFFFFFFFFFFFF; } MICRO_OP static void Convert64(P) { Put64(m->dx, Get64(m->ax) & 0x8000000000000000 ? 0xffffffffffffffff : 0); } MICRO_OP static void Convert32(P) { Put64(m->dx, Get32(m->ax) & 0x80000000 ? 0xffffffff : 0); } MICRO_OP static void Convert16(P) { Put16(m->dx, Get16(m->ax) & 0x8000 ? 0xffff : 0); } const nexgen32e_f kConvert[] = {Convert16, Convert32, Convert64}; #ifndef DISABLE_BMI2 #if X86_INTRINSICS MICRO_OP i64 Adcx32(u64 x, u64 y, struct Machine *m) { u32 z; _Static_assert(CF == 1, ""); asm("btr\t$0,%1\n\t" "adc\t%3,%0\n\t" "adc\t$0,%1" : "=&r" (z), "+&g" (m->flags) : "%0" ((u32)x), "g" ((u32)y) : "cc"); return z; } MICRO_OP i64 Adcx64(u64 x, u64 y, struct Machine *m) { u64 z; _Static_assert(CF == 1, ""); asm("btr\t$0,%1\n\t" "adc\t%3,%0\n\t" "adc\t$0,%1" : "=&r" (z), "+&g" (m->flags) : "%0" (x), "g" (y) : "cc"); return z; } MICRO_OP i64 Adox32(u64 x, u64 y, struct Machine *m) { u32 z, t; asm("btr\t%5,%1\n\t" "adc\t%4,%0\n\t" "sbb\t%2,%2\n\t" "and\t%6,%2\n\t" "or\t%2,%1" : "=&r" (z), "+&g" (m->flags), "=&r" (t) : "%0" ((u32)x), "g" ((u32)y), "i" (FLAGS_OF), "i" (OF) : "cc"); return z; } MICRO_OP i64 Adox64(u64 x, u64 y, struct Machine *m) { u64 z; u32 t; asm("btr\t%5,%1\n\t" "adc\t%4,%0\n\t" "sbb\t%2,%2\n\t" "and\t%6,%2\n\t" "or\t%2,%1" : "=&r" (z), "+&g" (m->flags), "=&r" (t) : "%0" (x), "g" (y), "i" (FLAGS_OF), "i" (OF) : "cc"); return z; } #elif ARM_INTRINSICS /* !X86_INTRINSICS */ MICRO_OP i64 Adcx32(u64 x, u64 y, struct Machine *m) { u64 f = m->flags, z; _Static_assert(CF == 1, ""); asm("ror\t%1,%1,#1\n\t" "adds\t%1,%1,%1\n\t" "adcs\t%w0,%w2,%w3\n\t" "adc\t%1,%1,xzr" : "=&r" (z), "+&r" (f) : "%0" (x), "r" (y) : "cc"); m->flags = f; return z; } MICRO_OP i64 Adcx64(u64 x, u64 y, struct Machine *m) { u64 f = m->flags, z; _Static_assert(CF == 1, ""); asm("ror\t%1,%1,#1\n\t" "adds\t%1,%1,%1\n\t" "adcs\t%0,%2,%3\n\t" "adc\t%1,%1,xzr" : "=&r" (z), "+&r" (f) : "%0" (x), "r" (y) : "cc"); m->flags = f; return z; } MICRO_OP i64 Adox32(u64 x, u64 y, struct Machine *m) { u64 f = m->flags, z; asm("ror\t%1,%1,%4\n\t" "adds\t%1,%1,%1\n\t" "adcs\t%w0,%w2,%w3\n\t" "adc\t%1,%1,xzr\n\t" "ror\t%1,%1,%5" : "=&r" (z), "+&r" (f) : "%0" (x), "r" (y), "i" (FLAGS_OF + 1), "i" (64 - FLAGS_OF) : "cc"); m->flags = f; return z; } MICRO_OP i64 Adox64(u64 x, u64 y, struct Machine *m) { u64 f = m->flags, z; asm("ror\t%1,%1,%4\n\t" "adds\t%1,%1,%1\n\t" "adcs\t%0,%2,%3\n\t" "adc\t%1,%1,xzr\n\t" "ror\t%1,%1,%5" : "=&r" (z), "+&r" (f) : "%0" (x), "r" (y), "i" (FLAGS_OF + 1), "i" (64 - FLAGS_OF) : "cc"); m->flags = f; return z; } #else /* !ARM_INTRINSICS */ MICRO_OP i64 Adcx32(u64 x, u64 y, struct Machine *m) { u32 t = x + !!(m->flags & CF); u32 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~CF) | c << FLAGS_CF; return z; } MICRO_OP i64 Adcx64(u64 x, u64 y, struct Machine *m) { u64 t = x + !!(m->flags & CF); u64 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~CF) | c << FLAGS_CF; return z; } MICRO_OP i64 Adox32(u64 x, u64 y, struct Machine *m) { u32 t = x + !!(m->flags & OF); u32 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~OF) | c << FLAGS_OF; return z; } MICRO_OP i64 Adox64(u64 x, u64 y, struct Machine *m) { u64 t = x + !!(m->flags & OF); u64 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~OF) | c << FLAGS_OF; return z; } #endif /* !ARM_INTRINSICS */ #endif /* !DISABLE_BMI2 */ //////////////////////////////////////////////////////////////////////////////// // BRANCHING MICRO_OP void FastJmp(struct Machine *m, u64 disp) { m->ip += disp; } MICRO_OP void FastJmpAbs(u64 addr, struct Machine *m) { m->ip = addr; } MICRO_OP static u32 Jb(struct Machine *m) { return !!(m->flags & CF); } MICRO_OP static u32 Jae(struct Machine *m) { return !!(~m->flags & CF); } MICRO_OP static u32 Je(struct Machine *m) { return !!(m->flags & ZF); } MICRO_OP static u32 Jne(struct Machine *m) { return !!(~m->flags & ZF); } MICRO_OP static u32 Js(struct Machine *m) { return !!(m->flags & SF); } MICRO_OP static u32 Jns(struct Machine *m) { return !!(~m->flags & SF); } MICRO_OP static u32 Jo(struct Machine *m) { return !!(m->flags & OF); } MICRO_OP static u32 Jno(struct Machine *m) { return !!(~m->flags & OF); } MICRO_OP static u32 Ja(struct Machine *m) { return IsAbove(m); } MICRO_OP static u32 Jbe(struct Machine *m) { return IsBelowOrEqual(m); } MICRO_OP static u32 Jg(struct Machine *m) { return IsGreater(m); } MICRO_OP static u32 Jge(struct Machine *m) { return IsGreaterOrEqual(m); } MICRO_OP static u32 Jl(struct Machine *m) { return IsLess(m); } MICRO_OP static u32 Jle(struct Machine *m) { return IsLessOrEqual(m); } const cc_f kConditionCode[16] = { Jo, // Jno, // Jb, // Jae, // Je, // Jne, // Jbe, // Ja, // Js, // Jns, // 0, // 0, // Jl, // Jge, // Jle, // Jg, // }; MICRO_OP u64 Pick(u32 p, u64 x, u64 y) { return p ? x : y; } //////////////////////////////////////////////////////////////////////////////// // FLOATING POINT MICRO_OP void OpPsdMuls1(u8 *p, struct Machine *m, long reg) { union FloatPun x, y; y.i = Read32(p); x.i = Read32(m->xmm[reg]); x.f = x.f * y.f; Write32(m->xmm[reg], x.i); } MICRO_OP void OpPsdMuld1(u8 *p, struct Machine *m, long reg) { union DoublePun x, y; y.i = Read64(p); x.i = Read64(m->xmm[reg]); x.f = x.f * y.f; Write64(m->xmm[reg], x.i); } MICRO_OP void OpPsdAdds1(u8 *p, struct Machine *m, long reg) { union FloatPun x, y; y.i = Read32(p); x.i = Read32(m->xmm[reg]); x.f = x.f + y.f; Write32(m->xmm[reg], x.i); } MICRO_OP void OpPsdAddd1(u8 *p, struct Machine *m, long reg) { union DoublePun x, y; y.i = Read64(p); x.i = Read64(m->xmm[reg]); x.f = x.f + y.f; Write64(m->xmm[reg], x.i); } MICRO_OP void OpPsdSubs1(u8 *p, struct Machine *m, long reg) { union FloatPun x, y; y.i = Read32(p); x.i = Read32(m->xmm[reg]); x.f = x.f - y.f; Write32(m->xmm[reg], x.i); } MICRO_OP void OpPsdSubd1(u8 *p, struct Machine *m, long reg) { union DoublePun x, y; y.i = Read64(p); x.i = Read64(m->xmm[reg]); x.f = x.f - y.f; Write64(m->xmm[reg], x.i); } MICRO_OP void OpPsdDivs1(u8 *p, struct Machine *m, long reg) { union FloatPun x, y; y.i = Read32(p); x.i = Read32(m->xmm[reg]); x.f = x.f / y.f; Write32(m->xmm[reg], x.i); } MICRO_OP void OpPsdDivd1(u8 *p, struct Machine *m, long reg) { union DoublePun x, y; y.i = Read64(p); x.i = Read64(m->xmm[reg]); x.f = x.f / y.f; Write64(m->xmm[reg], x.i); } MICRO_OP void OpPsdMins1(u8 *p, struct Machine *m, long reg) { union FloatPun x, y; y.i = Read32(p); x.i = Read32(m->xmm[reg]); x.f = MIN(x.f, y.f); Write32(m->xmm[reg], x.i); } MICRO_OP void OpPsdMind1(u8 *p, struct Machine *m, long reg) { union DoublePun x, y; y.i = Read64(p); x.i = Read64(m->xmm[reg]); x.f = MIN(x.f, y.f); Write64(m->xmm[reg], x.i); } MICRO_OP void OpPsdMaxs1(u8 *p, struct Machine *m, long reg) { union FloatPun x, y; y.i = Read32(p); x.i = Read32(m->xmm[reg]); x.f = MAX(x.f, y.f); Write32(m->xmm[reg], x.i); } MICRO_OP void OpPsdMaxd1(u8 *p, struct Machine *m, long reg) { union DoublePun x, y; y.i = Read64(p); x.i = Read64(m->xmm[reg]); x.f = MAX(x.f, y.f); Write64(m->xmm[reg], x.i); } MICRO_OP void Int64ToDouble(i64 x, struct Machine *m, long reg) { union DoublePun d; d.f = x; Put64(m->xmm[reg], d.i); } MICRO_OP void Int32ToDouble(i32 x, struct Machine *m, long reg) { union DoublePun d; d.f = x; Put64(m->xmm[reg], d.i); } MICRO_OP void Int64ToFloat(i64 x, struct Machine *m, long reg) { union FloatPun d; d.f = x; Put32(m->xmm[reg], d.i); } MICRO_OP void Int32ToFloat(i32 x, struct Machine *m, long reg) { union FloatPun d; d.f = x; Put32(m->xmm[reg], d.i); } #ifdef HAVE_JIT //////////////////////////////////////////////////////////////////////////////// // ACCOUNTING MICRO_OP void CountOp(long *instructions_jitted_ptr) { STATISTIC(++*instructions_jitted_ptr); } //////////////////////////////////////////////////////////////////////////////// // PROGRAM COUNTER MICRO_OP void AddIp(struct Machine *m, long oplen) { m->oplen = oplen; m->ip += oplen; } MICRO_OP void SkewIp(struct Machine *m, long oplen, long delta) { m->oplen = oplen; m->ip += delta; } MICRO_OP void AdvanceIp(struct Machine *m, long oplen) { m->ip += oplen; } //////////////////////////////////////////////////////////////////////////////// // READING FROM REGISTER FILE MICRO_OP static u64 GetCl(struct Machine *m) { return m->cl; } MICRO_OP static u64 GetReg8(struct Machine *m, long b) { return Get8(m->beg + b); } MICRO_OP static u64 GetReg16(struct Machine *m, long i) { return Get16(m->weg[i]); } MICRO_OP static u64 GetReg32(struct Machine *m, long i) { return Get32(m->weg[i]); } MICRO_OP static u64 GetReg64(struct Machine *m, long i) { return Get64(m->weg[i]); } MICRO_OP static XMM_TYPE GetReg128(struct Machine *m, long i) { RETURN_XMM(Get64(m->xmm[i]), Get64(m->xmm[i] + 8)); } typedef u64 (*getreg_f)(struct Machine *, long); static const getreg_f kGetReg[] = {GetReg8, GetReg16, // GetReg32, GetReg64, // (getreg_f)GetReg128}; MICRO_OP static u64 GetReg32_0(struct Machine *m) { return Get32(m->weg[0]); } MICRO_OP static u64 GetReg32_1(struct Machine *m) { return Get32(m->weg[1]); } MICRO_OP static u64 GetReg32_2(struct Machine *m) { return Get32(m->weg[2]); } MICRO_OP static u64 GetReg32_3(struct Machine *m) { return Get32(m->weg[3]); } MICRO_OP static u64 GetReg32_4(struct Machine *m) { return Get32(m->weg[4]); } MICRO_OP static u64 GetReg32_5(struct Machine *m) { return Get32(m->weg[5]); } MICRO_OP static u64 GetReg32_6(struct Machine *m) { return Get32(m->weg[6]); } MICRO_OP static u64 GetReg32_7(struct Machine *m) { return Get32(m->weg[7]); } MICRO_OP static u64 GetReg32_8(struct Machine *m) { return Get32(m->weg[8]); } MICRO_OP static u64 GetReg32_9(struct Machine *m) { return Get32(m->weg[9]); } MICRO_OP static u64 GetReg32_10(struct Machine *m) { return Get32(m->weg[10]); } MICRO_OP static u64 GetReg32_11(struct Machine *m) { return Get32(m->weg[11]); } MICRO_OP static u64 GetReg32_12(struct Machine *m) { return Get32(m->weg[12]); } MICRO_OP static u64 GetReg32_13(struct Machine *m) { return Get32(m->weg[13]); } MICRO_OP static u64 GetReg32_14(struct Machine *m) { return Get32(m->weg[14]); } MICRO_OP static u64 GetReg32_15(struct Machine *m) { return Get32(m->weg[15]); } typedef u64 (*getreg32_f)(struct Machine *); const getreg32_f kGetReg32[] = { GetReg32_0, // GetReg32_1, // GetReg32_2, // GetReg32_3, // GetReg32_4, // GetReg32_5, // GetReg32_6, // GetReg32_7, // GetReg32_8, // GetReg32_9, // GetReg32_10, // GetReg32_11, // GetReg32_12, // GetReg32_13, // GetReg32_14, // GetReg32_15, // }; MICRO_OP static u64 GetReg64_0(struct Machine *m) { return Get64(m->weg[0]); } MICRO_OP static u64 GetReg64_1(struct Machine *m) { return Get64(m->weg[1]); } MICRO_OP static u64 GetReg64_2(struct Machine *m) { return Get64(m->weg[2]); } MICRO_OP static u64 GetReg64_3(struct Machine *m) { return Get64(m->weg[3]); } MICRO_OP static u64 GetReg64_4(struct Machine *m) { return Get64(m->weg[4]); } MICRO_OP static u64 GetReg64_5(struct Machine *m) { return Get64(m->weg[5]); } MICRO_OP static u64 GetReg64_6(struct Machine *m) { return Get64(m->weg[6]); } MICRO_OP static u64 GetReg64_7(struct Machine *m) { return Get64(m->weg[7]); } MICRO_OP static u64 GetReg64_8(struct Machine *m) { return Get64(m->weg[8]); } MICRO_OP static u64 GetReg64_9(struct Machine *m) { return Get64(m->weg[9]); } MICRO_OP static u64 GetReg64_10(struct Machine *m) { return Get64(m->weg[10]); } MICRO_OP static u64 GetReg64_11(struct Machine *m) { return Get64(m->weg[11]); } MICRO_OP static u64 GetReg64_12(struct Machine *m) { return Get64(m->weg[12]); } MICRO_OP static u64 GetReg64_13(struct Machine *m) { return Get64(m->weg[13]); } MICRO_OP static u64 GetReg64_14(struct Machine *m) { return Get64(m->weg[14]); } MICRO_OP static u64 GetReg64_15(struct Machine *m) { return Get64(m->weg[15]); } typedef u64 (*getreg64_f)(struct Machine *); const getreg64_f kGetReg64[] = { GetReg64_0, // GetReg64_1, // GetReg64_2, // GetReg64_3, // GetReg64_4, // GetReg64_5, // GetReg64_6, // GetReg64_7, // GetReg64_8, // GetReg64_9, // GetReg64_10, // GetReg64_11, // GetReg64_12, // GetReg64_13, // GetReg64_14, // GetReg64_15, // }; //////////////////////////////////////////////////////////////////////////////// // WRITING TO REGISTER FILE MICRO_OP void ZeroRegFlags(struct Machine *m, long i) { Put64(m->weg[i], 0); m->flags &= ~(CF | ZF | SF | OF | AF | 0xFF000000u); m->flags |= 1 << FLAGS_ZF; } MICRO_OP static void PutReg8(struct Machine *m, long i, u64 x) { Put8(m->beg + i, x); } MICRO_OP static void PutReg16(struct Machine *m, long i, u64 x) { Put16(m->weg[i], x); } MICRO_OP static void PutReg32(struct Machine *m, long i, u64 x) { Put64(m->weg[i], x & 0xffffffff); } MICRO_OP static void PutReg64(struct Machine *m, long i, u64 x) { Put64(m->weg[i], x); } MICRO_OP static void PutReg128(u64 x, u64 y, struct Machine *m, long i) { Put64(m->xmm[i], x); Put64(m->xmm[i] + 8, y); } typedef void (*putreg_f)(struct Machine *, long, u64); static const putreg_f kPutReg[] = {PutReg8, PutReg16, // PutReg32, PutReg64, // (putreg_f)PutReg128}; MICRO_OP static void PutReg32_0(u64 x, struct Machine *m) { Put64(m->weg[0], (u32)x); } MICRO_OP static void PutReg32_1(u64 x, struct Machine *m) { Put64(m->weg[1], (u32)x); } MICRO_OP static void PutReg32_2(u64 x, struct Machine *m) { Put64(m->weg[2], (u32)x); } MICRO_OP static void PutReg32_3(u64 x, struct Machine *m) { Put64(m->weg[3], (u32)x); } MICRO_OP static void PutReg32_4(u64 x, struct Machine *m) { Put64(m->weg[4], (u32)x); } MICRO_OP static void PutReg32_5(u64 x, struct Machine *m) { Put64(m->weg[5], (u32)x); } MICRO_OP static void PutReg32_6(u64 x, struct Machine *m) { Put64(m->weg[6], (u32)x); } MICRO_OP static void PutReg32_7(u64 x, struct Machine *m) { Put64(m->weg[7], (u32)x); } MICRO_OP static void PutReg32_8(u64 x, struct Machine *m) { Put64(m->weg[8], (u32)x); } MICRO_OP static void PutReg32_9(u64 x, struct Machine *m) { Put64(m->weg[9], (u32)x); } MICRO_OP static void PutReg32_10(u64 x, struct Machine *m) { Put64(m->weg[10], (u32)x); } MICRO_OP static void PutReg32_11(u64 x, struct Machine *m) { Put64(m->weg[11], (u32)x); } MICRO_OP static void PutReg32_12(u64 x, struct Machine *m) { Put64(m->weg[12], (u32)x); } MICRO_OP static void PutReg32_13(u64 x, struct Machine *m) { Put64(m->weg[13], (u32)x); } MICRO_OP static void PutReg32_14(u64 x, struct Machine *m) { Put64(m->weg[14], (u32)x); } MICRO_OP static void PutReg32_15(u64 x, struct Machine *m) { Put64(m->weg[15], (u32)x); } typedef void (*putreg32_f)(u64, struct Machine *); const putreg32_f kPutReg32[] = { PutReg32_0, // PutReg32_1, // PutReg32_2, // PutReg32_3, // PutReg32_4, // PutReg32_5, // PutReg32_6, // PutReg32_7, // PutReg32_8, // PutReg32_9, // PutReg32_10, // PutReg32_11, // PutReg32_12, // PutReg32_13, // PutReg32_14, // PutReg32_15, // }; MICRO_OP static void PutReg64_0(u64 x, struct Machine *m) { Put64(m->weg[0], x); } MICRO_OP static void PutReg64_1(u64 x, struct Machine *m) { Put64(m->weg[1], x); } MICRO_OP static void PutReg64_2(u64 x, struct Machine *m) { Put64(m->weg[2], x); } MICRO_OP static void PutReg64_3(u64 x, struct Machine *m) { Put64(m->weg[3], x); } MICRO_OP static void PutReg64_4(u64 x, struct Machine *m) { Put64(m->weg[4], x); } MICRO_OP static void PutReg64_5(u64 x, struct Machine *m) { Put64(m->weg[5], x); } MICRO_OP static void PutReg64_6(u64 x, struct Machine *m) { Put64(m->weg[6], x); } MICRO_OP static void PutReg64_7(u64 x, struct Machine *m) { Put64(m->weg[7], x); } MICRO_OP static void PutReg64_8(u64 x, struct Machine *m) { Put64(m->weg[8], x); } MICRO_OP static void PutReg64_9(u64 x, struct Machine *m) { Put64(m->weg[9], x); } MICRO_OP static void PutReg64_10(u64 x, struct Machine *m) { Put64(m->weg[10], x); } MICRO_OP static void PutReg64_11(u64 x, struct Machine *m) { Put64(m->weg[11], x); } MICRO_OP static void PutReg64_12(u64 x, struct Machine *m) { Put64(m->weg[12], x); } MICRO_OP static void PutReg64_13(u64 x, struct Machine *m) { Put64(m->weg[13], x); } MICRO_OP static void PutReg64_14(u64 x, struct Machine *m) { Put64(m->weg[14], x); } MICRO_OP static void PutReg64_15(u64 x, struct Machine *m) { Put64(m->weg[15], x); } const putreg64_f kPutReg64[] = { PutReg64_0, // PutReg64_1, // PutReg64_2, // PutReg64_3, // PutReg64_4, // PutReg64_5, // PutReg64_6, // PutReg64_7, // PutReg64_8, // PutReg64_9, // PutReg64_10, // PutReg64_11, // PutReg64_12, // PutReg64_13, // PutReg64_14, // PutReg64_15, // }; //////////////////////////////////////////////////////////////////////////////// // MEMORY OPERATIONS typedef i64 (*load_f)(const u8 *); typedef void (*store_f)(u8 *, u64); MICRO_OP static u8 *ResolveHost(i64 v) { return ToHost(v); } MICRO_OP static u8 *GetBegPtr(struct Machine *m, long i) { return m->beg + i; } MICRO_OP static u8 *GetWegPtr(struct Machine *m, long i) { return m->weg[i]; } MICRO_OP static u8 *GetXmmPtr(struct Machine *m, long i) { return m->xmm[i]; } MICRO_OP void MovsdWpsVpsOp(u8 *p, struct Machine *m, long reg) { Write64(p, Read64(m->xmm[reg])); } #if (defined(__x86_64__) || defined(__aarch64__)) && \ defined(TRIVIALLY_RELOCATABLE) #define LOADSTORE "m" MICRO_OP static i64 NativeLoad8(const u8 *p) { return *p; } MICRO_OP static i64 NativeLoad16(const u8 *p) { return *(const u16 *)p; } MICRO_OP static i64 NativeLoad32(const u8 *p) { return *(const u32 *)p; } MICRO_OP static i64 NativeLoad64(const u8 *p) { return *(const u64 *)p; } MICRO_OP static XMM_TYPE NativeLoad128(u8 *p) { RETURN_XMM(((const u64 *)p)[0], ((const u64 *)p)[1]); } MICRO_OP static void NativeStore8(u8 *p, u64 x) { *p = x; } MICRO_OP static void NativeStore16(u8 *p, u64 x) { *(u16 *)p = x; } MICRO_OP static void NativeStore32(u8 *p, u64 x) { *(u32 *)p = x; } MICRO_OP static void NativeStore64(u8 *p, u64 x) { *(u64 *)p = x; } MICRO_OP static void NativeStore128(u8 *p, u64 x, u64 y) { ((u64 *)p)[0] = x; ((u64 *)p)[1] = y; } static const load_f kLoad[] = { (load_f)NativeLoad8, // (load_f)NativeLoad16, // (load_f)NativeLoad32, // (load_f)NativeLoad64, // (load_f)NativeLoad128, // }; static const store_f kStore[] = { (store_f)NativeStore8, // (store_f)NativeStore16, // (store_f)NativeStore32, // (store_f)NativeStore64, // (store_f)NativeStore128, // }; #else #define LOADSTORE "c" MICRO_OP static XMM_TYPE Load128(u8 *p) { RETURN_XMM(Read64(p), Read64(p + 8)); } MICRO_OP static void Store128(u8 *p, u64 x, u64 y) { Write64(p, x); Write64(p + 8, y); } static const load_f kLoad[] = {Load8, Load16, // Load32, Load64, // (load_f)Load128}; static const store_f kStore[] = {Store8, Store16, // Store32, Store64, // (store_f)Store128}; #endif /* __GNUC__ */ //////////////////////////////////////////////////////////////////////////////// // ARITHMETIC MICRO_OP i64 JustAdd(struct Machine *m, u64 x, u64 y) { return x + y; } MICRO_OP i64 JustOr(struct Machine *m, u64 x, u64 y) { return x | y; } MICRO_OP i64 JustAdc(struct Machine *m, u64 x, u64 y) { return x + y + !!(m->flags & CF); } MICRO_OP i64 JustSbb(struct Machine *m, u64 x, u64 y) { return x - y - !!(m->flags & CF); } MICRO_OP i64 JustAnd(struct Machine *m, u64 x, u64 y) { return x & y; } MICRO_OP i64 JustSub(struct Machine *m, u64 x, u64 y) { return x - y; } MICRO_OP i64 JustXor(struct Machine *m, u64 x, u64 y) { return x ^ y; } const aluop_f kJustAlu[8] = { JustAdd, // JustOr, // JustAdc, // JustSbb, // JustAnd, // JustSub, // JustXor, // JustSub, // }; MICRO_OP i64 JustRol(u64 x, int ign1, int ign2, u64 y) { return x << y | x >> (64 - y); } MICRO_OP i64 JustRor(u64 x, int ign1, int ign2, u64 y) { return x >> y | x << (64 - y); } MICRO_OP i64 JustShl(u64 x, int ign1, int ign2, u64 y) { return x << y; } MICRO_OP i64 JustShr(u64 x, int ign1, int ign2, u64 y) { return x >> y; } MICRO_OP i64 JustSar(u64 x, int ign1, int ign2, u64 y) { return (i64)x >> y; } const aluop_f kJustBsu[8] = { (aluop_f)JustRol, // (aluop_f)JustRor, // 0, // 0, // (aluop_f)JustShl, // (aluop_f)JustShr, // (aluop_f)JustShl, // (aluop_f)JustSar, // }; MICRO_OP i64 JustRolCl64(u64 x, struct Machine *m) { return x << (m->cl & 63) | x >> ((64 - m->cl) & 63); } MICRO_OP i64 JustRorCl64(u64 x, struct Machine *m) { return x >> (m->cl & 63) | x << ((64 - m->cl) & 63); } MICRO_OP i64 JustShlCl64(u64 x, struct Machine *m) { return x << (m->cl & 63); } MICRO_OP i64 JustShrCl64(u64 x, struct Machine *m) { return x >> (m->cl & 63); } MICRO_OP i64 JustSarCl64(u64 x, struct Machine *m) { return (i64)x >> (m->cl & 63); } const aluop_f kJustBsuCl64[8] = { (aluop_f)JustRolCl64, // (aluop_f)JustRorCl64, // 0, // 0, // (aluop_f)JustShlCl64, // (aluop_f)JustShrCl64, // (aluop_f)JustShlCl64, // (aluop_f)JustSarCl64, // }; MICRO_OP i32 JustRolCl32(u32 x, struct Machine *m) { return x << (m->cl & 31) | x >> ((32 - m->cl) & 31); } MICRO_OP i32 JustRorCl32(u32 x, struct Machine *m) { return x >> (m->cl & 31) | x << ((32 - m->cl) & 31); } MICRO_OP i32 JustShlCl32(u32 x, struct Machine *m) { return x << (m->cl & 31); } MICRO_OP i32 JustShrCl32(u32 x, struct Machine *m) { return x >> (m->cl & 31); } MICRO_OP i32 JustSarCl32(u32 x, struct Machine *m) { return (i32)x >> (m->cl & 31); } const aluop_f kJustBsuCl32[8] = { (aluop_f)JustRolCl32, // (aluop_f)JustRorCl32, // 0, // 0, // (aluop_f)JustShlCl32, // (aluop_f)JustShrCl32, // (aluop_f)JustShlCl32, // (aluop_f)JustSarCl32, // }; MICRO_OP i32 JustRol32(u32 x, int ign1, int ign2, u32 y) { return x << y | x >> (32 - y); } MICRO_OP i32 JustRor32(u32 x, int ign1, int ign2, u32 y) { return x >> y | x << (32 - y); } MICRO_OP i32 JustShl32(u32 x, int ign1, int ign2, u32 y) { return x << y; } MICRO_OP i32 JustShr32(u32 x, int ign1, int ign2, u32 y) { return x >> y; } MICRO_OP i32 JustSar32(u32 x, int ign1, int ign2, u32 y) { return (i32)x >> y; } const aluop_f kJustBsu32[8] = { (aluop_f)JustRol32, // (aluop_f)JustRor32, // 0, // 0, // (aluop_f)JustShl32, // (aluop_f)JustShr32, // (aluop_f)JustShl32, // (aluop_f)JustSar32, // }; #if X86_INTRINSICS #define ALU_FAST(M, TYPE, X, Y, OP, COMMUT) \ ({ \ TYPE Res; \ u32 OldFlags = (M)->flags & ~(OF | SF | ZF | AF | CF); \ u64 NewFlags; \ asm(OP "\t%3,%0\n\t" \ "pushfq\n\t" \ "pop\t%1" \ : "=&r" (Res), "=r" (NewFlags) \ : COMMUT "0" ((TYPE)(X)), "g" ((TYPE)(Y)) \ : "cc"); \ (M)->flags = OldFlags | ((u32)NewFlags & (OF | SF | ZF | AF | CF)); \ Res; \ }) #define ALU_FAST_CF(M, TYPE, X, Y, OP, COMMUT) \ ({ \ TYPE Res; \ u32 OldFlags = (M)->flags & ~(OF | SF | ZF | AF); \ u64 NewFlags; \ asm("btr\t%5,%2\n\t" \ OP "\t%4,%0\n\t" \ "pushfq\n\t" \ "pop\t%1" \ : "=&r" (Res), "=r" (NewFlags), "+&r" (OldFlags) \ : COMMUT "0" ((TYPE)(X)), "g" ((TYPE)(Y)), \ "i" (FLAGS_CF) \ : "cc"); \ (M)->flags = OldFlags | ((u32)NewFlags & (OF | SF | ZF | AF | CF)); \ Res; \ }) MICRO_OP static i64 FastXor64(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u64, x, y, "xor", "%"); } MICRO_OP static i64 FastOr64(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u64, x, y, "or", "%"); } MICRO_OP static i64 FastAnd64(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u64, x, y, "and", "%"); } MICRO_OP static i64 FastSub64(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u64, x, y, "sub", ""); } MICRO_OP static i64 FastAdd64(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u64, x, y, "add", "%"); } MICRO_OP static i64 FastAdc64(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u64, x, y, "adc", "%"); } MICRO_OP static i64 FastSbb64(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u64, x, y, "sbb", ""); } MICRO_OP static i64 FastXor32(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u32, x, y, "xor", "%"); } MICRO_OP static i64 FastOr32(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u32, x, y, "or", "%"); } MICRO_OP static i64 FastAnd32(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u32, x, y, "and", "%"); } MICRO_OP static i64 FastSub32(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u32, x, y, "sub", ""); } MICRO_OP static i64 FastAdd32(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u32, x, y, "add", "%"); } MICRO_OP static i64 FastAdc32(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u32, x, y, "adc", "%"); } MICRO_OP static i64 FastSbb32(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u32, x, y, "sbb", ""); } MICRO_OP static i64 FastXor16(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u16, x, y, "xor", "%"); } MICRO_OP static i64 FastOr16(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u16, x, y, "or", "%"); } MICRO_OP static i64 FastAnd16(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u16, x, y, "and", "%"); } MICRO_OP static i64 FastSub16(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u16, x, y, "sub", ""); } MICRO_OP static i64 FastAdd16(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u16, x, y, "add", "%"); } MICRO_OP static i64 FastAdc16(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u16, x, y, "adc", "%"); } MICRO_OP static i64 FastSbb16(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u16, x, y, "sbb", ""); } MICRO_OP static i64 FastXor8(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u8, x, y, "xor", "%"); } MICRO_OP static i64 FastOr8(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u8, x, y, "or", "%"); } MICRO_OP static i64 FastAnd8(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u8, x, y, "and", "%"); } MICRO_OP static i64 FastSub8(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u8, x, y, "sub", ""); } MICRO_OP static i64 FastAdd8(struct Machine *m, u64 x, u64 y) { return ALU_FAST(m, u8, x, y, "add", "%"); } MICRO_OP static i64 FastAdc8(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u8, x, y, "adc", "%"); } MICRO_OP static i64 FastSbb8(struct Machine *m, u64 x, u64 y) { return ALU_FAST_CF(m, u8, x, y, "sbb", ""); } #else /* !X86_INTRINSICS */ MICRO_OP static i64 FastXor64(struct Machine *m, u64 x, u64 y) { u64 z = x ^ y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastOr64(struct Machine *m, u64 x, u64 y) { u64 z = x | y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAnd64(struct Machine *m, u64 x, u64 y) { u64 z = x & y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastSub64(struct Machine *m, u64 x, u64 y) { u64 z = x - y; int c = x < z; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdd64(struct Machine *m, u64 x, u64 y) { u64 z = x + y; int c = z < y; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdc64(struct Machine *m, u64 x, u64 y) { u64 t = x + !!(m->flags & CF); u64 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastSbb64(struct Machine *m, u64 x, u64 y) { u64 t = x - !!(m->flags & CF); u64 z = t - y; int c = (x < t) | (t < z); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastXor32(struct Machine *m, u64 x, u64 y) { u32 z = x ^ y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastOr32(struct Machine *m, u64 x, u64 y) { u32 z = x | y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAnd32(struct Machine *m, u64 x, u64 y) { u32 z = x & y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastSub32(struct Machine *m, u64 x, u64 y) { u32 z = x - y; int c = x < z; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdd32(struct Machine *m, u64 x, u64 y) { u32 z = x + y; int c = z < y; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdc32(struct Machine *m, u64 x, u64 y) { u32 t = x + !!(m->flags & CF); u32 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastSbb32(struct Machine *m, u64 x, u64 y) { u32 t = x - !!(m->flags & CF); u32 z = t - y; int c = (x < t) | (t < z); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastXor16(struct Machine *m, u64 x, u64 y) { u16 z = x ^ y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastOr16(struct Machine *m, u64 x, u64 y) { u16 z = x | y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAnd16(struct Machine *m, u64 x, u64 y) { u16 z = x & y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastSub16(struct Machine *m, u64 x, u64 y) { u16 z = x - y; int c = x < z; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdd16(struct Machine *m, u64 x, u64 y) { u16 z = x + y; int c = z < y; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdc16(struct Machine *m, u64 x, u64 y) { u16 t = x + !!(m->flags & CF); u16 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastSbb16(struct Machine *m, u64 x, u64 y) { u16 t = x - !!(m->flags & CF); u16 z = t - y; int c = (x < t) | (t < z); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastXor8(struct Machine *m, u64 x, u64 y) { u8 z = x ^ y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastOr8(struct Machine *m, u64 x, u64 y) { u8 z = x | y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP i64 FastAnd8(struct Machine *m, u64 x, u64 y) { u8 z = x & y; m->flags = (m->flags & ~(CF | ZF)) | !z << FLAGS_ZF; return z; } MICRO_OP i64 FastSub8(struct Machine *m, u64 x, u64 y) { u8 z = x - y; int c = x < z; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdd8(struct Machine *m, u64 x, u64 y) { u8 z = x + y; int c = z < y; m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastAdc8(struct Machine *m, u64 x, u64 y) { u8 t = x + !!(m->flags & CF); u8 z = t + y; int c = (t < x) | (z < y); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastSbb8(struct Machine *m, u64 x, u64 y) { u8 t = x - !!(m->flags & CF); u8 z = t - y; int c = (x < t) | (t < z); m->flags = (m->flags & ~(CF | ZF)) | c << FLAGS_CF | !z << FLAGS_ZF; return z; } #endif /* !X86_INTRINSICS */ const aluop_f kAluFast[8][4] = { {FastAdd8, FastAdd16, FastAdd32, FastAdd64}, // {FastOr8, FastOr16, FastOr32, FastOr64}, // {FastAdc8, FastAdc16, FastAdc32, FastAdc64}, // {FastSbb8, FastSbb16, FastSbb32, FastSbb64}, // {FastAnd8, FastAnd16, FastAnd32, FastAnd64}, // {FastSub8, FastSub16, FastSub32, FastSub64}, // {FastXor8, FastXor16, FastXor32, FastXor64}, // {FastSub8, FastSub16, FastSub32, FastSub64}, // }; MICRO_OP u32 JustMul32(u32 x, u32 y, struct Machine *m) { return x * y; } MICRO_OP u64 JustMul64(u64 x, u64 y, struct Machine *m) { return x * y; } MICRO_OP i32 Imul32(i32 x, i32 y, struct Machine *m) { int o; i64 z; z = (i64)x * y; o = z != (i32)z; m->flags = (m->flags & ~(CF | OF)) | o << FLAGS_CF | o << FLAGS_OF; return z; } #ifdef HAVE_INT128 MICRO_OP i64 Imul64(i64 x, i64 y, struct Machine *m) { int o; __int128 z; z = (__int128)x * y; o = z != (i64)z; m->flags = (m->flags & ~(CF | OF)) | o << FLAGS_CF | o << FLAGS_OF; return z; } MICRO_OP void JustMulAxDx(u64 x, struct Machine *m) { unsigned __int128 z; z = (unsigned __int128)x * Get64(m->ax); Put64(m->ax, z); Put64(m->dx, z >> 64); } MICRO_OP void MulAxDx(u64 x, struct Machine *m) { int o; unsigned __int128 z; z = (unsigned __int128)x * Get64(m->ax); o = z != (u64)z; m->flags = (m->flags & ~(CF | OF)) | o << FLAGS_CF | o << FLAGS_OF; Put64(m->ax, z); Put64(m->dx, z >> 64); } #ifndef DISABLE_BMI2 MICRO_OP void Mulx64(u64 x, // struct Machine *m, // long vreg, // long rexrreg) { unsigned __int128 z; z = (unsigned __int128)x * Get64(m->dx); Put64(m->weg[vreg], z); Put64(m->weg[rexrreg], z >> 64); } #endif /* !DISABLE_BMI2 */ #endif /* HAVE_INT128 */ MICRO_OP i64 JustNeg(u64 x) { return -x; } MICRO_OP i64 JustDec(u64 x) { return x - 1; } MICRO_OP static i64 FastDec64(u64 x, struct Machine *m) { u64 z; z = x - 1; m->flags = (m->flags & ~ZF) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastDec32(u64 x64, struct Machine *m) { u32 x, z; x = x64; z = x - 1; m->flags = (m->flags & ~ZF) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastDec16(u64 x64, struct Machine *m) { u16 x, z; x = x64; z = x - 1; m->flags = (m->flags & ~ZF) | !z << FLAGS_ZF; return z; } MICRO_OP static i64 FastDec8(u64 x64, struct Machine *m) { u8 x, z; x = x64; z = x - 1; m->flags = (m->flags & ~ZF) | !z << FLAGS_ZF; return z; } const aluop_f kFastDec[4] = { (aluop_f)FastDec8, // (aluop_f)FastDec16, // (aluop_f)FastDec32, // (aluop_f)FastDec64, // }; //////////////////////////////////////////////////////////////////////////////// // STACK OPERATIONS MICRO_OP void FastPush(struct Machine *m, long rexbsrm) { u64 v, x = Get64(m->weg[rexbsrm]); Put64(m->sp, (v = Get64(m->sp) - 8)); Write64(ToHost(v), x); } MICRO_OP void FastPop(struct Machine *m, long rexbsrm) { u64 v = Get64(m->sp); Put64(m->sp, v + 8); Put64(m->weg[rexbsrm], Read64(ToHost(v))); } MICRO_OP void FastCall(struct Machine *m, u64 disp) { u64 v, x = m->ip + disp; Put64(m->sp, (v = Get64(m->sp) - 8)); Write64(ToHost(v), m->ip); m->ip = x; } MICRO_OP void FastCallAbs(u64 x, struct Machine *m) { u64 v; Put64(m->sp, (v = Get64(m->sp) - 8)); Write64(ToHost(v), m->ip); m->ip = x; } MICRO_OP void FastLeave(struct Machine *m) { u64 v = Get64(m->bp); Put64(m->sp, v + 8); Put64(m->bp, Read64(ToHost(v))); } MICRO_OP i64 PredictRet(struct Machine *m, i64 prediction) { u64 v = Get64(m->sp); Put64(m->sp, v + 8); m->ip = Read64(ToHost(v)); return m->ip ^ prediction; } //////////////////////////////////////////////////////////////////////////////// // SIGN EXTENDING MICRO_OP static u64 Sex8(u64 x) { return (i8)x; } MICRO_OP static u64 Sex16(u64 x) { return (i16)x; } MICRO_OP static u64 Sex32(u64 x) { return (i32)x; } typedef u64 (*sex_f)(u64); static const sex_f kSex[] = {Sex8, Sex16, Sex32}; //////////////////////////////////////////////////////////////////////////////// // ADDRESSING MICRO_OP static u64 Truncate32(u64 x) { return (u32)x; } MICRO_OP static i64 Seg(struct Machine *m, u64 d, long s) { return d + m->seg[s].base; } MICRO_OP static i64 Base(struct Machine *m, u64 d, long i) { return d + Get64(m->weg[i]); } MICRO_OP static i64 Index(struct Machine *m, u64 d, long i, int z) { return d + (Get64(m->weg[i]) << z); } MICRO_OP static i64 BaseIndex0(struct Machine *m, u64 d, long b, long i) { return d + Get64(m->weg[b]) + Get64(m->weg[i]); } MICRO_OP static i64 BaseIndex1(struct Machine *m, u64 d, long b, long i) { return d + Get64(m->weg[b]) + (Get64(m->weg[i]) << 1); } MICRO_OP static i64 BaseIndex2(struct Machine *m, u64 d, long b, long i) { return d + Get64(m->weg[b]) + (Get64(m->weg[i]) << 2); } MICRO_OP static i64 BaseIndex3(struct Machine *m, u64 d, long b, long i) { return d + Get64(m->weg[b]) + (Get64(m->weg[i]) << 3); } typedef i64 (*baseindex_f)(struct Machine *, u64, long, long); static const baseindex_f kBaseIndex[] = { BaseIndex0, // BaseIndex1, // BaseIndex2, // BaseIndex3, // }; //////////////////////////////////////////////////////////////////////////////// // JIT DEBUGGING UTILITIES static pureconst bool UsesStaticMemory(u64 rde) { return !IsModrmRegister(rde) && // !SibExists(rde) && // IsRipRelative(rde); // } static void ClobberEverythingExceptResult(struct Machine *m) { #ifdef DEBUG // clobber everything except result registers #if defined(__x86_64__) && !defined(__CYGWIN__) AppendJitSetReg(m->path.jb, kAmdDi, 0x666); AppendJitSetReg(m->path.jb, kAmdSi, 0x666); AppendJitSetReg(m->path.jb, kAmdCx, 0x666); AppendJitSetReg(m->path.jb, 8, 0x666); AppendJitSetReg(m->path.jb, 9, 0x666); AppendJitSetReg(m->path.jb, 10, 0x666); AppendJitSetReg(m->path.jb, 11, 0x666); #elif defined(__aarch64__) AppendJitSetReg(m->path.jb, 2, 0x666); AppendJitSetReg(m->path.jb, 3, 0x666); AppendJitSetReg(m->path.jb, 4, 0x666); AppendJitSetReg(m->path.jb, 5, 0x666); AppendJitSetReg(m->path.jb, 6, 0x666); AppendJitSetReg(m->path.jb, 7, 0x666); AppendJitSetReg(m->path.jb, 9, 0x666); AppendJitSetReg(m->path.jb, 10, 0x666); AppendJitSetReg(m->path.jb, 11, 0x666); AppendJitSetReg(m->path.jb, 12, 0x666); AppendJitSetReg(m->path.jb, 13, 0x666); AppendJitSetReg(m->path.jb, 14, 0x666); AppendJitSetReg(m->path.jb, 15, 0x666); #endif #endif } //////////////////////////////////////////////////////////////////////////////// // FUNCTION BODY EXTRACTOR static bool IsRet(u8 *p) { #if defined(__aarch64__) return Get32(p) == kArmRet; #elif defined(__x86_64__) return *p == kAmdRet; #else __builtin_unreachable(); #endif } static long GetInstructionLength(u8 *p) { #if defined(__aarch64__) // on AArch64, do not recognize instructions which are known to be not // trivially relocatable i.e. opcodes which do PC-relative addressing; // but as exceptions, allow CBZ, CBNZ, TBZ, TBNZ, & B.cond u32 ins = Get32(p); if ((ins & ~kArmDispMask) == kArmJmp) return -1; if ((ins & ~kArmDispMask) == kArmCall) return -1; if ((ins & kArmAdrMask) == kArmAdr) return -1; if ((ins & kArmAdrpMask) == kArmAdrp) return -1; if ((ins & kArmLdrPcMask) == kArmLdrPc) return -1; if ((ins & kArmLdrswPcMask) == kArmLdrswPc) return -1; if ((ins & kArmPrfmPcMask) == kArmPrfmPc) return -1; return 4; #elif defined(__x86_64__) /* !__aarch64__ */ struct XedDecodedInst x; unassert(!DecodeInstruction(&x, p, 15, XED_MODE_LONG)); #ifndef NDEBUG if (ClassifyOp(x.op.rde) == kOpBranching) return -1; if (UsesStaticMemory(x.op.rde)) return -1; #endif /* NDEBUG */ return x.length; #else /* !__x86_64__ */ __builtin_unreachable(); #endif /* !__x86_64__ */ } static long GetMicroOpLengthImpl(void *uop) { long k, n = 0; for (;;) { if (IsRet((u8 *)uop + n)) return n; k = GetInstructionLength((u8 *)uop + n); if (k == -1) return -1; n += k; } } static long GetMicroOpLength(void *uop) { _Static_assert(IS2POW(kMaxOps), ""); static unsigned count; static void *ops[kMaxOps * 2]; static short len[kMaxOps * 2]; long res; unsigned hash, i, step; i = 0; step = 0; hash = ((uintptr_t)uop * 0x9e3779b1u) >> 16; do { i = (hash + step * (step + 1) / 2) & (kMaxOps - 1); if (ops[i] == uop) return len[i]; ++step; } while (ops[i]); res = GetMicroOpLengthImpl(uop); unassert(count++ < kMaxOps); ops[i] = uop; len[i] = res; return res; } //////////////////////////////////////////////////////////////////////////////// // PRINTF-STYLE X86 MICROCODING WITH POSTFIX NOTATION #define ItemsRequired(n) unassert(i >= n) _Thread_local static long i; _Thread_local static u8 stack[8]; static inline unsigned CheckBelow(unsigned x, unsigned n) { unassert(x < n); return x; } static void CallFunction(struct Machine *m, void *fun) { AppendJitCall(m->path.jb, fun); ClobberEverythingExceptResult(m); } static void CallMicroOp(struct Machine *m, void *fun) { #ifdef TRIVIALLY_RELOCATABLE long len; if ((len = GetMicroOpLength(fun)) > 0) { AppendJit(m->path.jb, fun, len); } else { LOG_ONCE(LOGF("jit micro-operation at address %" PRIxPTR " has branches or static memory references", (uintptr_t)fun)); CallFunction(m, fun); } #else CallFunction(m, fun); #endif } static void GetReg_32_64(struct Machine *m, void *fun) { AppendJitMovReg(m->path.jb, kJitArg0, kJitSav0); CallMicroOp(m, fun); } static void GetReg(P, unsigned log2sz, unsigned reg, unsigned breg) { switch (log2sz) { case 0: Jitter(A, "q" // arg0 = machine "a1i" // arg1 = register index "m", // call micro-op (u64)kByteReg[breg], kGetReg[0]); break; case 2: GetReg_32_64(m, kGetReg32[reg]); break; case 3: GetReg_32_64(m, kGetReg64[reg]); break; default: Jitter(A, "q" // arg0 = machine "a1i" // arg1 = register index "m", // call micro-op (u64)reg, kGetReg[log2sz]); break; } } static void PutReg_32_64(struct Machine *m, void *fun) { ItemsRequired(1); AppendJitMovReg(m->path.jb, kJitArg1, kJitSav0); AppendJitMovReg(m->path.jb, kJitArg0, stack[i - 1]); CallMicroOp(m, fun); --i; } static void PutReg(P, unsigned log2sz, unsigned reg, unsigned breg) { switch (log2sz) { case 0: ItemsRequired(1); Jitter(A, "a2=" // arg2 = "a1i" // arg1 = register index "q" // arg0 = machine "m", // call micro-op (u64)kByteReg[breg], kPutReg[0]); break; case 1: ItemsRequired(1); Jitter(A, "a2=" // arg2 = "a1i" // arg1 = register index "q" // arg0 = machine "m", // call micro-op (u64)reg, kPutReg[1]); break; case 2: PutReg_32_64(m, kPutReg32[reg]); break; case 3: PutReg_32_64(m, kPutReg64[reg]); break; case 4: // note: r0 == a0 on aarch64 // note: r1 == a1 on aarch64 // note: r1 == a2 on system five // note: r1 == a1 on cygwin Jitter(A, "a3i" // arg3 = register index "r1a1=" // arg1 = res1 "s0a2=" // arg2 = machine "t" // arg0 = res0 "m", // call micro-op (u64)reg, kPutReg[log2sz]); break; default: __builtin_unreachable(); } } static unsigned JitterImpl(P, const char *fmt, va_list va, unsigned k, unsigned depth) { unsigned c, log2sz; log2sz = RegLog2(rde); LogCodOp(m, fmt); while ((c = fmt[k++])) { switch (c) { case ' ': // nop break; case 'u': // unpop i += 1; break; case '!': // trap AppendJitTrap(m->path.jb); break; case '%': // register switch ((c = fmt[k++])) { case 'c': switch ((c = fmt[k++])) { case 'l': Jitter(A, "q" // arg0 = machine "m", // call micro-op GetCl); break; default: unassert(!"bad register"); } break; default: unassert(!"bad register"); } break; case 'm': // micro-op CallMicroOp(m, va_arg(va, void *)); break; case 'c': // call CallFunction(m, va_arg(va, void *)); break; case 'r': // push res reg stack[i++] = kJitRes[CheckBelow(fmt[k++] - '0', ARRAYLEN(kJitRes))]; break; case 'a': // push arg reg stack[i++] = kJitArg[CheckBelow(fmt[k++] - '0', ARRAYLEN(kJitArg))]; break; case 's': // push sav reg stack[i++] = kJitSav[CheckBelow(fmt[k++] - '0', ARRAYLEN(kJitSav))]; break; case 'i': // set reg imm, e.g. ("a1i", 123) [mov $123,%rsi] ItemsRequired(1); AppendJitSetReg(m->path.jb, stack[--i], va_arg(va, u64)); break; case '=': // = mov reg, e.g. s0a0= [mov %rbx,%rdi] ItemsRequired(2); AppendJitMovReg(m->path.jb, stack[i - 1], stack[i - 2]); i -= 2; break; case 'q': // s0a0= [shortcut] AppendJitMovReg(m->path.jb, kJitArg0, kJitSav0); break; case 't': // r0a0= [shortcut] AppendJitMovReg(m->path.jb, kJitArg0, kJitRes0); break; case 'A': // res0 = GetReg(RexrReg) GetReg(A, log2sz, RexrReg(rde), RexRexr(rde)); break; case 'C': // PutReg(RexrReg, ) PutReg(A, log2sz, RexrReg(rde), RexRexr(rde)); break; case 'B': // res0 = GetRegOrMem(RexbRm) if (IsModrmRegister(rde)) { GetReg(A, log2sz, RexbRm(rde), RexRexb(rde)); } else if (HasLinearMapping()) { if (!kSkew) { Jitter(A, "L" // load effective address "t" // arg0 = pointer LOADSTORE, // call function (read word shared memory) kLoad[log2sz]); } else { Jitter(A, "L" // load effective address "t" // arg0 = virtual address "m" // call micro-op (turn virtual into pointer) "t" // arg0 = pointer LOADSTORE, // call function (read word shared memory) ResolveHost, kLoad[log2sz]); } } else { Jitter(A, "L" // load effective address "a3i" // arg3 = false "a2i" // arg2 = bytes to read "r0a1=" // arg1 = virtual address "q" // arg0 = machine "c" // call function (turn virtual into pointer) "t" // arg0 = pointer LOADSTORE, // call micro-op (read vector shared memory) (u64)0, (u64)(1 << log2sz), ReserveAddress, kLoad[log2sz]); } break; case 'D': // PutRegOrMem(RexbRm, ), e.g. c r0 D if (log2sz < 4) { ItemsRequired(1); if (IsModrmRegister(rde)) { PutReg(A, log2sz, RexbRm(rde), RexRexb(rde)); } else if (HasLinearMapping()) { if (!kSkew) { Jitter(A, "s3=" // sav3 = "L" // load effective address "s3a1=" // arg1 = sav3 "t" // arg0 = res0 LOADSTORE, // call micro-op (write word to shared memory) kStore[log2sz]); } else { Jitter(A, "s3=" // sav3 = "L" // load effective address "t" // arg0 = virtual address "m" // call micro-op "s3a1=" // arg1 = sav3 "t" // arg0 = res0 LOADSTORE, // call micro-op (write word to shared memory) ResolveHost, kStore[log2sz]); } } else { Jitter(A, "s3=" // sav3 = "L" // load effective address "a3i" // arg3 = true "a2i" // arg2 = byte width of write operation "r0a1=" // arg1 = res0 "q" // arg0 = machine "c" // call function (turn virtual into pointer) "s3a1=" // arg1 = sav3 "t" // arg0 = res0 LOADSTORE, // call function (write word to shared memory) (u64)1, (u64)(1 << log2sz), ReserveAddress, kStore[log2sz]); } } else { if (IsModrmRegister(rde)) { // note: r0 == a0 on aarch64 // note: r1 == a1 on aarch64 // note: r1 == a2 on system five // note: r1 == a1 on cygwin Jitter(A, "a3i" // arg3 = index of register "r1a1=" // arg1 = res1 "s0a3=" // arg2 = machine "t" // arg0 = res0 "m", // call micro-op (xmm put register) RexbRm(rde), kPutReg[log2sz]); } else if (HasLinearMapping()) { if (!kSkew) { Jitter( A, "r1s4=" // sav4 = res1 "r0s3=" // sav3 = res0 "L" // load effective address "s4a2=" // arg2 = sav4 "s3a1=" // arg1 = sav3 "t" // arg0 = res0 LOADSTORE, // call micro-op (store vector to shared memory) kStore[log2sz]); } else { Jitter( A, "r1s4=" // sav4 = res1 "r0s3=" // sav3 = res0 "L" // load effective address "t" // arg0 = virtual address "m" // call micro-op "s4a2=" // arg2 = sav4 "s3a1=" // arg1 = sav3 "t" // arg0 = res0 LOADSTORE, // call micro-op (store vector to shared memory) ResolveHost, kStore[log2sz]); } } else { Jitter(A, "r1s4=" // sav4 = res1 "r0s3=" // sav3 = res0 "L" // load effective address "a3i" // arg3 = true "a2i" // arg2 = bytes to write "r0a1=" // arg1 = res0 "q" // arg0 = machine "c" // call function (turn virtual into pointer) "s4a2=" // arg2 = sav4 "s3a1=" // arg1 = sav3 "t" // arg0 = res0 LOADSTORE, // call micro-op (store vector to shared memory) (u64)1, (u64)(1 << log2sz), ReserveAddress, kStore[log2sz]); } } break; case 'L': // load effective address if (!SibExists(rde) && IsRipRelative(rde)) { AppendJitSetReg(m->path.jb, kJitRes0, disp + m->ip); } else if (!SibExists(rde)) { if (disp) { Jitter(A, "a2i" // arg2 = address base register index "a1i" // arg1 = displacement "q" // arg0 = machine "m", // call micro-op RexbRm(rde), disp, Base); } else { Jitter(A, "q" // arg0 = machine "m", // call micro-op kGetReg64[RexbRm(rde)]); } } else if (!SibHasBase(rde) && !SibHasIndex(rde)) { Jitter(A, "r0i", disp); // res0 = absolute } else if (SibHasBase(rde) && !SibHasIndex(rde)) { if (disp) { AppendJitSetReg(m->path.jb, kJitArg2, RexbBase(rde)); AppendJitSetReg(m->path.jb, kJitArg1, disp); AppendJitMovReg(m->path.jb, kJitArg0, kJitSav0); CallMicroOp(m, Base); } else { Jitter(A, "q" // arg0 = machine "m", // call micro-op kGetReg64[RexbBase(rde)]); } } else if (!SibHasBase(rde) && SibHasIndex(rde)) { Jitter(A, "a3i" // arg3 = log2(address index scale) "a2i" // arg2 = address index register index "a1i" // arg1 = displacement "q" // arg0 = machine "m", // call micro-op SibScale(rde), Rexx(rde) << 3 | SibIndex(rde), disp, Index); } else { Jitter(A, "a3i" // arg4 = address index register index "a2i" // arg2 = address base register index "a1i" // arg1 = displacement "q" // arg0 = machine "m", // call micro-op Rexx(rde) << 3 | SibIndex(rde), RexbBase(rde), disp, kBaseIndex[SibScale(rde)]); } if (Eamode(rde) == XED_MODE_LEGACY) { Jitter(A, "t" // arg0 = res0 "m", // call micro-op Truncate32); } if (Sego(rde)) { Jitter(A, "a2i" // arg2 = segment register index "r0a1=" // arg1 = res0 "q" // arg0 = machine "m", // call micro-op Sego(rde) - 1, Seg); } break; case 'Q': // res0 = GetRegPointer(RexrReg) Jitter(A, "a1i" // arg1 = register index "q" // arg0 = machine "m", // call micro-op !log2sz ? (u64)kByteReg[RexrReg(rde)] : RexrReg(rde), !log2sz ? GetBegPtr : log2sz < 4 ? GetWegPtr : GetXmmPtr); break; case 'P': // res0 = GetRegOrMemPointer(RexbRm) if (IsModrmRegister(rde)) { Jitter(A, "a1i" // arg1 = register index "q" // arg0 = machine "m", // call micro-op !log2sz ? (u64)kByteReg[RexbRm(rde)] : RexbRm(rde), !log2sz ? GetBegPtr : log2sz < 4 ? GetWegPtr : GetXmmPtr); } else if (HasLinearMapping()) { if (!kSkew) { Jitter(A, "L"); // load effective address } else { Jitter(A, "L" // load effective address "t" // arg0 = virtual address "m", // res0 = call micro-op (turn virtual into pointer) ResolveHost); } } else { Jitter(A, "L" // load effective address "a3i" // arg3 = false "a2i" // arg2 = bytes to read "r0a1=" // arg1 = virtual address "q" // arg0 = machine "c", // res0 = call function (turn virtual into pointer) (u64)0, (u64)(1 << log2sz), ReserveAddress); } break; case 'E': // r0 = GetReg(RexbSrm) GetReg(A, log2sz, RexbSrm(rde), RexRexbSrm(rde)); break; case 'F': // PutReg(RexbSrm, ) PutReg(A, log2sz, RexbSrm(rde), RexRexbSrm(rde)); break; case 'G': // r0 = GetReg(AX) GetReg(A, log2sz, 0, 0); break; case 'H': // PutReg(AX, ) PutReg(A, log2sz, 0, 0); break; case 'w': // prevents byte operation log2sz = WordLog2(rde); continue; case 'z': // force size log2sz = CheckBelow(fmt[k++] - '0', 5); continue; case 'x': // sign extend ItemsRequired(1); unassert(log2sz < 4); if (log2sz < 3) { Jitter(A, "a0=" // arg0 = machine "m", // call micro-op (sign extend) kSex[log2sz]); } else { Jitter(A, "r0="); // result = } break; default: LOGF("%s %c index %d of '%s'", "bad jitter directive", c, k - 1, fmt); unassert(!"bad jitter directive"); } unassert(i <= ARRAYLEN(stack)); log2sz = RegLog2(rde); } return k; } /** * Generates JIT code that implements x86 instructions. */ void Jitter(P, const char *fmt, ...) { va_list va; if (!IsMakingPath(m)) return; va_start(va, fmt); JitterImpl(A, fmt, va, 0, 0); unassert(!i); va_end(va); } #endif /* HAVE_JIT */ ================================================ FILE: blink/util.h ================================================ #ifndef BLINK_UTIL_H_ #define BLINK_UTIL_H_ #include #include #include #include #include #include #include "blink/builtin.h" #include "blink/types.h" typedef void aborthook_f(void); extern int optind_; extern char *optarg_; extern const short kCp437[256]; _Noreturn void Abort(void); void AtAbort(aborthook_f *); char *GetStartDir(void); int GetOpt(int, char *const[], const char *); u64 tpenc(uint32_t); const char *DescribeSignal(int); const char *DescribeHostErrno(int); bool EndsWith(const char *, const char *); bool StartsWith(const char *, const char *); const char *doublenul(const char *, unsigned); ssize_t readansi(int, char *, size_t); char *FormatInt64(char *, int64_t); char *FormatUint64(char *, uint64_t); char *FormatInt64Thousands(char *, int64_t); char *FormatUint64Thousands(char *, uint64_t); char *FormatSize(char *, uint64_t, uint64_t); char *Commandv(const char *, char *, size_t); char *Demangle(char *, const char *, size_t); void *Deflate(const void *, unsigned, unsigned *); void Inflate(void *, unsigned, const void *, unsigned); ssize_t UninterruptibleWrite(int, const void *, size_t); long IsProcessTainted(void); long Magikarp(u8 *, long); int GetCpuCount(void); char *strchrnul_(const char *, int); int vasprintf_(char **, const char *, va_list); char *realpath_(const char *, char *); void *memccpy_(void *, const void *, int, size_t); int wcwidth_(wchar_t); u64 Vigna(u64[1]); #ifndef HAVE_STRCHRNUL #ifdef strchrnul #undef strchrnul #endif #define strchrnul strchrnul_ #endif #ifndef HAVE_VASPRINTF #ifdef vasprintf #undef vasprintf #endif #define vasprintf vasprintf_ #endif #ifndef HAVE_REALPATH #ifdef realpath #undef realpath #endif #define realpath realpath_ #endif #if !defined(HAVE_MEMCCPY) || defined(TINY) #ifdef memccpy #undef memccpy #endif #define memccpy memccpy_ #endif #ifndef HAVE_WCWIDTH #ifdef wcwidth #undef wcwidth #endif #define wcwidth wcwidth_ #endif #endif /* BLINK_UTIL_H_ */ ================================================ FILE: blink/vasprintf.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "blink/assert.h" #include "blink/util.h" int vasprintf_(char **strp, const char *fmt, va_list va) { va_list vb; size_t size; char *p, *p2; int wrote, rc = -1; if ((p = (char *)malloc((size = 512)))) { va_copy(vb, va); wrote = vsnprintf(p, size, fmt, va); if (wrote < size) { if ((p2 = (char *)realloc(p, wrote + 1))) { p = p2; rc = wrote; } } else { size = wrote + 1; if ((p2 = (char *)realloc(p, size))) { p = p2; wrote = vsnprintf(p, size, fmt, vb); unassert(wrote == size - 1); rc = wrote; } } va_end(vb); } if (rc != -1) { *strp = p; return rc; } else { return -1; } } ================================================ FILE: blink/vfs.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Trung Nguyen │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/vfs.h" #include #include #include #include #include #include #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/devfs.h" #include "blink/errno.h" #include "blink/hostfs.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/procfs.h" #include "blink/thread.h" #include "blink/tunables.h" #ifndef DISABLE_VFS #define VFS_UNREACHABLE "(unreachable)" #define VFS_TRAVERSE_MAX_LINKS 40 struct VfsFd { struct Dll elem; struct VfsInfo *data; int fd; }; struct VfsMap { struct Dll elem; struct VfsInfo *data; void *addr; size_t len; off_t offset; int prot; int flags; }; #define VFS_FD_CONTAINER(e) DLL_CONTAINER(struct VfsFd, elem, (e)) #define VFS_MAP_CONTAINER(e) DLL_CONTAINER(struct VfsMap, elem, (e)) static struct VfsDevice g_rootdevice = { .mounts = NULL, .ops = NULL, .data = NULL, .dev = 0, .refcount = 1u, }; static struct VfsInfo g_initialrootinfo = { .device = &g_rootdevice, .parent = NULL, .data = NULL, .ino = 0, .dev = 0, .mode = S_IFDIR | 0755, .refcount = 1u, }; struct VfsInfo *g_cwdinfo; struct VfsInfo *g_rootinfo; struct VfsInfo *g_actualrootinfo; struct Vfs g_vfs = { .devices = NULL, .systems = NULL, .fds = NULL, .maps = NULL, .lock = PTHREAD_MUTEX_INITIALIZER_, .mapslock = PTHREAD_MUTEX_INITIALIZER_, }; int VfsInit(const char *prefix) { struct stat st; char *cwd, hostcwd[PATH_MAX], *bprefix = NULL; struct VfsInfo *info; size_t hostcwdlen, prefixlen; int fd; // Register built-in filesystems unassert(!VfsRegister(&g_hostfs)); unassert(!VfsRegister(&g_devfs)); unassert(!VfsRegister(&g_procfs)); dll_init(&g_rootdevice.elem); dll_make_first(&g_vfs.devices, &g_rootdevice.elem); // Initialize the root directory unassert(!VfsAcquireInfo(&g_initialrootinfo, &g_rootinfo)); unassert(!VfsAcquireInfo(&g_initialrootinfo, &g_actualrootinfo)); if (prefix) { bprefix = realpath(prefix, NULL); } if (bprefix) { if (stat(bprefix, &st) == -1) { ERRF("Failed to stat BLINK_PREFIX %s, %s", bprefix, strerror(errno)); free(bprefix); bprefix = NULL; } else if (!S_ISDIR(st.st_mode)) { ERRF("BLINK_PREFIX %s is not a directory", bprefix); free(bprefix); bprefix = NULL; } } if (bprefix) { unassert(!VfsMount(bprefix, "/", "hostfs", 0, NULL)); } else { unassert(!VfsMount("/", "/", "hostfs", 0, NULL)); } unassert(!VfsFreeInfo(g_rootinfo)); unassert(!VfsTraverse("/", &g_rootinfo, false)); // Temporary cwd for syscalls to work during initialization unassert(!VfsChdir("/")); // Mount the host's root. if (VfsMkdir(AT_FDCWD, VFS_SYSTEM_ROOT_MOUNT, 0755) == -1 && errno != EEXIST) { ERRF("Failed to create system root mount directory, %s", strerror(errno)); goto cleananddie; } unassert(VfsMount("/", VFS_SYSTEM_ROOT_MOUNT, "hostfs", 0, NULL) != -1); unassert(!VfsTraverse("/", &g_actualrootinfo, false)); // devfs, procfs if (VfsMkdir(AT_FDCWD, "/dev", 0755) == -1 && errno != EEXIST) { ERRF("Failed to create /dev, %s", strerror(errno)); goto cleananddie; } unassert(!VfsMount("", "/dev", "devfs", 0, NULL)); if (VfsMkdir(AT_FDCWD, "/proc", 0755) == -1 && errno != EEXIST) { ERRF("Failed to create /proc, %s", strerror(errno)); goto cleananddie; } unassert(!VfsMount("proc", "/proc", "proc", 0, NULL)); // Initialize the current working directory unassert(getcwd(hostcwd, sizeof(hostcwd))); if (bprefix && !strncmp(hostcwd, bprefix, (prefixlen = strlen(bprefix)))) { hostcwdlen = strlen(hostcwd); if (hostcwdlen == prefixlen) { cwd = strdup("/"); } else { cwd = (char *)malloc(hostcwdlen - prefixlen + 1); if (cwd == NULL) { enomem(); goto cleananddie; } memcpy(cwd, hostcwd + prefixlen, hostcwdlen - prefixlen + 1); } } else { cwd = (char *)malloc(PATH_MAX + sizeof(VFS_SYSTEM_ROOT_MOUNT)); if (cwd == NULL) { enomem(); goto cleananddie; } memcpy(cwd, VFS_SYSTEM_ROOT_MOUNT, sizeof(VFS_SYSTEM_ROOT_MOUNT)); strcat(cwd, hostcwd); } unassert(!VfsChdir(cwd)); free(cwd); free(bprefix); // stdin, stdout, stderr unassert(!HostfsWrapFd(0, false, &info)); unassert(VfsAddFd(info) == 0); unassert(!HostfsWrapFd(1, false, &info)); unassert(VfsAddFd(info) == 1); unassert(!HostfsWrapFd(2, false, &info)); unassert(VfsAddFd(info) == 2); // Some Linux tests require that when EMFILE occurs, // the fd returned before it must be the maximum possible. // Force initialization of the logger fd. LogInfo(__FILE__, __LINE__, "Initializing VFS"); for (fd = kMinBlinkFd; HostfsWrapFd(fd, false, &info) != -1; ++fd) { unassert(!VfsSetFd(fd, info)); } VFS_LOGF("Initialized VFS"); return 0; cleananddie: free(bprefix); return -1; } int VfsRegister(struct VfsSystem *system) { if (system == NULL) { efault(); return -1; } LOCK(&g_vfs.lock); VFS_LOGF("Registering filesystem %s", system->name); dll_init(&system->elem); dll_make_last(&g_vfs.systems, &system->elem); UNLOCK(&g_vfs.lock); return 0; } int VfsMount(const char *source, const char *target, const char *fstype, u64 flags, const void *data) { struct VfsInfo *targetinfo; struct VfsSystem *newsystem, *s; struct VfsDevice *targetdevice = 0, *newdevice, *d; struct VfsMount *newmount; struct Dll *e; char *newname = 0; i64 nextdev; if (flags & MS_SILENT_LINUX) { flags &= ~MS_SILENT_LINUX; } if (flags) { // Theoretically, we can support a lot of the Linux flags without // changing the current design. However, as the major intended // usecase is to simply mount hostfs, this is currently not supported. LOGF("Unsupported mount flags: 0x%llx", (unsigned long long)flags); } if (VfsTraverse(target, &targetinfo, true) == -1) { return -1; } if (!S_ISDIR(targetinfo->mode)) { return enotdir(); } // Allow mounting once to "/" during initialization only. if ((targetinfo->dev != g_initialrootinfo.dev || targetinfo->ino != g_initialrootinfo.ino) && (targetinfo->dev == g_actualrootinfo->dev && targetinfo->ino == g_actualrootinfo->ino)) { errno = EBUSY; return -1; } LOCK(&g_vfs.lock); newsystem = NULL; for (e = dll_first(g_vfs.systems); e; e = dll_next(g_vfs.systems, e)) { s = VFS_SYSTEM_CONTAINER(e); if (strcmp(s->name, fstype) == 0) { newsystem = s; break; } } if (newsystem == NULL) { VFS_LOGF("Unknown filesystem type: %s", fstype); UNLOCK(&g_vfs.lock); return enodev(); } for (e = dll_first(g_vfs.devices); e; e = dll_next(g_vfs.devices, e)) { d = VFS_DEVICE_CONTAINER(e); if (d->dev == targetinfo->dev) { targetdevice = d; break; } } if (targetdevice == NULL) { // Might have been unmounted after VfsTraverse by another thread UNLOCK(&g_vfs.lock); return enoent(); } if (targetinfo->name != NULL) { newname = strdup(targetinfo->name); if (newname == NULL) { UNLOCK(&g_vfs.lock); return enomem(); } } if (newsystem->ops.Init(source, flags, data, &newdevice, &newmount) == -1) { UNLOCK(&g_vfs.lock); return -1; } nextdev = 0; for (e = dll_first(g_vfs.devices); e; e = dll_next(g_vfs.devices, e)) { d = VFS_DEVICE_CONTAINER(e); if (d->dev == nextdev) { ++nextdev; } else { break; } } newdevice->dev = nextdev; if (e == NULL) { dll_make_last(&g_vfs.devices, &newdevice->elem); } else { dll_splice_after(dll_prev(g_vfs.devices, e), &newdevice->elem); } newdevice->flags = flags; newmount->baseino = targetinfo->ino; newmount->root->dev = nextdev; newmount->root->name = newname; newmount->root->namelen = targetinfo->namelen; unassert(!VfsAcquireInfo(targetinfo->parent, &newmount->root->parent)); dll_init(&newmount->elem); dll_make_last(&targetdevice->mounts, &newmount->elem); UNLOCK(&g_vfs.lock); unassert(!VfsFreeInfo(targetinfo)); VFS_LOGF("Mounted a new device at %s, dev=%ld", target, nextdev); return 0; } //////////////////////////////////////////////////////////////////////////////// int VfsCreateDevice(struct VfsDevice **output) { struct VfsDevice *device; if (output == NULL) { return efault(); } device = (struct VfsDevice *)malloc(sizeof(struct VfsDevice)); if (device == NULL) { return enomem(); } device->dev = 0; device->refcount = 1; device->data = NULL; device->ops = NULL; device->mounts = NULL; device->refcount = 1; unassert(!pthread_mutex_init(&device->lock, NULL)); dll_init(&device->elem); *output = device; return 0; } int VfsFreeDevice(struct VfsDevice *device) { struct Dll *e; struct VfsMount *mount; int rc; if (device == NULL) { return 0; } if ((rc = atomic_fetch_sub(&device->refcount, 1)) != 1) { return 0; } LOCK(&device->lock); if (device->ops && device->ops->Freedevice) { if (device->ops->Freedevice(device->data) == -1) { UNLOCK(&device->lock); return -1; } } device->data = NULL; device->ops = NULL; // Don't free root, it's a weak reference. device->root = NULL; for (e = dll_first(device->mounts); e; e = dll_next(device->mounts, e)) { mount = VFS_MOUNT_CONTAINER(e); unassert(!VfsFreeInfo(mount->root)); mount->root = NULL; free(mount); } UNLOCK(&device->lock); unassert(!pthread_mutex_destroy(&device->lock)); free(device); return 0; } int VfsAcquireDevice(struct VfsDevice *device, struct VfsDevice **output) { int rc; if (output == NULL) { return efault(); } if (device == NULL) { *output = NULL; return 0; } rc = atomic_fetch_add(&device->refcount, 1); unassert(rc > 0); *output = device; return 0; } //////////////////////////////////////////////////////////////////////////////// int VfsCreateInfo(struct VfsInfo **output) { struct VfsInfo *info; if (output == NULL) { return efault(); } info = (struct VfsInfo *)malloc(sizeof(struct VfsInfo)); if (info == NULL) { return enomem(); } info->parent = NULL; info->device = NULL; info->name = NULL; info->namelen = 0; info->data = NULL; info->ino = 0; info->dev = 0; info->mode = 0; info->refcount = 1; *output = info; return 0; } int VfsAcquireInfo(struct VfsInfo *info, struct VfsInfo **output) { int rc; if (output == NULL) { return efault(); } if (info == NULL) { *output = NULL; return 0; } rc = atomic_fetch_add(&info->refcount, 1); unassert(rc > 0); VFS_LOGF("Acquired VfsInfo %p, refcount now %i.", info, rc + 1); *output = info; return 0; } int VfsFreeInfo(struct VfsInfo *info) { int rc; if (info == NULL) { return 0; } if ((rc = atomic_fetch_sub(&info->refcount, 1)) != 1) { VFS_LOGF("Freeing VfsInfo %p, refcount now %i.", info, rc - 1); return 0; } if (VfsFreeInfo(info->parent) == -1) { return -1; } info->parent = NULL; if (info->device->ops && info->device->ops->Freeinfo) { if (info->device->ops->Freeinfo(info->data) == -1) { return -1; } } unassert(!VfsFreeDevice(info->device)); info->data = NULL; if (info->name) { free((void *)info->name); info->name = NULL; } free(info); return 0; } //////////////////////////////////////////////////////////////////////////////// static int VfsTraverseMount(struct VfsInfo **info, char childname[VFS_NAME_MAX]) { struct VfsMount *mount; struct Dll *e; if (info == NULL) { return efault(); } if (!S_ISDIR((*info)->mode)) { return 0; } LOCK(&g_vfs.lock); for (e = dll_first((*info)->device->mounts); e; e = dll_next((*info)->device->mounts, e)) { mount = VFS_MOUNT_CONTAINER(e); if (!childname) { // Checking info itself. if (mount->baseino == (*info)->ino) { VFS_LOGF("VfsTraverseMount: switching from dev=%d to dev=%d", (*info)->dev, mount->root->dev); unassert(!VfsFreeInfo(*info)); unassert(!VfsAcquireInfo(mount->root, info)); break; } } else { // Checking child node "childname" of info. VFS_LOGF("VfsTraverseMount: checking mount %s", mount->root->name); if (mount->root->parent && mount->root->parent->ino == (*info)->ino && !strcmp(mount->root->name, childname)) { unassert(mount->root->parent->dev == (*info)->dev); VFS_LOGF("VfsTraverseMount: switching from dev=%d to dev=%d", (*info)->dev, mount->root->dev); strcpy(childname, "."); unassert(!VfsFreeInfo(*info)); unassert(!VfsAcquireInfo(mount->root, info)); break; } } } UNLOCK(&g_vfs.lock); return 0; } static int VfsTraverseStackBuild(struct VfsInfo **stack, const char *path, struct VfsInfo *root, bool follow, int level) { struct VfsInfo *next, *origin; const char *end; char filename[VFS_NAME_MAX]; char *link; VFS_LOGF("VfsTraverseStackBuild(%p, \"%s\", %p, %d)", stack, path, root, follow); if (stack == NULL || path == NULL) { return efault(); } if (level > VFS_TRAVERSE_MAX_LINKS) { return eloop(); } origin = *stack; if (*stack == NULL) { unassert(!VfsAcquireInfo(&g_initialrootinfo, stack)); } if (root == NULL) { root = &g_initialrootinfo; } while (*path) { if (!S_ISDIR((*stack)->mode)) { enotdir(); goto cleananddie; } unassert(!VfsTraverseMount(stack, NULL)); if ((*stack)->device->ops && (*stack)->device->ops->Traverse) { if ((*stack)->device->ops->Traverse(stack, &path, root) == -1) { goto cleananddie; } } else { while (*path == '/') { ++path; } end = path; while (end[0] && end[0] != '/') { ++end; } if (end == path) { break; } if (end - path >= VFS_NAME_MAX) { enametoolong(); goto cleananddie; } memcpy(filename, path, end - path); filename[end - path] = '\0'; path = end; if (!strcmp(filename, ".")) { continue; } if (!strcmp(filename, "..")) { if (*stack != root && (*stack)->parent != NULL) { unassert(!VfsAcquireInfo((*stack)->parent, &next)); unassert(!VfsFreeInfo(*stack)); *stack = next; } continue; } if ((*stack)->device->ops->Finddir(*stack, filename, &next) == -1) { goto cleananddie; } unassert(!VfsFreeInfo(*stack)); *stack = next; } if (follow) { while (S_ISLNK((*stack)->mode)) { if ((*stack)->device->ops->Readlink(*stack, &link) == -1) { goto cleananddie; } VFS_LOGF("VfsTraverseStackBuild: symlink to %s", link); if (link[0] == '/') { unassert(!VfsFreeInfo(*stack)); unassert(!VfsAcquireInfo(root, stack)); } else { unassert(!VfsAcquireInfo((*stack)->parent, &next)); unassert(!VfsFreeInfo(*stack)); *stack = next; } if (VfsTraverseStackBuild(stack, link, root, follow, level + 1) == -1) { free(link); goto cleananddie; } free(link); } } } unassert(!VfsTraverseMount(stack, NULL)); return 0; cleananddie: while (*stack != origin) { unassert(!VfsAcquireInfo((*stack)->parent, &next)); unassert(!VfsFreeInfo(*stack)); *stack = next; } return -1; } int VfsTraverse(const char *path, struct VfsInfo **output, bool follow) { struct VfsInfo *root; VFS_LOGF("VfsTraverse(\"%s\", %p, %d)", path, output, follow); if (path == NULL || output == NULL) { efault(); return -1; } root = NULL; if (path[0] != '/') { unassert(!VfsAcquireInfo(g_cwdinfo, output)); } else { unassert(!VfsAcquireInfo(g_rootinfo, output)); } if (VfsTraverseStackBuild(output, path, root, follow, 0) == -1) { unassert(!VfsFreeInfo(*output)); return -1; } return 0; } ssize_t VfsPathBuildFull(struct VfsInfo *info, struct VfsInfo *root, char **output) { struct VfsInfo *current; size_t len, currentlen; len = 0; current = info; if (root == NULL) { root = g_rootinfo; } if (current->dev == root->dev && current->ino == root->ino) { *output = strdup("/"); if (*output == NULL) { return enomem(); } return 1; } while (current && (current->dev != root->dev || current->ino != root->ino)) { len += current->namelen + 1; current = current->parent; } if (current == NULL) { *output = strdup(VFS_UNREACHABLE); if (*output == NULL) { return enomem(); } return sizeof(VFS_UNREACHABLE) - 1; } *output = (char *)malloc(len + 1); if (*output == NULL) { return enomem(); } (*output)[len] = '\0'; current = info; currentlen = len; while (current && (current->dev != root->dev || current->ino != root->ino)) { currentlen -= current->namelen; memcpy(*output + currentlen, current->name, current->namelen); if (currentlen != 0) { --currentlen; (*output)[currentlen] = '/'; } current = current->parent; } return len; } ssize_t VfsPathBuild(struct VfsInfo *info, struct VfsInfo *root, bool absolute, char output[VFS_PATH_MAX]) { struct VfsInfo *current; size_t len, currentlen; len = 0; current = info; VFS_LOGF("VfsPathBuild(%p, %p, %d, %p)", info, root, absolute, output); if (root == NULL) { root = g_rootinfo; } if (current->dev == root->dev && current->ino == root->ino) { if (absolute) { memcpy(output, "/", 2); return 1; } else { output[0] = '\0'; return 0; } } while (current && (current->dev != root->dev || current->ino != root->ino)) { len += current->namelen + 1; current = current->parent; } if (current == NULL) { memcpy(output, VFS_UNREACHABLE, sizeof(VFS_UNREACHABLE)); return sizeof(VFS_UNREACHABLE) - 1; } len -= !absolute; if (len >= PATH_MAX) { return enametoolong(); } current = info; currentlen = len; output[currentlen] = '\0'; while (current && (current->dev != root->dev || current->ino != root->ino)) { currentlen -= current->namelen; memcpy(output + currentlen, current->name, current->namelen); if (currentlen != 0) { --currentlen; output[currentlen] = '/'; } current = current->parent; } return len; } //////////////////////////////////////////////////////////////////////////////// int VfsAddFdAtOrAfter(struct VfsInfo *data, int minfd) { struct VfsFd *vfsfd; struct Dll *e; vfsfd = (struct VfsFd *)malloc(sizeof(*vfsfd)); if (vfsfd == NULL) { return -1; } vfsfd->data = data; LOCK(&g_vfs.lock); for (e = dll_first(g_vfs.fds); e; e = dll_next(g_vfs.fds, e)) { if (VFS_FD_CONTAINER(e)->fd < minfd) { continue; } else if (VFS_FD_CONTAINER(e)->fd == minfd) { ++minfd; } else { break; } } vfsfd->fd = minfd; dll_init(&vfsfd->elem); if (e == NULL) { dll_make_last(&g_vfs.fds, &vfsfd->elem); } else { e = dll_prev(g_vfs.fds, e); if (e == NULL) { dll_make_first(&g_vfs.fds, &vfsfd->elem); } else { dll_splice_after(e, &vfsfd->elem); } } UNLOCK(&g_vfs.lock); return vfsfd->fd; } int VfsAddFd(struct VfsInfo *data) { return VfsAddFdAtOrAfter(data, 0); } /** * Closes the emulated file descriptor fd and returns the data associated with * it. */ int VfsFreeFd(int fd, struct VfsInfo **data) { struct Dll *e; struct VfsFd *vfsfd; LOCK(&g_vfs.lock); for (e = dll_first(g_vfs.fds); e;) { vfsfd = VFS_FD_CONTAINER(e); if (VFS_FD_CONTAINER(e)->fd == fd) { *data = vfsfd->data; dll_remove(&g_vfs.fds, &vfsfd->elem); free(vfsfd); VFS_LOGF("VfsFreeFd(%d)", fd); UNLOCK(&g_vfs.lock); return 0; } e = dll_next(g_vfs.fds, e); } UNLOCK(&g_vfs.lock); return ebadf(); } int VfsGetFd(int fd, struct VfsInfo **output) { struct Dll *e; LOCK(&g_vfs.lock); for (e = dll_first(g_vfs.fds); e; e = dll_next(g_vfs.fds, e)) { if (VFS_FD_CONTAINER(e)->fd == fd) { UNLOCK(&g_vfs.lock); unassert(!VfsAcquireInfo(VFS_FD_CONTAINER(e)->data, output)); return 0; } } UNLOCK(&g_vfs.lock); return ebadf(); } int VfsSetFd(int fd, struct VfsInfo *data) { struct Dll *e; struct VfsFd *vfsfd; LOCK(&g_vfs.lock); for (e = dll_first(g_vfs.fds); e; e = dll_next(g_vfs.fds, e)) { if (VFS_FD_CONTAINER(e)->fd == fd) { unassert(!VfsFreeInfo(VFS_FD_CONTAINER(e)->data)); VFS_FD_CONTAINER(e)->data = data; UNLOCK(&g_vfs.lock); return 0; } else if (VFS_FD_CONTAINER(e)->fd > fd) { break; } } vfsfd = (struct VfsFd *)malloc(sizeof(*vfsfd)); if (vfsfd == NULL) { UNLOCK(&g_vfs.lock); return enomem(); } vfsfd->data = data; vfsfd->fd = fd; dll_init(&vfsfd->elem); if (e == NULL) { dll_make_last(&g_vfs.fds, &vfsfd->elem); } else if ((e = dll_prev(g_vfs.fds, e))) { dll_splice_after(e, &vfsfd->elem); } else { dll_make_first(&g_vfs.fds, &vfsfd->elem); } UNLOCK(&g_vfs.lock); return 0; } //////////////////////////////////////////////////////////////////////////////// int VfsChdir(const char *path) { struct VfsInfo *info, *tmp; int ret = 0; VFS_LOGF("VfsChdir(\"%s\")", path); if (path == NULL) { return efault(); } if (*path == '\0') { return enoent(); } if (VfsTraverse(path, &info, true) == -1) { return -1; } if (!S_ISDIR(info->mode)) { ret = enotdir(); } else { tmp = g_cwdinfo; g_cwdinfo = info; info = tmp; } unassert(!VfsFreeInfo(info)); return ret; } int VfsFchdir(int fd) { struct VfsInfo *info, *tmp; int ret = 0; VFS_LOGF("VfsFchdir(%d)", fd); if (VfsGetFd(fd, &info) != 0) { return -1; } if (!S_ISDIR(info->mode)) { ret = enotdir(); } else { tmp = g_cwdinfo; g_cwdinfo = info; info = tmp; } unassert(!VfsFreeInfo(info)); return ret; } int VfsChroot(const char *path) { struct VfsInfo *info, *tmp; int ret = 0; VFS_LOGF("VfsChroot(\"%s\")", path); if (path == NULL) { return efault(); } if (*path == '\0') { return enoent(); } if (VfsTraverse(path, &info, true) != 0) { return -1; } if (!S_ISDIR(info->mode)) { ret = enotdir(); } else { tmp = g_rootinfo; g_rootinfo = info; info = tmp; } unassert(!VfsFreeInfo(info)); return ret; } char *VfsGetcwd(char *buf, size_t size) { char cwd[VFS_PATH_MAX]; if (buf == NULL) { efault(); return NULL; } if (size == 0) { return buf; } if (VfsPathBuild(g_cwdinfo, NULL, true, cwd) == -1) { return NULL; } strncpy(buf, cwd, size); buf[size - 1] = '\0'; return buf; } static int VfsHandleDirfdName(int dirfd, const char *name, struct VfsInfo **parent, char leaf[VFS_NAME_MAX]) { struct VfsInfo *dir = NULL, *tmp = NULL; const char *p, *q; char *parentname = NULL; if (name[0] == '/') { unassert(!VfsAcquireInfo(g_rootinfo, &dir)); } else if (dirfd == AT_FDCWD) { unassert(!VfsAcquireInfo(g_cwdinfo, &dir)); } else { if (VfsGetFd(dirfd, &dir) == -1) { goto cleananddie; } } if (!strcmp(name, "/")) { strcpy(leaf, "/"); *parent = dir; return 0; } if (!S_ISDIR(dir->mode)) { enotdir(); goto cleananddie; } for (p = name, q = name; *p; ++p) { if (*p == '/' && p[1]) { q = p + 1; } } if (p - q >= VFS_NAME_MAX) { enametoolong(); goto cleananddie; } parentname = strndup(name, q - name); if (parentname == NULL) { goto cleananddie; } if (VfsTraverseStackBuild(&dir, parentname, g_rootinfo, true, 0) == -1) { goto cleananddie; } if (!strcmp(q, "..") && dir->parent) { unassert(!VfsAcquireInfo(dir->parent, &tmp)); unassert(!VfsFreeInfo(dir)); dir = tmp; memcpy(leaf, ".", 2); } else { memcpy(leaf, q, p - q + 1); } *parent = dir; free(parentname); return 0; cleananddie: free(parentname); unassert(!VfsFreeInfo(dir)); return -1; } static int VfsHandleDirfdSymlink(struct VfsInfo **dir, char name[VFS_NAME_MAX]) { int level = 0; char *buf, *s; struct VfsInfo *tmp; ssize_t linklen; VFS_LOGF("VfsHandleDirfdSymlink(%p, %p)", dir, name); buf = NULL; tmp = NULL; while (true) { if (++level > VFS_TRAVERSE_MAX_LINKS) { return eloop(); } if (!(*dir)->device->ops->Finddir || !(*dir)->device->ops->Readlink) { return eperm(); } if ((*dir)->device->ops->Finddir(*dir, name, &tmp) == -1) { if (errno != ENOENT) { return -1; } else { break; } } if (!S_ISLNK(tmp->mode)) { unassert(!VfsFreeInfo(tmp)); break; } if ((linklen = (*dir)->device->ops->Readlink(tmp, &buf)) == -1) { goto cleananddie; } unassert(!VfsFreeInfo(tmp)); tmp = NULL; if (buf[0] == '/') { if (VfsHandleDirfdName(AT_FDCWD, buf, &tmp, name) == -1) { goto cleananddie; } unassert(!VfsFreeInfo(*dir)); *dir = tmp; } else { for (s = buf + linklen; s >= buf; --s) { if (*s == '/') { break; } } ++s; if (buf + linklen - s >= VFS_NAME_MAX) { enametoolong(); goto cleananddie; } memmove(name, s, buf + linklen - s + 1); *s = '\0'; if (s != buf) { if (VfsTraverseStackBuild(dir, buf, NULL, true, 0) == -1) { goto cleananddie; } } } free(buf); buf = NULL; } return 0; cleananddie: free(buf); unassert(!VfsFreeInfo(tmp)); return -1; } int VfsUnlink(int dirfd, const char *name, int flags) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret; VFS_LOGF("VfsUnlink(%d, \"%s\", %d)", dirfd, name, flags); if (name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } unassert(!VfsTraverseMount(&dir, newname)); if (dir->device->ops->Unlink) { ret = dir->device->ops->Unlink(dir, newname, flags); } else { ret = eperm(); } unassert(!VfsFreeInfo(dir)); return ret; } int VfsMkdir(int dirfd, const char *name, mode_t mode) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret; VFS_LOGF("VfsMkdir(%d, \"%s\", %d)", dirfd, name, mode); if (name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } unassert(!VfsTraverseMount(&dir, newname)); if (dir->device->ops->Mkdir) { ret = dir->device->ops->Mkdir(dir, newname, mode); } else { ret = eperm(); } unassert(!VfsFreeInfo(dir)); return ret; } int VfsMkfifo(int dirfd, const char *name, mode_t mode) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret; VFS_LOGF("VfsMkfifo(%d, \"%s\", %d)", dirfd, name, mode); if (name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } unassert(!VfsTraverseMount(&dir, newname)); if (dir->device->ops->Mkfifo) { ret = dir->device->ops->Mkfifo(dir, newname, mode); } else { ret = eperm(); } unassert(!VfsFreeInfo(dir)); return ret; } int VfsOpen(int dirfd, const char *name, int flags, int mode) { struct VfsInfo *dir, *out; char newname[VFS_NAME_MAX]; int ret = 0; VFS_LOGF("VfsOpen(%d, \"%s\", %d, %d)", dirfd, name, flags, mode); if (name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } if (!(flags & O_NOFOLLOW)) { ret = VfsHandleDirfdSymlink(&dir, newname); } unassert(!VfsTraverseMount(&dir, newname)); if (ret != -1) { if (dir->device->ops->Open) { if (dir->device->ops->Open(dir, newname, flags, mode, &out) == -1) { ret = -1; } else { ret = VfsAddFd(out); } } else { ret = eperm(); } } unassert(!VfsFreeInfo(dir)); return ret; } int VfsChmod(int dirfd, const char *name, mode_t mode, int flags) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret = 0; VFS_LOGF("VfsChmod(%d, \"%s\", %d, %d)", dirfd, name, mode, flags); if (name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } if (!(flags & AT_SYMLINK_NOFOLLOW)) { ret = VfsHandleDirfdSymlink(&dir, newname); } unassert(!VfsTraverseMount(&dir, newname)); if (ret != -1) { if (dir->device->ops->Chmod) { ret = dir->device->ops->Chmod(dir, newname, mode, flags); } else { ret = eperm(); } } unassert(!VfsFreeInfo(dir)); return ret; } int VfsFchmod(int fd, mode_t mode) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFchmod(%d, %d)", fd, mode); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Fchmod) { ret = info->device->ops->Fchmod(info, mode); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsAccess(int dirfd, const char *name, mode_t mode, int flags) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret = 0; VFS_LOGF("VfsAccess(%d, \"%s\", %d, %d)", dirfd, name, mode, flags); if (name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } if (!(flags & AT_SYMLINK_NOFOLLOW)) { ret = VfsHandleDirfdSymlink(&dir, newname); } unassert(!VfsTraverseMount(&dir, newname)); if (ret != -1) { if (dir->device->ops->Access) { ret = dir->device->ops->Access(dir, newname, mode, flags); } else { ret = eperm(); } } unassert(!VfsFreeInfo(dir)); return ret; } int VfsSymlink(const char *target, int dirfd, const char *name) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret; VFS_LOGF("VfsSymlink(\"%s\", %d, \"%s\")", target, dirfd, name); if (target == NULL || name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } unassert(!VfsTraverseMount(&dir, newname)); if (dir->device->ops->Symlink) { ret = dir->device->ops->Symlink(target, dir, newname); } else { ret = eperm(); } unassert(!VfsFreeInfo(dir)); return ret; } int VfsStat(int dirfd, const char *name, struct stat *st, int flags) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret = 0; VFS_LOGF("VfsStat(%d, \"%s\", %p, %d)", dirfd, name, st, flags); if (name == NULL || st == NULL) { return efault(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } if (!(flags & AT_SYMLINK_NOFOLLOW)) { ret = VfsHandleDirfdSymlink(&dir, newname); } unassert(!VfsTraverseMount(&dir, newname)); if (ret != -1) { if (dir->device->ops->Stat) { ret = dir->device->ops->Stat(dir, newname, st, flags); } else { ret = eperm(); } } unassert(!VfsFreeInfo(dir)); return ret; } int VfsChown(int dirfd, const char *name, uid_t uid, gid_t gid, int flags) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret = 0; VFS_LOGF("VfsChown(%d, \"%s\", %d, %d, %d)", dirfd, name, uid, gid, flags); if (name == NULL) { return efault(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } if (!(flags & AT_SYMLINK_NOFOLLOW)) { ret = VfsHandleDirfdSymlink(&dir, newname); } unassert(!VfsTraverseMount(&dir, newname)); if (ret != -1) { if (dir->device->ops->Chown) { ret = dir->device->ops->Chown(dir, newname, uid, gid, flags); } else { ret = eperm(); } } unassert(!VfsFreeInfo(dir)); return ret; } int VfsFchown(int fd, uid_t uid, gid_t gid) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFchown(%d, %d, %d)", fd, uid, gid); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Fchown) { ret = info->device->ops->Fchown(info, uid, gid); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsRename(int olddirfd, const char *oldname, int newdirfd, const char *newname) { struct VfsInfo *olddir, *newdir; char newoldname[VFS_NAME_MAX], newnewname[VFS_NAME_MAX]; int ret; VFS_LOGF("VfsRename(%d, \"%s\", %d, \"%s\")", olddirfd, oldname, newdirfd, newname); if (oldname == NULL || newname == NULL) { return efault(); } if (!*oldname || !*newname) { return enoent(); } if (VfsHandleDirfdName(olddirfd, oldname, &olddir, newoldname) == -1) { return -1; } if (VfsHandleDirfdName(newdirfd, newname, &newdir, newnewname) == -1) { unassert(!VfsFreeInfo(olddir)); return -1; } unassert(!VfsTraverseMount(&olddir, newoldname)); unassert(!VfsTraverseMount(&newdir, newnewname)); if (olddir->device->ops->Rename) { ret = olddir->device->ops->Rename(olddir, newoldname, newdir, newnewname); } else { ret = eperm(); } unassert(!VfsFreeInfo(olddir)); unassert(!VfsFreeInfo(newdir)); return ret; } ssize_t VfsReadlink(int dirfd, const char *name, char *buf, size_t bufsiz) { struct VfsInfo *dir, *file; ssize_t ret; char *tmp; char newname[VFS_NAME_MAX]; VFS_LOGF("VfsReadlink(%d, \"%s\", %p, %zu)", dirfd, name, buf, bufsiz); if (name == NULL || buf == NULL) { return efault(); } if (*name == '\0') { dir = NULL; if (VfsGetFd(dirfd, &file) == -1) { return -1; } } else { if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } if (!dir->device->ops->Finddir || dir->device->ops->Finddir(dir, newname, &file) == -1) { unassert(!VfsFreeInfo(dir)); return -1; } } if (file->device->ops->Readlink) { ret = file->device->ops->Readlink(file, &tmp); if (ret != -1) { memcpy(buf, tmp, MIN(ret, bufsiz)); ret = MIN(ret, bufsiz); free(tmp); } } else { ret = eperm(); } unassert(!VfsFreeInfo(dir)); unassert(!VfsFreeInfo(file)); return ret; } int VfsLink(int olddirfd, const char *oldname, int newdirfd, const char *newname, int flags) { struct VfsInfo *olddir, *newdir; char newoldname[VFS_NAME_MAX], newnewname[VFS_NAME_MAX]; int ret; VFS_LOGF("VfsLink(%d, \"%s\", %d, \"%s\", %d)", olddirfd, oldname, newdirfd, newname, flags); if (oldname == NULL || newname == NULL) { return efault(); } if (!*oldname || !*newname) { return enoent(); } // AT_EMPTY_PATH currently not supported by blink's syscall subsystem. if (VfsHandleDirfdName(olddirfd, oldname, &olddir, newoldname) == -1) { return -1; } if (flags & AT_SYMLINK_FOLLOW) { if (VfsHandleDirfdName(olddirfd, oldname, &olddir, newoldname) == -1) { unassert(!VfsFreeInfo(olddir)); return -1; } } unassert(!VfsTraverseMount(&olddir, newoldname)); if (VfsHandleDirfdName(newdirfd, newname, &newdir, newnewname) == -1) { unassert(!VfsFreeInfo(olddir)); return -1; } unassert(!VfsTraverseMount(&newdir, newnewname)); if (olddir->device != newdir->device) { ret = exdev(); } else if (olddir->device->ops->Link) { ret = olddir->device->ops->Link(olddir, newoldname, newdir, newnewname, flags); } else { ret = eperm(); } unassert(!VfsFreeInfo(olddir)); unassert(!VfsFreeInfo(newdir)); return ret; } int VfsUtime(int dirfd, const char *name, const struct timespec times[2], int flags) { struct VfsInfo *dir; char newname[VFS_NAME_MAX]; int ret = -1; VFS_LOGF("VfsUtime(%d, \"%s\", %p, %d)", dirfd, name, times, flags); if (name == NULL) { return efault(); } if (!*name) { return enoent(); } if (VfsHandleDirfdName(dirfd, name, &dir, newname) == -1) { return -1; } if (!(flags & AT_SYMLINK_NOFOLLOW)) { ret = VfsHandleDirfdSymlink(&dir, newname); } unassert(!VfsTraverseMount(&dir, newname)); if (ret != -1) { if (dir->device->ops->Utime) { ret = dir->device->ops->Utime(dir, newname, times, flags); } else { ret = eperm(); } } unassert(!VfsFreeInfo(dir)); return ret; } int VfsFutime(int fd, const struct timespec times[2]) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFutime(%d, %p)", fd, times); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Futime) { ret = info->device->ops->Futime(info, times); } else { unassert(!VfsFreeInfo(info)); return eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsFstat(int fd, struct stat *st) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFstat(%d, %p)", fd, st); if (st == NULL) { return efault(); } if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Fstat) { ret = info->device->ops->Fstat(info, st); } else { unassert(!VfsFreeInfo(info)); return eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsFtruncate(int fd, off_t length) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFtruncate(%d, %ld)", fd, length); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Ftruncate) { ret = info->device->ops->Ftruncate(info, length); } else { unassert(!VfsFreeInfo(info)); return eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsClose(int fd) { struct VfsInfo *info; int ret = 0; VFS_LOGF("VfsClose(%d)", fd); if (VfsFreeFd(fd, &info) == -1) { return -1; } if (info->device->ops->Close) { ret = info->device->ops->Close(info); } if (ret != -1) { unassert(!VfsFreeInfo(info)); } return ret; } ssize_t VfsRead(int fd, void *buf, size_t nbyte) { struct VfsInfo *info; int ret; VFS_LOGF("VfsRead(%d, %p, %zu)", fd, buf, nbyte); if (buf == NULL) { return efault(); } if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Read) { ret = info->device->ops->Read(info, buf, nbyte); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsWrite(int fd, const void *buf, size_t nbyte) { struct VfsInfo *info; int ret; VFS_LOGF("VfsWrite(%d, %p, %zu)", fd, buf, nbyte); if (buf == NULL) { return efault(); } if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Write) { ret = info->device->ops->Write(info, buf, nbyte); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsPread(int fd, void *buf, size_t nbyte, off_t offset) { struct VfsInfo *info; int ret; VFS_LOGF("VfsPread(%d, %p, %zu, %ld)", fd, buf, nbyte, offset); if (buf == NULL) { return efault(); } if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Pread) { ret = info->device->ops->Pread(info, buf, nbyte, offset); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsPwrite(int fd, const void *buf, size_t nbyte, off_t offset) { struct VfsInfo *info; int ret; VFS_LOGF("VfsPwrite(%d, %p, %zu, %ld)", fd, buf, nbyte, offset); if (buf == NULL) { return efault(); } if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Pwrite) { ret = info->device->ops->Pwrite(info, buf, nbyte, offset); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsReadv(int fd, const struct iovec *iov, int iovcnt) { struct VfsInfo *info; int ret; VFS_LOGF("VfsReadv(%d, %p, %d)", fd, iov, iovcnt); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Readv) { ret = info->device->ops->Readv(info, iov, iovcnt); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsWritev(int fd, const struct iovec *iov, int iovcnt) { struct VfsInfo *info; int ret; VFS_LOGF("VfsWritev(%d, %p, %d)", fd, iov, iovcnt); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Writev) { ret = info->device->ops->Writev(info, iov, iovcnt); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsPreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { struct VfsInfo *info; int ret; VFS_LOGF("VfsPreadv(%d, %p, %d, %ld)", fd, iov, iovcnt, offset); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Preadv) { ret = info->device->ops->Preadv(info, iov, iovcnt, offset); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsPwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { struct VfsInfo *info; int ret; VFS_LOGF("VfsPwritev(%d, %p, %d, %ld)", fd, iov, iovcnt, offset); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Pwritev) { ret = info->device->ops->Pwritev(info, iov, iovcnt, offset); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } off_t VfsSeek(int fd, off_t offset, int whence) { struct VfsInfo *info; off_t ret; VFS_LOGF("VfsSeek(%d, %ld, %d)", fd, offset, whence); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Seek) { ret = info->device->ops->Seek(info, offset, whence); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsFsync(int fd) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFsync(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Fsync) { ret = info->device->ops->Fsync(info); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsFdatasync(int fd) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFdatasync(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Fdatasync) { ret = info->device->ops->Fdatasync(info); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsFlock(int fd, int operation) { struct VfsInfo *info; int ret; VFS_LOGF("VfsFlock(%d, %d)", fd, operation); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Flock) { ret = info->device->ops->Flock(info, operation); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsFcntl(int fd, int cmd, ...) { struct VfsInfo *info, *newinfo; int ret; va_list ap; VFS_LOGF("VfsFcntl(%d, %d, ...)", fd, cmd); if (VfsGetFd(fd, &info) == -1) { return -1; } va_start(ap, cmd); // CLOEXEC is already handled by the syscall layer. if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) { if (info->device->ops->Dup) { ret = info->device->ops->Dup(info, &newinfo); if (ret != -1) { ret = VfsAddFdAtOrAfter(newinfo, va_arg(ap, int)); if (ret == -1) { unassert(!VfsFreeInfo(newinfo)); } } } else { unassert(!VfsFreeInfo(info)); ret = eperm(); } } else { if (info->device->ops->Fcntl) { ret = info->device->ops->Fcntl(info, cmd, ap); } else { ret = eperm(); } } va_end(ap); unassert(!VfsFreeInfo(info)); return ret; } int VfsIoctl(int fd, unsigned long request, void *arg) { struct VfsInfo *info; int ret; VFS_LOGF("VfsIoctl(%d, %lu, %p)", fd, request, arg); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Ioctl) { ret = info->device->ops->Ioctl(info, request, arg); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } int VfsDup(int fd) { struct VfsInfo *info, *newinfo; int ret; VFS_LOGF("VfsDup(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Dup) { ret = info->device->ops->Dup(info, &newinfo); if (ret != -1) { ret = VfsAddFd(newinfo); if (ret == -1) { unassert(!VfsFreeInfo(newinfo)); } } } else { unassert(!VfsFreeInfo(info)); return eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsDup2(int fd, int newfd) { struct VfsInfo *info, *newinfo; int ret; VFS_LOGF("VfsDup2(%d, %d)", fd, newfd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (VfsFreeFd(newfd, &newinfo) == 0) { unassert(!VfsFreeInfo(newinfo)); } if (info->device->ops->Dup) { ret = info->device->ops->Dup(info, &newinfo); if (ret != -1) { ret = VfsSetFd(newfd, newinfo); if (ret != -1) { ret = newfd; } } } else { unassert(!VfsFreeInfo(info)); return eperm(); } unassert(!VfsFreeInfo(info)); return ret; } #ifdef HAVE_DUP3 int VfsDup3(int fd, int newfd, int flags) { struct VfsInfo *info, *newinfo; int ret; VFS_LOGF("VfsDup3(%d, %d, %d)", fd, newfd, flags); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Dup3) { ret = info->device->ops->Dup3(info, &newinfo, flags); if (ret != -1) { ret = VfsSetFd(newfd, newinfo); if (ret != -1) { ret = newfd; } } } else { unassert(!VfsFreeInfo(info)); return eperm(); } unassert(!VfsFreeInfo(info)); return ret; } #endif int VfsPoll(struct pollfd *fds, nfds_t nfds, int timeout) { struct VfsInfo *info; int ret; VFS_LOGF("VfsPoll(%p, %lld, %d)", fds, (long long)nfds, timeout); // Currently, blink only uses poll with nfds = 1 and timeout = 0 unassert(nfds == 1); unassert(timeout == 0); if (VfsGetFd(fds[0].fd, &info) == -1) { return -1; } if (info->device->ops->Poll) { ret = info->device->ops->Poll(&info, fds, 1, timeout); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timespec *timeout, sigset_t *sigmask) { VFS_LOGF("VfsSelect(%d, %p, %p, %p, %p, %p)", nfds, readfds, writefds, exceptfds, timeout, sigmask); return enosys(); } DIR *VfsOpendir(int fd) { struct VfsInfo *info; DIR *ret; VFS_LOGF("VfsOpendir(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return NULL; } if (info->device->ops->Opendir) { if (info->device->ops->Opendir(info, (struct VfsInfo **)&ret) == -1) { ret = NULL; } } else { eperm(); } unassert(!VfsFreeInfo(info)); return ret; } #ifdef HAVE_SEEKDIR void VfsSeekdir(DIR *dir, long loc) { struct VfsInfo *info; VFS_LOGF("VfsSeekdir(%p, %ld)", dir, loc); info = (struct VfsInfo *)dir; if (info->device->ops->Seekdir) { info->device->ops->Seekdir(info, loc); } else { VFS_LOGF("seekdir() not supported by device %p.", info->device); eperm(); return; } } long VfsTelldir(DIR *dir) { struct VfsInfo *info; long ret; VFS_LOGF("VfsTelldir(%p)", dir); info = (struct VfsInfo *)dir; if (info->device->ops->Telldir) { ret = info->device->ops->Telldir(info); } else { VFS_LOGF("telldir() not supported by device %p.", info->device); return eperm(); } return ret; } #endif struct dirent *VfsReaddir(DIR *dir) { struct VfsInfo *info; struct dirent *ret; VFS_LOGF("VfsReaddir(%p)", dir); info = (struct VfsInfo *)dir; if (info->device->ops->Readdir) { ret = info->device->ops->Readdir(info); } else { VFS_LOGF("readdir() not supported by device %p.", info->device); eperm(); ret = NULL; } return ret; } void VfsRewinddir(DIR *dir) { struct VfsInfo *info; VFS_LOGF("VfsRewindDir(%p)", dir); info = (struct VfsInfo *)dir; if (info->device->ops->Rewinddir) { info->device->ops->Rewinddir(info); } else { VFS_LOGF("rewinddir() not supported by device %p.", info->device); eperm(); return; } } int VfsClosedir(DIR *dir) { struct VfsInfo *info; struct Dll *e; struct VfsFd *vfsfd; int ret; VFS_LOGF("VfsClosedir(%p)", dir); info = (struct VfsInfo *)dir; if (info->device->ops->Closedir) { ret = info->device->ops->Closedir(info); if (ret != -1) { LOCK(&g_vfs.lock); for (e = dll_first(g_vfs.fds); e;) { vfsfd = VFS_FD_CONTAINER(e); e = dll_next(g_vfs.fds, e); if (vfsfd->data == info) { unassert(!VfsFreeInfo(vfsfd->data)); dll_remove(&g_vfs.fds, &vfsfd->elem); free(vfsfd); break; } } UNLOCK(&g_vfs.lock); } } else { ret = eperm(); } return ret; } int VfsBind(int fd, const struct sockaddr *addr, socklen_t addrlen) { struct VfsInfo *info, *dir, *oldparent; struct VfsDevice *olddevice; char newname[PATH_MAX]; int ret; VFS_LOGF("VfsBind(%d, %p, %d)", fd, addr, addrlen); if (VfsGetFd(fd, &info) == -1) { return -1; } if (addr->sa_family != AF_UNIX) { ret = HostfsBind(info, addr, addrlen); } else { if (VfsHandleDirfdName(AT_FDCWD, addr->sa_data, &dir, newname) == -1) { ret = -1; } else { oldparent = info->parent; unassert(!VfsAcquireInfo(dir, &info->parent)); olddevice = info->device; unassert(!VfsAcquireDevice(dir->device, &info->device)); info->name = strdup(newname); if (!info->name) { ret = enomem(); } else { info->namelen = strlen(info->name); // The new driver should know the info's parent, name and device. // The data still belongs to hostfs, which should be freed and replaced // with its own. ret = dir->device->ops->Bind(info, addr, addrlen); if (ret == -1) { unassert(!VfsFreeInfo(info->parent)); info->parent = oldparent; unassert(!VfsFreeDevice(info->device)); info->device = olddevice; free((void *)info->name); info->name = NULL; info->namelen = 0; } else { unassert(!VfsFreeInfo(oldparent)); unassert(!VfsFreeDevice(olddevice)); } } unassert(!VfsFreeInfo(dir)); } } unassert(!VfsFreeInfo(info)); return ret; } int VfsConnect(int fd, const struct sockaddr *addr, socklen_t addrlen) { struct VfsInfo *info, *sock; const char *name; int ret; VFS_LOGF("VfsConnect(%d, %p, %d)", fd, addr, addrlen); if (VfsGetFd(fd, &info) == -1) { return -1; } // TODO: Handle abstract sockets (sa_data[0] == '\0') on non-Linux // platforms. if (addr->sa_family != AF_UNIX || addr->sa_data[0] == '\0') { ret = HostfsConnect(info, addr, addrlen); } else { name = ((struct sockaddr_un *)addr)->sun_path; if (VfsTraverse(name, &sock, false) == -1) { ret = -1; } else { if (info->device->ops->Connectunix) { ret = info->device->ops->Connectunix( sock, info, (const struct sockaddr_un *)addr, addrlen); } else { ret = eperm(); } unassert(!VfsFreeInfo(sock)); } } unassert(!VfsFreeInfo(info)); return ret; } int VfsAccept(int fd, struct sockaddr *addr, socklen_t *addrlen) { struct VfsInfo *info, *newinfo; int ret; VFS_LOGF("VfsAccept(%d, %p, %p)", fd, addr, addrlen); if (VfsGetFd(fd, &info) == -1) { return -1; } if (addr->sa_family != AF_UNIX) { ret = HostfsAccept(info, addr, addrlen, &newinfo); } else { if (info->device->ops->Accept) { ret = info->device->ops->Accept(info, addr, addrlen, &newinfo); } else { ret = eperm(); } } if (ret != -1) { ret = VfsAddFd(newinfo); if (ret == -1) { unassert(!VfsFreeInfo(newinfo)); } } unassert(!VfsFreeInfo(info)); return ret; } int VfsListen(int fd, int backlog) { struct VfsInfo *info; int ret; VFS_LOGF("VfsListen(%d, %d)", fd, backlog); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Listen) { ret = info->device->ops->Listen(info, backlog); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsShutdown(int fd, int how) { struct VfsInfo *info; int ret; VFS_LOGF("VfsShutdown(%d, %d)", fd, how); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Shutdown) { ret = info->device->ops->Shutdown(info, how); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsRecvmsg(int fd, struct msghdr *msg, int flags) { struct VfsInfo *info, *sock; const char *name; int ret; VFS_LOGF("VfsRecvmsg(%d, %p, %d)", fd, msg, flags); if (VfsGetFd(fd, &info) == -1) { return -1; } if (msg->msg_name && ((struct sockaddr *)msg->msg_name)->sa_family == AF_UNIX) { name = ((struct sockaddr_un *)msg->msg_name)->sun_path; if (VfsTraverse(name, &sock, false) == -1) { ret = -1; } else { if (sock->device->ops->Recvmsgunix) { ret = sock->device->ops->Recvmsgunix(sock, info, msg, flags); } else { ret = eperm(); } unassert(!VfsFreeInfo(sock)); } } if (info->device->ops->Recvmsg) { ret = info->device->ops->Recvmsg(info, msg, flags); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } ssize_t VfsSendmsg(int fd, const struct msghdr *msg, int flags) { struct VfsInfo *info, *sock; const char *name; int ret; VFS_LOGF("VfsSendmsg(%d, %p, %d)", fd, msg, flags); if (VfsGetFd(fd, &info) == -1) { return -1; } if (msg->msg_name && ((struct sockaddr *)msg->msg_name)->sa_family == AF_UNIX) { name = ((struct sockaddr_un *)msg->msg_name)->sun_path; if (VfsTraverse(name, &sock, false) == -1) { ret = -1; } else { if (sock->device->ops->Sendmsgunix) { ret = sock->device->ops->Sendmsgunix(sock, info, msg, flags); } else { ret = eperm(); } unassert(!VfsFreeInfo(sock)); } } else { if (info->device->ops->Sendmsg) { ret = info->device->ops->Sendmsg(info, msg, flags); } else { ret = eperm(); } } unassert(!VfsFreeInfo(info)); return ret; } int VfsGetsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) { struct VfsInfo *info; int ret; VFS_LOGF("VfsGetsockopt(%d, %d, %d, %p, %p)", fd, level, optname, optval, optlen); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Getsockopt) { ret = info->device->ops->Getsockopt(info, level, optname, optval, optlen); } else { ret = eopnotsupp(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsSetsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) { struct VfsInfo *info; int ret; VFS_LOGF("VfsSetsockopt(%d, %d, %d, %p, %u)", fd, level, optname, optval, optlen); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Setsockopt) { ret = info->device->ops->Setsockopt(info, level, optname, optval, optlen); } else { ret = eopnotsupp(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsGetsockname(int fd, struct sockaddr *addr, socklen_t *addrlen) { struct VfsInfo *info; int ret; VFS_LOGF("VfsGetsockname(%d, %p, %p)", fd, addr, addrlen); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Getsockname) { ret = info->device->ops->Getsockname(info, addr, addrlen); } else { ret = eopnotsupp(); } unassert(!VfsFreeInfo(info)); return ret; } int VfsGetpeername(int fd, struct sockaddr *addr, socklen_t *addrlen) { struct VfsInfo *info; int ret; VFS_LOGF("VfsGetpeername(%d, %p, %p)", fd, addr, addrlen); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Getpeername) { ret = info->device->ops->Getpeername(info, addr, addrlen); } else { ret = eopnotsupp(); } unassert(!VfsFreeInfo(info)); return ret; } //////////////////////////////////////////////////////////////////////////////// static bool VfsMemoryRangeOverlap(void *a, size_t alen, void *b, size_t blen) { return ((uintptr_t)a <= (uintptr_t)b && (uintptr_t)b < (uintptr_t)a + alen) || ((uintptr_t)b <= (uintptr_t)a && (uintptr_t)a < (uintptr_t)b + blen); } static bool VfsMemoryRangeContains(void *a, size_t alen, void *b, size_t blen) { return (uintptr_t)a <= (uintptr_t)b && (uintptr_t)b + blen <= (uintptr_t)a + alen; } static int VfsMapFree(struct VfsMap *map) { if (map == NULL) { return 0; } if (VfsFreeInfo(map->data) == -1) { return -1; } free(map); return 0; } static int VfsMapSplit(struct VfsMap *map, void *addr, size_t len, struct VfsMap **left, struct VfsMap **right) { struct VfsMap *l, *r; void *end, *mapend; l = r = NULL; unassert(VfsMemoryRangeOverlap(map->addr, map->len, addr, len)); if ((uintptr_t)map->addr + map->len > (uintptr_t)addr && (uintptr_t)map->addr < (uintptr_t)addr) { l = (struct VfsMap *)malloc(sizeof(*l)); if (!l) return enomem(); l->addr = map->addr; l->len = (uintptr_t)addr - (uintptr_t)map->addr; l->offset = map->offset; l->prot = map->prot; l->flags = map->flags; unassert(!VfsAcquireInfo(map->data, &l->data)); dll_init(&l->elem); } if ((uintptr_t)addr + len > (uintptr_t)map->addr && (uintptr_t)addr + len < (uintptr_t)map->addr + map->len) { r = (struct VfsMap *)malloc(sizeof(*r)); if (!r) { unassert(!VfsMapFree(l)); return enomem(); } r->addr = (void *)((uintptr_t)addr + len); r->len = (uintptr_t)map->addr + map->len - ((uintptr_t)addr + len); r->offset = map->offset + ((uintptr_t)addr + len - (uintptr_t)map->addr); r->prot = map->prot; r->flags = map->flags; unassert(!VfsAcquireInfo(map->data, &r->data)); dll_init(&r->elem); } end = (void *)((uintptr_t)addr + len); mapend = (void *)((uintptr_t)map->addr + map->len); map->addr = (void *)MAX((uintptr_t)map->addr, (uintptr_t)addr); map->len = MIN((uintptr_t)mapend, (uintptr_t)end) - (uintptr_t)map->addr; *left = l; *right = r; return 0; } static int VfsMapListExtractAffectedRange(struct Dll **maps, void *addr, size_t len, struct Dll **original, struct Dll **modified, struct Dll **before) { struct Dll *e, *f; struct VfsMap *map, *newmap, *newmapleft = 0, *newmapright = 0; e = dll_first(*maps); while (e && !VfsMemoryRangeOverlap(VFS_MAP_CONTAINER(e)->addr, VFS_MAP_CONTAINER(e)->len, addr, len)) { e = dll_next(*maps, e); } if (!e) { *original = *modified = *before = NULL; return 0; } *original = *modified = NULL; *before = dll_prev(*maps, e); while (e && (map = VFS_MAP_CONTAINER(e)) && VfsMemoryRangeOverlap(map->addr, map->len, addr, len)) { newmap = (struct VfsMap *)malloc(sizeof(*newmap)); if (!newmap) return enomem(); newmap->addr = map->addr; newmap->len = map->len; newmap->offset = map->offset; newmap->prot = map->prot; newmap->flags = map->flags; unassert(!VfsAcquireInfo(map->data, &newmap->data)); dll_init(&newmap->elem); if (VfsMapSplit(newmap, addr, len, &newmapleft, &newmapright) == -1) { unassert(!VfsMapFree(newmap)); if (before == NULL) { e = dll_first(*original); dll_remove(original, e); dll_make_first(maps, e); dll_splice_after(e, dll_first(*original)); } else { dll_splice_after(*before, dll_first(*original)); } for (e = dll_first(*modified); e;) { map = VFS_MAP_CONTAINER(e); e = dll_next(*modified, e); dll_remove(modified, &map->elem); unassert(!VfsMapFree(map)); } return -1; } if (newmapleft) { dll_make_last(modified, &newmapleft->elem); } dll_make_last(modified, &newmap->elem); if (newmapright) { dll_make_last(modified, &newmapright->elem); } f = dll_next(*maps, e); dll_remove(maps, e); dll_make_last(original, e); e = f; } return 0; } static void VfsMapListJoin(struct Dll **maps, struct Dll **tojoin, struct Dll *before) { struct Dll *e; if (*tojoin == NULL) { return; } if (before == NULL) { e = dll_first(*tojoin); dll_remove(tojoin, e); dll_make_first(&g_vfs.maps, e); if (!dll_is_empty(*tojoin)) { dll_splice_after(e, dll_first(*tojoin)); } } else { dll_splice_after(before, dll_first(*tojoin)); } } static void VfsMapListFree(struct Dll **tofree) { struct Dll *e; struct VfsMap *map; for (e = dll_first(*tofree); e;) { map = VFS_MAP_CONTAINER(e); e = dll_next(*tofree, e); dll_remove(tofree, &map->elem); unassert(!VfsMapFree(map)); } } //////////////////////////////////////////////////////////////////////////////// void *VfsMmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { struct VfsInfo *info; struct VfsMap *map, *newmap; void *ret; struct Dll *e, *original, *modified, *before; VFS_LOGF("VfsMmap(%p, %zu, %d, %d, %d, %ld)", addr, len, prot, flags, fd, offset); LOCK(&g_vfs.mapslock); info = NULL; original = modified = NULL; newmap = NULL; if (VfsMapListExtractAffectedRange(&g_vfs.maps, addr, len, &original, &modified, &before) == -1) { goto cleananddie; } #ifdef MAP_ANONYMOUS if (flags & MAP_ANONYMOUS) { if ((ret = mmap(addr, len, prot, flags, -1, 0)) == MAP_FAILED) { goto cleananddie; } } else { #else { #endif if (VfsGetFd(fd, &info) == -1) { goto cleananddie; } newmap = (struct VfsMap *)malloc(sizeof(*newmap)); if (!newmap) { goto cleananddie; } newmap->len = len; newmap->offset = offset; newmap->prot = prot; newmap->flags = flags; unassert(!VfsAcquireInfo(info, &newmap->data)); dll_init(&newmap->elem); if (info->device->ops->Mmap) { if ((ret = info->device->ops->Mmap(info, addr, len, prot, flags, offset)) == MAP_FAILED) { goto cleananddie; } newmap->addr = ret; } else { enodev(); goto cleananddie; } } if (flags & MAP_FIXED) { // Successful MAP_FIXED means that the old mappings were unmapped for (e = dll_first(modified); e;) { map = VFS_MAP_CONTAINER(e); if (!VfsMemoryRangeContains(addr, len, map->addr, map->len)) { unassert(!VfsMemoryRangeOverlap(addr, len, map->addr, map->len)); e = dll_next(modified, e); continue; } if (map->data->device->ops->Munmap) { unassert( !map->data->device->ops->Munmap(map->data, map->addr, map->len)); } e = dll_next(modified, e); dll_remove(&modified, &map->elem); unassert(!VfsMapFree(map)); } } if (newmap) { e = dll_last(modified); while (e && (map = VFS_MAP_CONTAINER(e)) && (uintptr_t)map->addr + map->len > (uintptr_t)newmap->addr) { unassert(!VfsMemoryRangeOverlap(map->addr, map->len, newmap->addr, newmap->len)); e = dll_prev(modified, e); } if (e) { dll_splice_after(e, &newmap->elem); } else { dll_make_first(&modified, &newmap->elem); } } VfsMapListFree(&original); VfsMapListJoin(&g_vfs.maps, &modified, before); VfsFreeInfo(info); UNLOCK(&g_vfs.mapslock); return ret; cleananddie: VfsMapListJoin(&g_vfs.maps, &original, before); VfsMapListFree(&modified); VfsFreeInfo(info); UNLOCK(&g_vfs.mapslock); unassert(!VfsMapFree(newmap)); return MAP_FAILED; } int VfsMunmap(void *addr, size_t len) { struct Dll *e; struct VfsMap *map; struct Dll *original, *modified, *before; VFS_LOGF("VfsMunmap(%p, %zu)", addr, len); original = modified = NULL; LOCK(&g_vfs.mapslock); if (VfsMapListExtractAffectedRange(&g_vfs.maps, addr, len, &original, &modified, &before) == -1) { goto cleananddie; } if (munmap(addr, len) == -1) { goto cleananddie; } for (e = dll_first(modified); e;) { map = VFS_MAP_CONTAINER(e); if (!VfsMemoryRangeContains(addr, len, map->addr, map->len)) { unassert(!VfsMemoryRangeOverlap(addr, len, map->addr, map->len)); e = dll_next(modified, e); continue; } if (map->data->device->ops->Munmap) { unassert(!map->data->device->ops->Munmap(map->data, map->addr, map->len)); } e = dll_next(modified, e); dll_remove(&modified, &map->elem); unassert(!VfsMapFree(map)); } VfsMapListFree(&original); VfsMapListJoin(&g_vfs.maps, &modified, before); UNLOCK(&g_vfs.mapslock); return 0; cleananddie: VfsMapListJoin(&g_vfs.maps, &original, before); VfsMapListFree(&modified); UNLOCK(&g_vfs.mapslock); return -1; } int VfsMprotect(void *addr, size_t len, int prot) { struct Dll *e; struct VfsMap *map; struct Dll *original, *modified, *before; VFS_LOGF("VfsMprotect(%p, %zu, %d)", addr, len, prot); original = modified = NULL; LOCK(&g_vfs.mapslock); if (VfsMapListExtractAffectedRange(&g_vfs.maps, addr, len, &original, &modified, &before) == -1) { goto cleananddie; } for (e = dll_first(modified); e; e = dll_next(modified, e)) { map = VFS_MAP_CONTAINER(e); if (!VfsMemoryRangeContains(addr, len, map->addr, map->len)) { unassert(!VfsMemoryRangeOverlap(addr, len, map->addr, map->len)); continue; } if (map->data->device->ops->Mprotect) { if (map->data->device->ops->Mprotect(map->data, map->addr, map->len, prot) == -1) { goto cleananddie; } map->prot = prot; } } if (mprotect(addr, len, prot) == -1) { goto cleananddie; } VfsMapListFree(&original); VfsMapListJoin(&g_vfs.maps, &modified, before); UNLOCK(&g_vfs.mapslock); return 0; cleananddie: if (original != NULL) { for (e = dll_first(original); e; e = dll_next(original, e)) { map = VFS_MAP_CONTAINER(e); if (map->data->device->ops->Mprotect) { unassert(!map->data->device->ops->Mprotect(map->data, map->addr, map->len, map->prot)); } } } VfsMapListJoin(&g_vfs.maps, &original, before); VfsMapListFree(&modified); UNLOCK(&g_vfs.mapslock); return -1; } int VfsMsync(void *addr, size_t len, int flags) { struct Dll *e; struct VfsMap *map; void *currentaddr; size_t currentlen; VFS_LOGF("VfsMsync(%p, %zu, %d)", addr, len, flags); if (msync(addr, len, flags) == -1) { return -1; } LOCK(&g_vfs.mapslock); for (e = dll_first(g_vfs.maps); e; e = dll_next(g_vfs.maps, e)) { map = VFS_MAP_CONTAINER(e); if ((uintptr_t)map->addr + map->len <= (uintptr_t)addr || (uintptr_t)map->addr >= (uintptr_t)addr + len) { continue; } if (!map->data->device->ops->Msync) { UNLOCK(&g_vfs.mapslock); return enodev(); } currentaddr = map->addr; currentlen = map->len; if (currentaddr < addr) { currentlen -= (uintptr_t)addr - (uintptr_t)currentaddr; currentaddr = addr; } if ((uintptr_t)currentaddr + currentlen > (uintptr_t)addr + len) { currentlen = (uintptr_t)addr + len - (uintptr_t)currentaddr; } if (map->data->device->ops->Msync(map->data, currentaddr, currentlen, flags) == -1) { UNLOCK(&g_vfs.mapslock); return -1; } } UNLOCK(&g_vfs.mapslock); return 0; } int VfsTcgetattr(int fd, struct termios *termios_p) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcgetattr(%d, %p)", fd, termios_p); if (termios_p == NULL) { return efault(); } if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcgetattr) { ret = info->device->ops->Tcgetattr(info, termios_p); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } int VfsTcsetattr(int fd, int optional_actions, const struct termios *termios_p) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcsetattr(%d, %d, %p)", fd, optional_actions, termios_p); if (termios_p == NULL) { return efault(); } if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcsetattr) { ret = info->device->ops->Tcsetattr(info, optional_actions, termios_p); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } int VfsTcflush(int fd, int queue_selector) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcflush(%d, %d)", fd, queue_selector); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcflush) { ret = info->device->ops->Tcflush(info, queue_selector); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } int VfsTcdrain(int fd) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcdrain(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcdrain) { ret = info->device->ops->Tcdrain(info); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } int VfsTcsendbreak(int fd, int duration) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcsendbreak(%d, %d)", fd, duration); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcsendbreak) { ret = info->device->ops->Tcsendbreak(info, duration); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } int VfsTcflow(int fd, int action) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcflow(%d, %d)", fd, action); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcflow) { ret = info->device->ops->Tcflow(info, action); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } pid_t VfsTcgetsid(int fd) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcgetsid(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcgetsid) { ret = info->device->ops->Tcgetsid(info); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } pid_t VfsTcgetpgrp(int fd) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcgetpgrp(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcgetpgrp) { ret = info->device->ops->Tcgetpgrp(info); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } int VfsTcsetpgrp(int fd, pid_t pgrp_id) { struct VfsInfo *info; int ret; VFS_LOGF("VfsTcsetpgrp(%d, %d)", fd, pgrp_id); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Tcsetpgrp) { ret = info->device->ops->Tcsetpgrp(info, pgrp_id); } else { errno = ENOTTY; ret = -1; } unassert(!VfsFreeInfo(info)); return ret; } #ifdef HAVE_SOCKATMARK int VfsSockatmark(int fd) { struct VfsInfo *info; int ret; VFS_LOGF("VfsSockatmark(%d)", fd); if (VfsGetFd(fd, &info) == -1) { return -1; } if (info->device->ops->Sockatmark) { ret = info->device->ops->Sockatmark(info); } else { ret = eopnotsupp(); } unassert(!VfsFreeInfo(info)); return ret; } #endif int VfsExecve(const char *pathname, char *const *argv, char *const *envp) { struct VfsInfo *info; int ret; VFS_LOGF("VfsExecve(\"%s\", %p, %p)", pathname, argv, envp); info = NULL; if ((ret = VfsOpen(AT_FDCWD, pathname, O_RDONLY | O_CLOEXEC, 0)) == -1) { return -1; } if (VfsFreeFd(ret, &info) == -1) { return -1; } if (info->device->ops->Fexecve) { ret = info->device->ops->Fexecve(info, argv, envp); } else { ret = eperm(); } unassert(!VfsFreeInfo(info)); return ret; } //////////////////////////////////////////////////////////////////////////////// int VfsPipe(int fds[2]) { struct VfsInfo *infos[2]; VFS_LOGF("VfsPipe(%p)", fds); if (fds == NULL) { return efault(); } if (HostfsPipe(infos) == -1) { return -1; } if ((fds[0] = VfsAddFd(infos[0])) == -1) { VfsFreeInfo(infos[0]); VfsFreeInfo(infos[1]); return -1; } if ((fds[1] = VfsAddFd(infos[1])) == -1) { VfsFreeFd(fds[0], &infos[0]); VfsFreeInfo(infos[0]); VfsFreeInfo(infos[1]); return -1; } return 0; } // TODO(trungnt): pipe2() should be polyfilled not partially disabled #ifdef HAVE_PIPE2 int VfsPipe2(int fds[2], int flags) { struct VfsInfo *infos[2]; VFS_LOGF("VfsPipe2(%p, %d)", fds, flags); if (fds == NULL) { return efault(); } if (HostfsPipe2(infos, flags) == -1) { return -1; } if ((fds[0] = VfsAddFd(infos[0])) == -1) { VfsFreeInfo(infos[0]); VfsFreeInfo(infos[1]); return -1; } if ((fds[1] = VfsAddFd(infos[1])) == -1) { VfsFreeFd(fds[0], &infos[0]); VfsFreeInfo(infos[0]); VfsFreeInfo(infos[1]); return -1; } return 0; } #endif int VfsSocket(int domain, int type, int protocol) { struct VfsInfo *info; int fd; VFS_LOGF("VfsSocket(%d, %d, %d)", domain, type, protocol); if (HostfsSocket(domain, type, protocol, &info) == -1) { return -1; } if ((fd = VfsAddFd(info)) == -1) { unassert(!VfsFreeInfo(info)); return -1; } return fd; } int VfsSocketpair(int domain, int type, int protocol, int fds[2]) { struct VfsInfo *infos[2]; VFS_LOGF("VfsSocketPair(%d, %d, %d, %p)", domain, type, protocol, fds); if (fds == NULL) { return efault(); } if (HostfsSocketpair(domain, type, protocol, infos) == -1) { return -1; } if ((fds[0] = VfsAddFd(infos[0])) == -1) { VfsFreeInfo(infos[0]); VfsFreeInfo(infos[1]); return -1; } if ((fds[1] = VfsAddFd(infos[1])) == -1) { VfsFreeFd(fds[0], &infos[0]); VfsFreeInfo(infos[0]); VfsFreeInfo(infos[1]); return -1; } return 0; } #endif /* DISABLE_VFS */ ================================================ FILE: blink/vfs.h ================================================ #ifndef BLINK_VFS_H_ #define BLINK_VFS_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include "blink/dll.h" #include "blink/macros.h" #include "blink/overlays.h" #include "blink/preadv.h" #include "blink/thread.h" #include "blink/tsan.h" #include "blink/types.h" #define VFS_SYSTEM_ROOT_MOUNT "/SystemRoot" #define VFS_PATH_MAX MAX(PATH_MAX, 4096) #define VFS_NAME_MAX 256 struct VfsDevice; struct VfsMount; struct VfsInfo; struct VfsSystem; struct VfsFd; struct VfsMap; struct Vfs { struct Dll *devices GUARDED_BY(lock); struct Dll *systems GUARDED_BY(lock); struct Dll *fds GUARDED_BY(lock); struct Dll *maps GUARDED_BY(mapslock); pthread_mutex_t_ lock; pthread_mutex_t_ mapslock; }; struct VfsOps { int (*Init)(const char *, u64, const void *, struct VfsDevice **, struct VfsMount **); int (*Freeinfo)(void *); int (*Freedevice)(void *); int (*Readmountentry)(struct VfsDevice *, char **, char **, char **); int (*Finddir)(struct VfsInfo *, const char *, struct VfsInfo **); int (*Traverse)(struct VfsInfo **, const char **, struct VfsInfo *); ssize_t (*Readlink)(struct VfsInfo *, char **); int (*Mkdir)(struct VfsInfo *, const char *, mode_t); int (*Mkfifo)(struct VfsInfo *, const char *, mode_t); int (*Open)(struct VfsInfo *, const char *, int, int, struct VfsInfo **); int (*Access)(struct VfsInfo *, const char *, mode_t, int); int (*Stat)(struct VfsInfo *, const char *, struct stat *, int); int (*Fstat)(struct VfsInfo *, struct stat *); int (*Chmod)(struct VfsInfo *, const char *, mode_t, int); int (*Fchmod)(struct VfsInfo *, mode_t); int (*Chown)(struct VfsInfo *, const char *, uid_t, gid_t, int); int (*Fchown)(struct VfsInfo *, uid_t, gid_t); int (*Ftruncate)(struct VfsInfo *, off_t); int (*Close)(struct VfsInfo *); int (*Link)(struct VfsInfo *, const char *, struct VfsInfo *, const char *, int); int (*Unlink)(struct VfsInfo *, const char *, int); ssize_t (*Read)(struct VfsInfo *, void *, size_t); ssize_t (*Write)(struct VfsInfo *, const void *, size_t); ssize_t (*Pread)(struct VfsInfo *, void *, size_t, off_t); ssize_t (*Pwrite)(struct VfsInfo *, const void *, size_t, off_t); ssize_t (*Readv)(struct VfsInfo *, const struct iovec *, int); ssize_t (*Writev)(struct VfsInfo *, const struct iovec *, int); ssize_t (*Preadv)(struct VfsInfo *, const struct iovec *, int, off_t); ssize_t (*Pwritev)(struct VfsInfo *, const struct iovec *, int, off_t); off_t (*Seek)(struct VfsInfo *, off_t, int); int (*Fsync)(struct VfsInfo *); int (*Fdatasync)(struct VfsInfo *); int (*Flock)(struct VfsInfo *, int); int (*Fcntl)(struct VfsInfo *, int, va_list); int (*Ioctl)(struct VfsInfo *, unsigned long, const void *); int (*Dup)(struct VfsInfo *, struct VfsInfo **); #ifdef HAVE_DUP3 int (*Dup3)(struct VfsInfo *, struct VfsInfo **, int); #endif int (*Poll)(struct VfsInfo **, struct pollfd *, nfds_t, int); int (*Opendir)(struct VfsInfo *, struct VfsInfo **); #ifdef HAVE_SEEKDIR void (*Seekdir)(struct VfsInfo *, long); long (*Telldir)(struct VfsInfo *); #endif struct dirent *(*Readdir)(struct VfsInfo *); void (*Rewinddir)(struct VfsInfo *); int (*Closedir)(struct VfsInfo *); int (*Bind)(struct VfsInfo *, const struct sockaddr *, socklen_t); int (*Connect)(struct VfsInfo *, const struct sockaddr *, socklen_t); int (*Connectunix)(struct VfsInfo *, struct VfsInfo *, const struct sockaddr_un *, socklen_t); int (*Accept)(struct VfsInfo *, struct sockaddr *, socklen_t *, struct VfsInfo **); int (*Listen)(struct VfsInfo *, int); int (*Shutdown)(struct VfsInfo *, int); ssize_t (*Recvmsg)(struct VfsInfo *, struct msghdr *, int); ssize_t (*Sendmsg)(struct VfsInfo *, const struct msghdr *, int); ssize_t (*Recvmsgunix)(struct VfsInfo *, struct VfsInfo *, struct msghdr *, int); ssize_t (*Sendmsgunix)(struct VfsInfo *, struct VfsInfo *, const struct msghdr *, int); int (*Getsockopt)(struct VfsInfo *, int, int, void *, socklen_t *); int (*Setsockopt)(struct VfsInfo *, int, int, const void *, socklen_t); int (*Getsockname)(struct VfsInfo *, struct sockaddr *, socklen_t *); int (*Getpeername)(struct VfsInfo *, struct sockaddr *, socklen_t *); int (*Rename)(struct VfsInfo *, const char *, struct VfsInfo *, const char *); int (*Utime)(struct VfsInfo *, const char *, const struct timespec[2], int); int (*Futime)(struct VfsInfo *, const struct timespec[2]); int (*Symlink)(const char *, struct VfsInfo *, const char *); void *(*Mmap)(struct VfsInfo *, void *, size_t, int, int, off_t); int (*Munmap)(struct VfsInfo *, void *, size_t); int (*Mprotect)(struct VfsInfo *, void *, size_t, int); int (*Msync)(struct VfsInfo *, void *, size_t, int); int (*Pipe)(struct VfsInfo *[2]); #ifdef HAVE_PIPE2 int (*Pipe2)(struct VfsInfo *[2], int); #endif int (*Socket)(int, int, int, struct VfsInfo **); int (*Socketpair)(int, int, int, struct VfsInfo *[2]); int (*Tcgetattr)(struct VfsInfo *, struct termios *); int (*Tcsetattr)(struct VfsInfo *, int, const struct termios *); int (*Tcflush)(struct VfsInfo *, int); int (*Tcdrain)(struct VfsInfo *); int (*Tcsendbreak)(struct VfsInfo *, int); int (*Tcflow)(struct VfsInfo *, int); pid_t (*Tcgetsid)(struct VfsInfo *); pid_t (*Tcgetpgrp)(struct VfsInfo *); int (*Tcsetpgrp)(struct VfsInfo *, pid_t); #ifdef HAVE_SOCKATMARK int (*Sockatmark)(struct VfsInfo *); #endif int (*Fexecve)(struct VfsInfo *, char *const *, char *const *); }; #define VFS_SYSTEM_NAME_MAX 8 struct VfsSystem { struct Dll elem; struct VfsOps ops; char name[VFS_SYSTEM_NAME_MAX]; bool nodev; }; struct VfsMount { u64 baseino; struct VfsInfo *root; struct Dll elem; }; struct VfsDevice { pthread_mutex_t_ lock; struct Dll *mounts; struct VfsOps *ops; struct VfsInfo *root; void *data; struct Dll elem; u64 flags; u32 dev; _Atomic(u32) refcount; }; struct VfsInfo { struct VfsDevice *device; struct VfsInfo *parent; const char *name; size_t namelen; void *data; u64 ino; u32 dev; u32 mode; _Atomic(u32) refcount; }; extern struct Vfs g_vfs; extern struct VfsInfo *g_cwdinfo; extern struct VfsInfo *g_rootinfo; extern struct VfsInfo *g_actualrootinfo; #define VFS_SYSTEM_CONTAINER(e) DLL_CONTAINER(struct VfsSystem, elem, (e)) #define VFS_MOUNT_CONTAINER(e) DLL_CONTAINER(struct VfsMount, elem, (e)) #define VFS_DEVICE_CONTAINER(e) DLL_CONTAINER(struct VfsDevice, elem, (e)) #if !defined(DISABLE_VFS) int VfsChdir(const char *); char *VfsGetcwd(char *, size_t); int VfsChroot(const char *); int VfsMount(const char *, const char *, const char *, u64, const void *); int VfsUnlink(int, const char *, int); int VfsMkdir(int, const char *, mode_t); int VfsMkfifo(int, const char *, mode_t); int VfsOpen(int, const char *, int, int); int VfsChmod(int, const char *, mode_t, int); int VfsAccess(int, const char *, mode_t, int); int VfsSymlink(const char *, int, const char *); int VfsStat(int, const char *, struct stat *, int); int VfsChown(int, const char *, uid_t, gid_t, int); int VfsRename(int, const char *, int, const char *); ssize_t VfsReadlink(int, const char *, char *, size_t); int VfsLink(int, const char *, int, const char *, int); int VfsUtime(int, const char *, const struct timespec[2], int); int VfsFutime(int, const struct timespec[2]); int VfsFchown(int, uid_t, gid_t); int VfsFstat(int, struct stat *); int VfsFtruncate(int, off_t); int VfsClose(int); ssize_t VfsRead(int, void *, size_t); ssize_t VfsWrite(int, const void *, size_t); ssize_t VfsPread(int, void *, size_t, off_t); ssize_t VfsPwrite(int, const void *, size_t, off_t); ssize_t VfsReadv(int, const struct iovec *, int); ssize_t VfsWritev(int, const struct iovec *, int); ssize_t VfsPreadv(int, const struct iovec *, int, off_t); ssize_t VfsPwritev(int, const struct iovec *, int, off_t); off_t VfsSeek(int, off_t, int); int VfsFchmod(int, mode_t); int VfsFchdir(int); int VfsFsync(int); int VfsFdatasync(int); int VfsFlock(int, int); int VfsFcntl(int, int, ...); int VfsIoctl(int, unsigned long, void *); int VfsDup(int); int VfsDup2(int, int); #ifdef HAVE_DUP3 int VfsDup3(int, int, int); #endif int VfsPoll(struct pollfd *, nfds_t, int); int VfsSelect(int, fd_set *, fd_set *, fd_set *, struct timespec *, sigset_t *); DIR *VfsOpendir(int); #ifdef HAVE_SEEKDIR void VfsSeekdir(DIR *, long); long VfsTelldir(DIR *); #endif struct dirent *VfsReaddir(DIR *); void VfsRewinddir(DIR *); int VfsClosedir(DIR *); int VfsBind(int, const struct sockaddr *, socklen_t); int VfsConnect(int, const struct sockaddr *, socklen_t); int VfsAccept(int, struct sockaddr *, socklen_t *); int VfsListen(int, int); int VfsShutdown(int, int); ssize_t VfsRecvmsg(int, struct msghdr *, int); ssize_t VfsSendmsg(int, const struct msghdr *, int); int VfsGetsockopt(int, int, int, void *, socklen_t *); int VfsSetsockopt(int, int, int, const void *, socklen_t); int VfsGetsockname(int, struct sockaddr *, socklen_t *); int VfsGetpeername(int, struct sockaddr *, socklen_t *); int VfsPipe(int[2]); #ifdef HAVE_PIPE2 int VfsPipe2(int[2], int); #endif int VfsSocket(int, int, int); int VfsSocketpair(int, int, int, int[2]); int VfsTcgetattr(int, struct termios *); int VfsTcsetattr(int, int, const struct termios *); pid_t VfsTcgetpgrp(int); int VfsTcsetpgrp(int, pid_t); int VfsTcdrain(int); int VfsTcsendbreak(int, int); int VfsTcflow(int, int); pid_t VfsTcgetsid(int); int VfsTcflush(int, int); int VfsSockatmark(int); int VfsExecve(const char *, char *const *, char *const *); void *VfsMmap(void *, size_t, int, int, int, off_t); int VfsMunmap(void *, size_t); int VfsMprotect(void *, size_t, int); int VfsMsync(void *, size_t, int); int VfsInit(const char *); int VfsRegister(struct VfsSystem *); int VfsTraverse(const char *, struct VfsInfo **, bool); int VfsCreateInfo(struct VfsInfo **); int VfsAcquireInfo(struct VfsInfo *, struct VfsInfo **); int VfsCreateDevice(struct VfsDevice **output); int VfsAcquireDevice(struct VfsDevice *, struct VfsDevice **); int VfsFreeDevice(struct VfsDevice *); int VfsFreeInfo(struct VfsInfo *); int VfsAddFd(struct VfsInfo *); int VfsFreeFd(int, struct VfsInfo **); int VfsSetFd(int, struct VfsInfo *); ssize_t VfsPathBuildFull(struct VfsInfo *, struct VfsInfo *, char **); ssize_t VfsPathBuild(struct VfsInfo *, struct VfsInfo *, bool, char[VFS_PATH_MAX]); #elif !defined(DISABLE_OVERLAYS) #define VfsChown OverlaysChown #define VfsAccess OverlaysAccess #define VfsStat OverlaysStat #define VfsChdir OverlaysChdir #define VfsGetcwd OverlaysGetcwd #define VfsMkdir OverlaysMkdir #define VfsChmod OverlaysChmod #define VfsReadlink OverlaysReadlink #define VfsOpen OverlaysOpen #define VfsSymlink OverlaysSymlink #define VfsMkfifo OverlaysMkfifo #define VfsUnlink OverlaysUnlink #define VfsRename OverlaysRename #define VfsLink OverlaysLink #define VfsUtime OverlaysUtime #define VfsFchown fchown #define VfsFchdir fchdir #define VfsFchmod fchmod #define VfsFutime futimens #define VfsFstat fstat #define VfsFtruncate ftruncate #define VfsClose close #define VfsRead read #define VfsWrite write #define VfsPread pread #define VfsPwrite pwrite #define VfsReadv readv #define VfsWritev writev #define VfsPreadv preadv #define VfsPwritev pwritev #define VfsSeek lseek #define VfsFsync fsync #define VfsFdatasync fdatasync #define VfsFlock flock #define VfsFcntl fcntl #define VfsDup dup #define VfsDup2 dup2 #define VfsDup3 dup3 #define VfsPoll poll #define VfsSelect pselect #define VfsOpendir fdopendir #define VfsSeekdir seekdir #define VfsTelldir telldir #define VfsReaddir readdir #define VfsRewinddir rewinddir #define VfsClosedir closedir #define VfsPipe pipe #define VfsPipe2 pipe2 #define VfsSocket socket #define VfsSocketpair socketpair #define VfsBind bind #define VfsConnect connect #define VfsAccept accept #define VfsListen listen #define VfsShutdown shutdown #define VfsRecvmsg recvmsg #define VfsSendmsg sendmsg #define VfsGetsockopt getsockopt #define VfsSetsockopt setsockopt #define VfsGetsockname getsockname #define VfsGetpeername getpeername #define VfsIoctl ioctl #define VfsTcgetattr tcgetattr #define VfsTcsetattr tcsetattr #define VfsTcgetpgrp tcgetpgrp #define VfsTcsetpgrp tcsetpgrp #define VfsTcgetsid tcgetsid #define VfsTcsendbreak tcsendbreak #define VfsTcflow tcflow #define VfsTcflush tcflush #define VfsTcdrain tcdrain #define VfsSockatmark sockatmark #define VfsExecve execve #define VfsMmap mmap #define VfsMunmap munmap #define VfsMprotect mprotect #define VfsMsync msync #else #define VfsChown fchownat #define VfsAccess faccessat #define VfsStat fstatat #define VfsChdir chdir #define VfsGetcwd getcwd #define VfsMkdir mkdirat #define VfsChmod fchmodat #define VfsReadlink readlinkat #define VfsOpen openat #define VfsSymlink symlinkat #define VfsMkfifo mkfifoat #define VfsUnlink unlinkat #define VfsRename renameat #define VfsLink linkat #define VfsUtime utimensat #define VfsFchown fchown #define VfsFchdir fchdir #define VfsFchmod fchmod #define VfsFutime futimens #define VfsFstat fstat #define VfsFtruncate ftruncate #define VfsClose close #define VfsRead read #define VfsWrite write #define VfsPread pread #define VfsPwrite pwrite #define VfsReadv readv #define VfsWritev writev #define VfsPreadv preadv #define VfsPwritev pwritev #define VfsSeek lseek #define VfsFsync fsync #define VfsFdatasync fdatasync #define VfsFlock flock #define VfsFcntl fcntl #define VfsDup dup #define VfsDup2 dup2 #define VfsDup3 dup3 #define VfsPoll poll #define VfsSelect pselect #define VfsOpendir fdopendir #define VfsSeekdir seekdir #define VfsTelldir telldir #define VfsReaddir readdir #define VfsRewinddir rewinddir #define VfsClosedir closedir #define VfsPipe pipe #define VfsPipe2 pipe2 #define VfsSocket socket #define VfsSocketpair socketpair #define VfsBind bind #define VfsConnect connect #define VfsAccept accept #define VfsListen listen #define VfsShutdown shutdown #define VfsRecvmsg recvmsg #define VfsSendmsg sendmsg #define VfsGetsockopt getsockopt #define VfsSetsockopt setsockopt #define VfsGetsockname getsockname #define VfsGetpeername getpeername #define VfsIoctl ioctl #define VfsTcgetattr tcgetattr #define VfsTcsetattr tcsetattr #define VfsTcgetpgrp tcgetpgrp #define VfsTcsetpgrp tcsetpgrp #define VfsTcgetsid tcgetsid #define VfsTcsendbreak tcsendbreak #define VfsTcflow tcflow #define VfsTcflush tcflush #define VfsTcdrain tcdrain #define VfsSockatmark sockatmark #define VfsExecve execve #define VfsMmap mmap #define VfsMunmap munmap #define VfsMprotect mprotect #define VfsMsync msync #endif #endif /* BLINK_VFS_H_ */ ================================================ FILE: blink/vigna.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/util.h" u64 Vigna(u64 s[1]) { u64 z = (s[0] += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; return z ^ (z >> 31); } ================================================ FILE: blink/watch.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/watch.h" #include #include #include "blink/debug.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/x86.h" void PopWatchpoint(struct Watchpoints *wps) { if (wps->i) { --wps->i; } } ssize_t PushWatchpoint(struct Watchpoints *wps, struct Watchpoint *b) { int i; for (i = 0; i < wps->i; ++i) { if (wps->p[i].disable) { memcpy(&wps->p[i], b, sizeof(*b)); return i; } } if (wps->i++ == wps->n) { wps->n = wps->i + (wps->i >> 1); wps->p = (struct Watchpoint *)realloc(wps->p, wps->n * sizeof(*wps->p)); } wps->p[wps->i - 1] = *b; return wps->i - 1; } ssize_t IsAtWatchpoint(struct Watchpoints *wps, struct Machine *m) { u8 *r; int i; u64 w; i64 oldip; bool hasop; struct XedDecodedInst x; if (!wps->i) return -1; hasop = !GetInstruction(m, GetPc(m), &x) && x.op.has_modrm; for (i = wps->i; i--;) { if (wps->p[i].disable) continue; oldip = m->ip; m->ip += Oplength(x.op.rde); if ((hasop && !IsModrmRegister(x.op.rde) && ComputeAddress(m, x.op.rde, x.op.disp, x.op.uimm0) == wps->p[i].addr) || Get64(m->ax) == wps->p[i].addr || // Get64(m->cx) == wps->p[i].addr || // Get64(m->dx) == wps->p[i].addr || // Get64(m->bx) == wps->p[i].addr || // Get64(m->sp) == wps->p[i].addr || // Get64(m->bp) == wps->p[i].addr || // Get64(m->si) == wps->p[i].addr || // Get64(m->di) == wps->p[i].addr || // Get64(m->r8) == wps->p[i].addr || // Get64(m->r9) == wps->p[i].addr || // Get64(m->r10) == wps->p[i].addr || // Get64(m->r11) == wps->p[i].addr || // Get64(m->r12) == wps->p[i].addr || // Get64(m->r13) == wps->p[i].addr || // Get64(m->r14) == wps->p[i].addr || // Get64(m->r15) == wps->p[i].addr) { // return i; } m->ip = oldip; // TODO(jart): Handle case of overlapping page boundary. // TODO(jart): Possibly track munmap() type cases. if ((r = SpyAddress(m, wps->p[i].addr))) { w = Read64(r); if (!wps->p[i].initialized) { wps->p[i].oldvalue = w; wps->p[i].initialized = true; } else if (w != wps->p[i].oldvalue) { wps->p[i].oldvalue = w; return i; } } } return -1; } ================================================ FILE: blink/watch.h ================================================ #ifndef BLINK_WATCH_H_ #define BLINK_WATCH_H_ #include #include "blink/machine.h" #include "blink/types.h" struct Watchpoint { i64 addr; const char *symbol; u64 oldvalue; bool initialized; bool disable; }; struct Watchpoints { int i, n; struct Watchpoint *p; }; ssize_t IsAtWatchpoint(struct Watchpoints *, struct Machine *); ssize_t PushWatchpoint(struct Watchpoints *, struct Watchpoint *); void PopWatchpoint(struct Watchpoints *); #endif /* BLINK_WATCH_H_ */ ================================================ FILE: blink/wcwidth.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/util.h" int wcwidth_(wchar_t c) { if (!c) return 0; if (c < 0 || iswcntrl(c)) return -1; return 1 + (c >= 0x1100 && (c <= 0x115f || c == 0x2329 || c == 0x232a || (c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) || (c >= 0xac00 && c <= 0xd7a3) || (c >= 0xf900 && c <= 0xfaff) || (c >= 0xfe10 && c <= 0xfe19) || (c >= 0xfe30 && c <= 0xfe6f) || (c >= 0xff00 && c <= 0xff60) || (c >= 0xffe0 && c <= 0xffe6) || (c >= 0x20000 && c <= 0x2fffd) || (c >= 0x30000 && c <= 0x3fffd))); } ================================================ FILE: blink/web.h ================================================ #ifndef BLINK_WEB_H_ #define BLINK_WEB_H_ #include "blink/builtin.h" #ifdef __EMSCRIPTEN__ #include static void SetupWeb(void) { // EM_ASM({FS.mkdir("/cwd"); FS.mount(NODEFS, {root : "."}, "/cwd");}); } #else static void SetupWeb(void) { } #endif /* __EMSCRIPTEN__ */ #endif /* BLINK_WEB_H_ */ ================================================ FILE: blink/x86.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2018 Intel Corporation │ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Licensed under the Apache License, Version 2.0 (the "License"); │ │ you may not use this file except in compliance with the License. │ │ You may obtain a copy of the License at │ │ │ │ http://www.apache.org/licenses/LICENSE-2.0 │ │ │ │ Unless required by applicable law or agreed to in writing, software │ │ distributed under the License is distributed on an "AS IS" BASIS, │ │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ │ See the License for the specific language governing permissions and │ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/x86.h" #include #include #include "blink/assert.h" #include "blink/bitscan.h" #include "blink/builtin.h" #include "blink/endian.h" #include "blink/macros.h" #include "blink/modrm.h" #include "blink/rde.h" #include "blink/types.h" const char kXedCopyright[] = "\ Xed (Apache 2.0)\n\ Copyright 2018 Intel Corporation\n\ Copyright 2022 Justine Alexandra Roberts Tunney\n\ Modifications: Removed as much code and functionality as possible"; #define XED_ILD_HASMODRM_IGNORE_MOD 2 static const u32 xed_prefix_table_bit[8] = { 0x00000000, 0x40404040, 0x0000ffff, 0x000000f0, 0x00000000, 0x00000000, 0x00000000, 0x000d0000, }; static const struct XedDenseMagnums { u8 eamode[2][3]; u8 has_sib_table[3][4][8]; u8 has_disp_regular[3][4][8]; u8 imm_bits_2d[2][256]; u8 has_modrm_2d[XED_ILD_MAP2][256]; u8 disp_bits_2d[XED_ILD_MAP2][256]; u8 BRDISPz_BRDISP_WIDTH[4]; u8 MEMDISPv_DISP_WIDTH[4]; u8 SIMMz_IMM_WIDTH[4]; u8 UIMMv_IMM_WIDTH[4]; u8 ASZ_NONTERM_EASZ[2][3]; u8 OSZ_NONTERM_DF64_EOSZ[2][2][3]; u8 OSZ_NONTERM_EOSZ[2][2][3]; } kXed = { .eamode = {{XED_MODE_REAL, XED_MODE_LEGACY, XED_MODE_LONG}, {XED_MODE_LEGACY, XED_MODE_REAL, XED_MODE_LEGACY}}, .has_sib_table = {{{0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}}, .has_disp_regular = {{{0, 0, 0, 0, 0, 0, 2, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {2, 2, 2, 2, 2, 2, 2, 2}, {0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 0, 0, 0, 0, 4, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {4, 4, 4, 4, 4, 4, 4, 4}, {0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 0, 0, 0, 0, 4, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {4, 4, 4, 4, 4, 4, 4, 4}, {0, 0, 0, 0, 0, 0, 0, 0}}}, .imm_bits_2d = {{1, 1, 1, 1, 5, 7, 1, 1, 1, 1, 1, 1, 9, 7, 1, 0, 1, 1, 1, 1, 5, 7, 1, 1, 1, 1, 1, 1, 5, 7, 1, 1, 1, 1, 1, 1, 5, 7, 0, 1, 1, 1, 1, 1, 5, 7, 0, 1, 1, 1, 1, 1, 9, 7, 0, 1, 1, 1, 1, 1, 5, 7, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 6, 7, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 7, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 7, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 8, 1, 1, 1, 9, 2, 11, 1, 8, 1, 1, 9, 1, 1, 1, 1, 1, 1, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 1, 1, 8, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 1, 1, 1, 1, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 0, 0, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 9, 1, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, .has_modrm_2d = {{1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 3, 0, 1, 1, 1, 1, 0, 0, 3, 0, 1, 1, 1, 1, 0, 0, 3, 0, 1, 1, 1, 1, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 3, 3, 3, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1}, {1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 3, 0, 3, 1, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 3, 3, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, .disp_bits_2d = {{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 4, 4, 4, 4, 3, 3, 2, 1, 4, 4, 4, 4, 0, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, {4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 0, 4, 0, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}}, .BRDISPz_BRDISP_WIDTH = {0, 16, 32, 32}, .MEMDISPv_DISP_WIDTH = {0, 16, 32, 64}, .SIMMz_IMM_WIDTH = {0x00, 0x10, 0x20, 0x20}, .UIMMv_IMM_WIDTH = {0x00, 0x10, 0x20, 0x40}, .ASZ_NONTERM_EASZ = {{1, 2, 3}, {2, 1, 2}}, .OSZ_NONTERM_DF64_EOSZ = {{{1, 2, 3}, {2, 1, 1}}, {{1, 2, 3}, {2, 1, 3}}}, .OSZ_NONTERM_EOSZ = {{{1, 2, 2}, {2, 1, 1}}, {{1, 2, 3}, {2, 1, 3}}}, }; static size_t xed_bits2bytes(unsigned bits) { return bits >> 3; } static size_t xed_bytes2bits(unsigned bytes) { return bytes << 3; } static u8 xed_get_prefix_table_bit(u8 a) { return (xed_prefix_table_bit[a >> 5] >> (a & 0x1F)) & 1; } static void xed_set_mopcode(struct XedDecodedInst *x, u64 mopcode) { x->op.rde |= mopcode << 40; } static int xed_too_short(struct XedDecodedInst *x) { if (x->op.max_bytes >= 15) { return XED_ERROR_INSTR_TOO_LONG; } else { return XED_ERROR_BUFFER_TOO_SHORT; } } static void xed_set_simmz_imm_width_eosz(struct XedDecodedInst *x, const u8 eosz[2][2][3], int *imm_width, u8 *imm_signed) { *imm_width = kXed.SIMMz_IMM_WIDTH[eosz[Rexw(x->op.rde)][Osz(x->op.rde)] [Mode(x->op.rde)]]; *imm_signed = 1; } static int xed_set_imm_bytes(struct XedDecodedInst *x, int *imm_width, u8 *imm_signed) { if (!*imm_width && Opmap(x->op.rde) < XED_ILD_MAP2) { switch (kXed.imm_bits_2d[Opmap(x->op.rde)][Opcode(x->op.rde)]) { case 0: return XED_ERROR_GENERAL_ERROR; case 1: *imm_width = 0; return XED_ERROR_NONE; case 2: switch (ModrmReg(x->op.rde)) { case 0: xed_set_simmz_imm_width_eosz(x, kXed.OSZ_NONTERM_EOSZ, imm_width, imm_signed); return XED_ERROR_NONE; case 7: *imm_width = 0; return XED_ERROR_NONE; default: return XED_ERROR_NONE; } case 3: if (ModrmReg(x->op.rde) <= 1) { *imm_width = 8; *imm_signed = 1; } else if (2 <= ModrmReg(x->op.rde) && ModrmReg(x->op.rde) <= 7) { *imm_width = 0; } return XED_ERROR_NONE; case 4: if (ModrmReg(x->op.rde) <= 1) { xed_set_simmz_imm_width_eosz(x, kXed.OSZ_NONTERM_EOSZ, imm_width, imm_signed); } else if (2 <= ModrmReg(x->op.rde) && ModrmReg(x->op.rde) <= 7) { *imm_width = 0; } return XED_ERROR_NONE; case 5: *imm_width = 8; *imm_signed = 1; return XED_ERROR_NONE; case 6: xed_set_simmz_imm_width_eosz(x, kXed.OSZ_NONTERM_DF64_EOSZ, imm_width, imm_signed); return XED_ERROR_NONE; case 7: xed_set_simmz_imm_width_eosz(x, kXed.OSZ_NONTERM_EOSZ, imm_width, imm_signed); return XED_ERROR_NONE; case 8: *imm_width = 16; return XED_ERROR_NONE; case 9: *imm_width = 8; return XED_ERROR_NONE; case 10: *imm_width = kXed.UIMMv_IMM_WIDTH[kXed.OSZ_NONTERM_EOSZ[Rexw( x->op.rde)][Osz(x->op.rde)][Mode(x->op.rde)]]; return XED_ERROR_NONE; case 11: // actually 2 bytes for uimm0 & 1 byte for uimm1 *imm_width = xed_bytes2bits(3); return XED_ERROR_NONE; case 12: if (Osz(x->op.rde) || Rep(x->op.rde) == 2) { *imm_width = xed_bytes2bits(1); } return XED_ERROR_NONE; default: __builtin_unreachable(); } } else { return XED_ERROR_NONE; } } static bool xed_is_bound_instruction(struct XedDecodedInst *x) { return Mode(x->op.rde) != XED_MODE_LONG && // x->length + 1 < x->op.max_bytes && // (x->bytes[x->length + 1] & 0xC0) != 0xC0; } static int xed_prefix_scanner(struct XedDecodedInst *x) { u32 rde; u8 b, rep, max_bytes, length, islong; u8 asz, osz, rex, rexw, rexr, rexx, rexb; rex = 0; rep = 0; length = 0; rde = x->op.rde; max_bytes = x->op.max_bytes; islong = Mode(rde) == XED_MODE_LONG; while (length < max_bytes) { b = x->bytes[length]; if (xed_get_prefix_table_bit(b) == 0) goto out; switch (b) { case 0x66: // osz rex = 0; osz = 1; rde |= osz << 5; break; case 0x67: // asz rex = 0; asz = 1; rde |= asz << 21; break; case 0x2E: // cs if (1 || !islong) { rde &= 037770777777; rde |= 000002000000; } rex = 0; break; case 0x3E: // ds if (1 || !islong) { rde &= 037770777777; rde |= 000004000000; } rex = 0; break; case 0x26: // es if (1 || !islong) { rde &= 037770777777; rde |= 000001000000; } rex = 0; break; case 0x36: // ss if (1 || !islong) { rde &= 037770777777; rde |= 000003000000; } rex = 0; break; case 0x64: // fs rde &= 037770777777; rde |= 000005000000; rex = 0; break; case 0x65: // gs rde &= 037770777777; rde |= 000006000000; rex = 0; break; case 0xF0: // lock rde |= 020000000000; rex = 0; break; case 0xF2: // rep case 0xF3: rep = b & 3; rex = 0; break; default: if (islong && (b & 0xf0) == 0x40) { rex = b; break; } else { goto out; } } length++; } out: x->length = length; if (rex) { rexw = (rex >> 3) & 1; rexr = (rex >> 2) & 1; rexx = (rex >> 1) & 1; rexb = rex & 1; rex = 1; rde |= rexx << 17 | rex << 16 | rexb << 15 | rex << 11 | rexb << 10 | rexw << 6 | rex << 4 | rexr << 3; } x->op.rde = (u64)rep << 51 | rde; if (length < max_bytes) { return XED_ERROR_NONE; } else { return xed_too_short(x); } } static void xed_set_vex_prefix(struct XedDecodedInst *x, unsigned prefix) { switch (prefix) { case 0: break; case 1: // osz x->op.rde &= ~(1 << 5); x->op.rde |= 1 << 5; break; case 2: // rep3 case 3: // rep2 x->op.rde &= ~((u64)3 << 51); x->op.rde |= (u64)(prefix ^ 1) << 51; break; default: __builtin_unreachable(); } } static int xed_vex_opcode_scanner(struct XedDecodedInst *x, int map) { xed_set_mopcode(x, map << 8 | x->bytes[x->length]); x->op.pos_opcode = x->length++; #ifndef TINY if (Mode(x->op.rde) == XED_MODE_LONG && Rex(x->op.rde)) { return XED_ERROR_BAD_REX_PREFIX; } if (Mode(x->op.rde) == XED_MODE_REAL) { return XED_ERROR_INVALID_MODE; } #endif return 0; } static int xed_vex_c4_scanner(struct XedDecodedInst *x, int *imm_width, int *vexvalid) { unsigned length, b1, b2; int map, rexr, rexx, rexb, rexw, ymm, vrex, vexdest210; if (xed_is_bound_instruction(x)) return 0; length = x->length; length++; if (length + 2 < x->op.max_bytes) { // map: 5-bit // rex.b: 1-bit (expands r/m or srm register operand) // rex.x: 1-bit (expands sib register operands) // rex.r: 1-bit (expands reg register operand) b1 = x->bytes[length]; rexr = !(b1 & 128); rexx = !(b1 & 64); rexb = (Mode(x->op.rde) == XED_MODE_LONG) & !(b1 & 32); // prefix: 2-bit → {none, osz, rep3, rep2} // vector_length: 1-bit → {xmm, ymm} aka VEX.L // vexdest210: 3-bit (second reg operand, inverted) // vrex: 1-bit a.k.a. vexdest3 // rex.w: 1-bit (for 64-bit registers) aka VEX.W1 b2 = x->bytes[length + 1]; rexw = !!(b2 & 128); vrex = !(b2 & 64); vexdest210 = (~b2 >> 3) & 7; ymm = !!(b2 & 4); xed_set_vex_prefix(x, b2 & 3); map = b1 & 31; if ((b1 & 3) == XED_ILD_MAP3) { *imm_width = xed_bytes2bits(1); } x->op.rde |= (u64)vrex << 63 | rexx << 17 | rexb << 15 | rexb << 10 | rexw << 6 | rexr << 3; x->op.rde |= ymm << 30; x->op.rde |= (u64)vexdest210 << 60; *vexvalid = 1; length += 2; x->length = length; return xed_vex_opcode_scanner(x, map); } else { x->length = length; return xed_too_short(x); } } static int xed_vex_c5_scanner(struct XedDecodedInst *x, int *vexvalid) { unsigned length, b; int rexr, ymm, vrex, vexdest210; length = x->length; if (xed_is_bound_instruction(x)) return 0; length++; if (length + 1 < x->op.max_bytes) { // prefix: 2-bit → {none, osz, rep3, rep2} // vector_length: 1-bit → {xmm, ymm} // vexdest210: 3-bit // vrex: 1-bit // rex.r: 1-bit b = x->bytes[length]; rexr = !(b & 128); vrex = !!(b & 64); vexdest210 = (~b >> 3) & 7; ymm = (b >> 2) & 1; xed_set_vex_prefix(x, b & 3); x->op.rde |= (u64)vrex << 63 | rexr << 3; x->op.rde |= ymm << 30; x->op.rde |= (u64)vexdest210 << 60; *vexvalid = 1; length++; x->length = length; return xed_vex_opcode_scanner(x, XED_ILD_MAP1); } else { x->length = length; return xed_too_short(x); } } static int xed_vex_scanner(struct XedDecodedInst *x, int *imm_width, int *vexvalid) { if (Mode(x->op.rde) != XED_MODE_LONG) return 0; switch (x->bytes[x->length]) { case 0xC5: return xed_vex_c5_scanner(x, vexvalid); case 0xC4: return xed_vex_c4_scanner(x, imm_width, vexvalid); default: return 0; } } static int xed_get_next_as_opcode(struct XedDecodedInst *x, int map) { u8 length; length = x->length; if (length < x->op.max_bytes) { xed_set_mopcode(x, map << 8 | x->bytes[length]); x->length++; return XED_ERROR_NONE; } else { return xed_too_short(x); } } static int xed_opcode_scanner(struct XedDecodedInst *x, int *imm_width) { u8 b, length; length = x->length; if ((b = x->bytes[length]) != 0x0F) { xed_set_mopcode(x, XED_ILD_MAP0 << 8 | b); x->op.pos_opcode = length; x->length++; return XED_ERROR_NONE; } else { length++; x->op.pos_opcode = length; if (length < x->op.max_bytes) { switch ((b = x->bytes[length])) { case 0x38: x->length = ++length; return xed_get_next_as_opcode(x, XED_ILD_MAP2); case 0x3A: x->length = ++length; *imm_width = xed_bytes2bits(1); return xed_get_next_as_opcode(x, XED_ILD_MAP3); case 0x3B: case 0x39: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x0F: length++; x->length = length; xed_get_next_as_opcode(x, XED_ILD_BAD_MAP); return XED_ERROR_BAD_MAP; default: xed_set_mopcode(x, XED_ILD_MAP1 << 8 | b); x->length = ++length; return XED_ERROR_NONE; } } else { return xed_too_short(x); } } } static u64 xed_read_number(u8 *p, size_t n, unsigned s) { switch (s << 2 | bsr(n)) { case 0: return Read8(p); case 1: return Read16(p); case 2: return Read32(p); case 3: return Read64(p); case 4: return (i8)Read8(p); case 5: return (i16)Read16(p); case 6: return (i32)Read32(p); case 7: return (i64)Read64(p); default: __builtin_unreachable(); } } static void xed_set_has_modrm(struct XedDecodedInst *x) { if (Opmap(x->op.rde) < ARRAYLEN(kXed.has_modrm_2d)) { x->op.has_modrm = kXed.has_modrm_2d[Opmap(x->op.rde)][Opcode(x->op.rde)]; } else { x->op.has_modrm = 1; } } static int xed_modrm_scanner(struct XedDecodedInst *x, int *disp_width, int *has_sib) { u8 b, rm, reg, mod, eamode, length, has_modrm; xed_set_has_modrm(x); has_modrm = x->op.has_modrm; if (has_modrm) { length = x->length; if (length < x->op.max_bytes) { b = x->bytes[length]; x->length++; rm = b & 0007; reg = (b & 0070) >> 3; mod = (b & 0300) >> 6; x->op.rde &= ~1; x->op.rde |= mod << 22 | rm << 7 | reg; if (has_modrm != XED_ILD_HASMODRM_IGNORE_MOD) { eamode = kXed.eamode[Asz(x->op.rde)][Mode(x->op.rde)]; *disp_width = xed_bytes2bits(kXed.has_disp_regular[eamode][mod][rm]); *has_sib = kXed.has_sib_table[eamode][mod][rm]; } return XED_ERROR_NONE; } else { return xed_too_short(x); } } else { return XED_ERROR_NONE; } } static int xed_sib_scanner(struct XedDecodedInst *x, int *disp_width) { u8 b, length; length = x->length; if (length < x->op.max_bytes) { b = x->bytes[length]; x->op.rde |= (u64)b << 32; // set sib byte x->length++; if ((b & 7) == 5) { if (!ModrmMod(x->op.rde)) { *disp_width = xed_bytes2bits(4); } } return XED_ERROR_NONE; } else { return xed_too_short(x); } } static u8 XED_LF_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2( struct XedDecodedInst *x) { return kXed.BRDISPz_BRDISP_WIDTH[kXed.OSZ_NONTERM_EOSZ[Rexw(x->op.rde)][Osz( x->op.rde)][Mode(x->op.rde)]]; } static int xed_disp_scanner(struct XedDecodedInst *x, int disp_width) { u8 disp_unsigned = 0; u8 length, disp_bytes; length = x->length; if (Opmap(x->op.rde) < XED_ILD_MAP2) { switch (kXed.disp_bits_2d[Opmap(x->op.rde)][Opcode(x->op.rde)]) { case 0: return XED_ERROR_GENERAL_ERROR; case 1: disp_width = 8; break; case 2: disp_width = XED_LF_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2(x); disp_unsigned = 1; break; case 3: if (Mode(x->op.rde) <= XED_MODE_LEGACY) { disp_width = XED_LF_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2(x); } else if (Mode(x->op.rde) == XED_MODE_LONG) { disp_width = 0x20; } break; case 4: break; case 5: disp_width = kXed.MEMDISPv_DISP_WIDTH[kXed.ASZ_NONTERM_EASZ[Asz(x->op.rde)] [Mode(x->op.rde)]]; disp_unsigned = 1; break; case 6: switch (ModrmReg(x->op.rde)) { case 0: break; case 7: disp_width = XED_LF_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2(x); disp_unsigned = 1; break; default: break; } break; default: __builtin_unreachable(); } } disp_bytes = xed_bits2bytes(disp_width); if (!disp_bytes) { return XED_ERROR_NONE; } else if (length + disp_bytes <= x->op.max_bytes) { x->op.disp = xed_read_number(x->bytes + length, disp_bytes, !disp_unsigned); x->length = length + disp_bytes; return XED_ERROR_NONE; } else { return xed_too_short(x); } } static int xed_imm_scanner(struct XedDecodedInst *x, int imm_width) { u8 *p; int e; u8 imm_signed = 0; u8 i, length, imm_bytes; p = x->bytes; if ((e = xed_set_imm_bytes(x, &imm_width, &imm_signed))) return e; i = length = x->length; imm_bytes = xed_bits2bytes(imm_width); if (!imm_bytes) { return XED_ERROR_NONE; } else if (length + imm_bytes <= x->op.max_bytes) { length += imm_bytes; x->length = length; x->op.uimm0 = xed_read_number(p + i, imm_bytes, imm_signed); return XED_ERROR_NONE; } else { return xed_too_short(x); } } static int xed_decode_instruction_length(struct XedDecodedInst *x) { int e; int has_sib = 0; int vexvalid = 0; int imm_width = 0; int disp_width = 0; if ((e = xed_prefix_scanner(x))) return e; #ifndef DISABLE_BMI2 if ((e = xed_vex_scanner(x, &imm_width, &vexvalid))) return e; #endif if (!vexvalid && (e = xed_opcode_scanner(x, &imm_width))) return e; if ((e = xed_modrm_scanner(x, &disp_width, &has_sib))) return e; if (has_sib && (e = xed_sib_scanner(x, &disp_width))) return e; if ((e = xed_disp_scanner(x, disp_width))) return e; return xed_imm_scanner(x, imm_width); } /** * Decodes machine instruction. * * This function also decodes other useful attributes, such as the * offsets of displacement, immediates, etc. It works for all ISAs from * 1977 to 2020. * * @note binary footprint increases ~4kb if this is used * @see biggest code in gdb/clang/tensorflow binaries */ int DecodeInstruction(struct XedDecodedInst *x, const void *itext, size_t bytes, u64 mode) { int rc; u64 rde; u8 kLog2[2][2][2] = {{{2, 3}, {1, 3}}}; unassert(mode == XED_MODE_LONG || // mode == XED_MODE_LEGACY || // mode == XED_MODE_REAL); x->op.rde = mode << 26; x->op.disp = 0; x->op.uimm0 = 0; x->op.has_modrm = 0; x->op.pos_opcode = 0; if (bytes >= 15) { x->op.max_bytes = 15; memcpy(x->bytes, itext, 15); } else { x->op.max_bytes = bytes; memcpy(x->bytes, itext, bytes); } rc = xed_decode_instruction_length(x); rde = x->op.rde; rde |= (Opcode(rde) & 7) << 12; // srm if (Mode(rde) == XED_MODE_REAL) { // in 16-bit mode, flip osz, except for SIMD instructions & cmpxchg8b; // for SIMD instructions, 0x66 always refers to instructions with larger // operands, & lack of 0x66 to instructions with smaller operands u16 mop = Mopcode(rde); if ((mop >= 0x150 && mop <= 0x176) || (mop >= 0x17C && mop <= 0x17F) || mop == 0x1C2 || (mop >= 0x1C4 && mop <= 0x1C7) || (mop >= 0x1D0 && mop <= 0x1FE)) { (void)rde; } else { rde ^= 1 << 5; } } rde |= (u32)kLog2[IsByteOp(rde)][Osz(rde)][Rexw(rde)] << 28; rde |= (u64)kLog2[0][Osz(rde)][Rexw(rde)] << 57; // wordlog2 rde |= (u32)kXed.eamode[Asz(rde)][Mode(rde)] << 24; rde |= (u64)x->length << 53; x->op.rde = rde; return rc; } ================================================ FILE: blink/x86.h ================================================ #ifndef BLINK_X86_H_ #define BLINK_X86_H_ #include #include /* ▓▓▓▓▓▓▓▓▓▓▓▓▓ ▄▄▄▄ ▓▓▓▓▓▓▓▓▓▓▓▓▓ ▄▓▓▓▓▓▓▄ ▄▓▓▓▓▓▓▓▓ ▄▓▓▓▀ ▓▓▓▓ ▓▓▓▓▓ ▓ ▓▓▓▓ ▓▓ ▓▓▓ ▄▓▓▓▓ ▬▬▬▬▬▬▬▬▬▬▬▬▬▓▓▓▓▓▓▓▓▓▓▓▓▓▬▬▬▬▬▬▬▬▬▬▬▓▓▓▬▬▬▓▓▓▬▬▬▬▬▬▬▬▓▓▬▬▬▬▓▓▓▓▓▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ │ ▓▓▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓▓▄ ▓▓▓ ▓▓▓▓ │ ▬▬▬▬▬▬▬▬▬▬▬▬▬▓▓▓▓ ▓▓▓▓▓▬▬▬▬▬▬▬▬▓▓▓▓▓▓▓▬▬▬▀▓▓▓▓▄▄▄▓▓▓▬▬▓▓▓▓▓▓▓▓▓▓▓▓▓▬▬▬▬▬▬▬▬▬▬ │ ▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▄ ▄▄▓▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▄ │ ▬▬▬▬▬▬▬▬▬▬▬▬▬▓▓▓▓ ▓▓▓▓▓▬▬▬▬▬▬▬▬▬▬▬▓▓▓▓▓▄▄▓▓▀ ▀▀▓▓▓▓▓▓▓▓▓▓▬▬▬▬▬▬▬▬▓▓▓▬▬▬▬▬▬▬▬ ▬▬▬▬▬▬▬▬║▬▬▬▬▓▓▓▓ ▓▓▓▓▓▬▬▬▬▬▬▬▬▬▬▬▬▓▓▓▓▓▓▓▬▬▬▬▬▬▬▬▬▓▓▓ ▓▓▓▬▬▬▬▬▬▬▬▓▓▓▬▬▬▬║▬▬▬ ▬▬▬▬▬▬▬▬▬▬▬▬▬▓▓▓▓ ▓▓▓▓▓▬▬▬▬▬▬▬▬▬▬▬▓▓▓▓▬▬▓▓▓▬▬▬▬▬▬▬▬▓▓▓▬▓▓▓▓▬▬▬▬▬▬▬▓▓▓▬▬▬▬▬▬▬▬ ■■■■■■■■║■■■■▓▓▓▓ ▓▓▓▓▓■■■▓▓▓▄▄▄▓▓▓▓■■■■▬▓▓▓▓▄▄▄▄▓▓▓■■■■▬▓▓▓▓▄▄▄▓▓▓▓▀■■■■║■■■ ■■■■■■■■■■■■■▓▓▓▓▓▓▓▓▓▓▓▓▓■■■■■▀▓▓▓■■■■■■■■■■■■■■▀▀■■■■■■■■■■■■▀▓▓▀■■■■■■■■■■■■■ ║▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓║ */ #define XED_MODE_REAL 0 #define XED_MODE_LEGACY 1 #define XED_MODE_LONG 2 #define XED_ILD_MAP0 0 // 8086+ ... #define XED_ILD_MAP1 1 // 286+ 0x0F,... #define XED_ILD_MAP2 2 // Core2+ 0x0F,0x38,... #define XED_ILD_MAP3 3 // Core2+ 0x0F,0x3A,... #define XED_ILD_MAP4 4 #define XED_ILD_MAP5 5 #define XED_ILD_MAP6 6 #define XED_ILD_BAD_MAP 7 #define XED_GEN_MODE_REAL 0 #define XED_GEN_MODE_PROTECTED 1 #define XED_GEN_MODE_V86 2 // unimplemented struct XedMachineMode { uint8_t omode : 2, // bitness of operands, for instruction decoding // - 16-bit if XED_MODE_REAL // - 32-bit if XED_MODE_LEGACY // - 64-bit if XED_MODE_LONG genmode : 6; // general machine mode // - real address mode if XED_GEN_MODE_REAL // - protected/long mode, with GDT & all that, if // XED_GEN_MODE_PROTECTED }; #define XED_MACHINE_MODE_REAL \ ((struct XedMachineMode){XED_MODE_REAL, XED_GEN_MODE_REAL}) #define XED_MACHINE_MODE_LEGACY_16 \ ((struct XedMachineMode){XED_MODE_REAL, XED_GEN_MODE_PROTECTED}) #define XED_MACHINE_MODE_LEGACY_32 \ ((struct XedMachineMode){XED_MODE_LEGACY, XED_GEN_MODE_PROTECTED}) #define XED_MACHINE_MODE_LONG \ ((struct XedMachineMode){XED_MODE_LONG, XED_GEN_MODE_PROTECTED}) #define XED_MAX_INSTRUCTION_BYTES 15 #define XED_ERROR_NONE 0 #define XED_ERROR_BUFFER_TOO_SHORT 1 #define XED_ERROR_GENERAL_ERROR 2 #define XED_ERROR_BAD_LEGACY_PREFIX 7 #define XED_ERROR_BAD_REX_PREFIX 8 #define XED_ERROR_BAD_MAP 10 #define XED_ERROR_INSTR_TOO_LONG 18 #define XED_ERROR_INVALID_MODE 19 #define XED_ERROR_LAST 22 struct XedOperands { /* ┌vreg │ ┌log₂𝑏 (-/16/32/64) │ │ ┌length │ │ │ ┌rep │ │ │ │ ┌map │ │ │ │ │ ┌opcode │ │ │ │ │ │ ┌sib scale │ │ │ │ │ │ │ ┌sib index │ │ │ │ │ │ │ │ ┌sib base │ │ │ │ │ │ │ │ │ ┌lock │ │ │ │ │ │ │ │ │ │┌ymm │ │ │ │ │ │ │ │ │ ││┌log₂𝑏 (8/16/32/64) │ │ │ │ │ │ │ │ │ │││ ┌mode │ │ │ │ │ │ │ │ │ │││ │ ┌eamode │ │ │ │ │ │ │ │ │ │││ │ │ ┌mod │ │ │ │ │ │ │ │ │ │││ │ │ │ ┌asz │ │ │ │ │ │ │ │ │ │││ │ │ │ │┌sego │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ┌rexx │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ │┌rex REGISTER │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││┌rexb DISPATCH │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ │││┌srm ENCODING │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ ┌rex │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ │┌rexb │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ ││┌rm │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ │││ ┌rexw │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ │││ │┌osz │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ │││ ││┌rex │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ │││ │││┌rexr │ │ │ │ │ │ │ │ │ │││ │ │ │ ││ ││││ │││ ││││┌reg │6 │5│5 │5│4 │4 │3│3 │3 │││2│2│2│2││ ││││ │││ │││││ │0 │7│3 │1│8 │0 │8│5 │2 │││8│6│4│2││18││││12│││ 7│││││ 0 ├──┐ ├┐├──┐├┐├─┐├──────┐├┐├─┐├─┐││├┐├┐├┐├┐│├─┐│││├─┐││├─┐││││├─┐ 0b0000000000000000000000000000000000000000000000000000000000000000*/ uint64_t rde; uint64_t uimm0; // $immediate mostly sign-extended int64_t disp; // displacement(%xxx) mostly sign-extended uint8_t has_modrm; uint8_t pos_opcode; uint8_t max_bytes; }; struct XedDecodedInst { unsigned char length; uint8_t bytes[15]; struct XedOperands op; }; extern const char kXedCopyright[]; extern const char kXedErrorNames[]; int DecodeInstruction(struct XedDecodedInst *, const void *, size_t, uint64_t); #endif /* BLINK_X86_H_ */ ================================================ FILE: blink/x86error.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/x86.h" const char kXedErrorNames[] = "\ none\0\ buffer too short\0\ general error\0\ invalid for chip\0\ bad register\0\ bad lock prefix\0\ bad rep prefix\0\ bad legacy prefix\0\ bad rex prefix\0\ bad evex ubit\0\ bad map\0\ bad evex v prime\0\ bad evex z no masking\0\ no output pointer\0\ no agen call back registered\0\ bad memop index\0\ callback problem\0\ gather regs\0\ instr too long\0\ invalid mode\0\ bad evex ll\0\ unimplemented\0\ "; ================================================ FILE: blink/xadd.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/alu.h" #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/log.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/swap.h" #include "blink/thread.h" void OpXaddEbGb(P) { u8 x, y, z, *p, *q; p = GetModrmRegisterBytePointerWrite1(A); q = ByteRexrReg(m, rde); if (Lock(rde)) { x = atomic_load_explicit((_Atomic(u8) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u8) *)q, memory_order_relaxed); y = Little8(y); do { atomic_store_explicit((_Atomic(u8) *)q, x, memory_order_relaxed); z = Little8(Add8(m, Little8(x), y)); } while (!atomic_compare_exchange_weak_explicit( (_Atomic(u8) *)p, &x, z, memory_order_release, memory_order_acquire)); } else { x = Load8(p); y = Get8(q); z = Add8(m, x, y); Put8(q, x); Store8(p, z); } } void OpXaddEvqpGvqp(P) { u8 *p, *q; q = RegRexrReg(m, rde); p = GetModrmRegisterWordPointerWriteOszRexw(A); if (Rexw(rde)) { u64 x, y, z; #if CAN_64BIT if (Lock(rde) && !((uintptr_t)p & 7)) { x = atomic_load_explicit((_Atomic(u64) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u64) *)q, memory_order_relaxed); y = Little64(y); do { atomic_store_explicit((_Atomic(u64) *)q, x, memory_order_relaxed); z = Little64(Add64(m, Little64(x), y)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u64) *)p, &x, z, memory_order_release, memory_order_acquire)); return; } #endif if (Lock(rde)) { LockBus(p); x = Load64Unlocked(p); y = Get64(q); z = Add64(m, x, y); Put64(q, x); Store64Unlocked(p, z); UnlockBus(p); } else { x = Load64(p); y = Get64(q); z = Add64(m, x, y); Put64(q, x); Store64(p, z); } } else if (!Osz(rde)) { u32 x, y, z; if (Lock(rde) && !((uintptr_t)p & 3)) { x = atomic_load_explicit((_Atomic(u32) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u32) *)q, memory_order_relaxed); y = Little32(y); do { atomic_store_explicit((_Atomic(u32) *)q, x, memory_order_relaxed); z = Little32(Add32(m, Little32(x), y)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u32) *)p, &x, z, memory_order_release, memory_order_acquire)); } else { if (Lock(rde)) LockBus(p); x = Load32(p); y = Get32(q); z = Add32(m, x, y); Put32(q, x); Store32(p, z); if (Lock(rde)) UnlockBus(p); } Put32(q + 4, 0); if (IsModrmRegister(rde)) { Put32(p + 4, 0); } } else { u16 x, y, z; if (Lock(rde) && !((uintptr_t)p & 1)) { x = atomic_load_explicit((_Atomic(u16) *)p, memory_order_acquire); y = atomic_load_explicit((_Atomic(u16) *)q, memory_order_relaxed); y = Little16(y); do { atomic_store_explicit((_Atomic(u16) *)q, x, memory_order_relaxed); z = Little16(Add16(m, Little16(x), y)); } while (!atomic_compare_exchange_weak_explicit((_Atomic(u16) *)p, &x, z, memory_order_release, memory_order_acquire)); } else { if (Lock(rde)) LockBus(p); x = Load16(p); y = Get16(q); z = Add16(m, x, y); Put16(q, x); Store16(p, z); if (Lock(rde)) UnlockBus(p); } } } ================================================ FILE: blink/xchg.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include "blink/assert.h" #include "blink/atomic.h" #include "blink/builtin.h" #include "blink/bus.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/modrm.h" #include "blink/thread.h" void OpXchgGbEb(P) { u8 *p, *q, x, y; q = ByteRexrReg(m, rde); /* When a memory operand is used with the XCHG instruction, the processor's LOCK signal is automatically asserted. ──Intel V.1 §7.3.1.2 */ if (!IsModrmRegister(rde)) { p = ComputeReserveAddressWrite1(A); *q = atomic_exchange_explicit((_Atomic(u8) *)p, *q, memory_order_acq_rel); } else { p = ByteRexbRm(m, rde); x = Get8(q); y = Get8(p); Put8(q, y); Put8(p, x); } } void OpXchgGvqpEvqp(P) { u8 *q = RegRexrReg(m, rde); u8 *p = GetModrmRegisterWordPointerWriteOszRexw(A); if (Rexw(rde)) { #if CAN_64BIT if (!IsModrmRegister(rde) && !((uintptr_t)p & 7)) { atomic_store_explicit( (_Atomic(u64) *)q, atomic_exchange_explicit( (_Atomic(u64) *)p, atomic_load_explicit((_Atomic(u64) *)q, memory_order_relaxed), memory_order_acq_rel), memory_order_relaxed); return; } #endif u64 x, y; if (IsModrmRegister(rde)) { x = Get64(q); y = Get64(p); Put64(q, y); Put64(p, x); } else { LockBus(p); y = Load64Unlocked(p); x = Get64(q); Put64(q, y); Store64Unlocked(p, x); UnlockBus(p); } } else if (!Osz(rde)) { if (!IsModrmRegister(rde) && !((uintptr_t)p & 3)) { atomic_store_explicit( (_Atomic(u32) *)q, atomic_exchange_explicit( (_Atomic(u32) *)p, atomic_load_explicit((_Atomic(u32) *)q, memory_order_relaxed), memory_order_acq_rel), memory_order_relaxed); } else { u32 x, y; if (!IsModrmRegister(rde)) LockBus(p); y = Load32(p); x = Read32(q); Write32(q, y); Store32(p, x); if (!IsModrmRegister(rde)) UnlockBus(p); } Write32(q + 4, 0); if (IsModrmRegister(rde)) { Write32(p + 4, 0); } } else { if (!IsModrmRegister(rde) && !((uintptr_t)p & 1)) { atomic_store_explicit( (_Atomic(u16) *)q, atomic_exchange_explicit( (_Atomic(u16) *)p, atomic_load_explicit((_Atomic(u16) *)q, memory_order_relaxed), memory_order_acq_rel), memory_order_relaxed); } else { u16 x, y; if (!IsModrmRegister(rde)) LockBus(p); y = Load16(p); x = Read16(q); Write16(q, y); Store16(p, x); if (!IsModrmRegister(rde)) UnlockBus(p); } } } ================================================ FILE: blink/xlat.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/xlat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "blink/builtin.h" #include "blink/case.h" #include "blink/endian.h" #include "blink/errno.h" #include "blink/linux.h" #include "blink/log.h" #include "blink/macros.h" #include "blink/map.h" #include "blink/ndelay.h" #include "blink/sigwinch.h" #include "blink/util.h" #if defined(__APPLE__) || defined(__NetBSD__) #define st_atim st_atimespec #define st_ctim st_ctimespec #define st_mtim st_mtimespec #endif // NSIG isn't POSIX but it's more common than SIGRTMAX which is. // Note: OpenBSD defines NSIG as 33, even though it only has 32. #ifdef NSIG #define TOPSIG NSIG #elif defined(SIGRTMAX) #define TOPSIG SIGRTMAX #else #define TOPSIG 32 #endif int XlatErrno(int x) { if (x == EPERM) return EPERM_LINUX; if (x == ENOENT) return ENOENT_LINUX; if (x == ESRCH) return ESRCH_LINUX; if (x == EINTR) return EINTR_LINUX; if (x == EIO) return EIO_LINUX; if (x == ENXIO) return ENXIO_LINUX; if (x == E2BIG) return E2BIG_LINUX; if (x == ENOEXEC) return ENOEXEC_LINUX; if (x == EBADF) return EBADF_LINUX; if (x == ECHILD) return ECHILD_LINUX; if (x == EAGAIN) return EAGAIN_LINUX; #if EWOULDBLOCK != EAGAIN if (x == EWOULDBLOCK) return EWOULDBLOCK_LINUX; #endif if (x == ENOMEM) return ENOMEM_LINUX; if (x == EACCES) return EACCES_LINUX; if (x == EFAULT) return EFAULT_LINUX; #ifdef ENOTBLK if (x == ENOTBLK) return ENOTBLK_LINUX; #endif if (x == EBUSY) return EBUSY_LINUX; if (x == EEXIST) return EEXIST_LINUX; if (x == EXDEV) return EXDEV_LINUX; if (x == ENODEV) return ENODEV_LINUX; if (x == ENOTDIR) return ENOTDIR_LINUX; if (x == EISDIR) return EISDIR_LINUX; if (x == EINVAL) return EINVAL_LINUX; if (x == ENFILE) return ENFILE_LINUX; if (x == EMFILE) return EMFILE_LINUX; if (x == ENOTTY) return ENOTTY_LINUX; if (x == ETXTBSY) return ETXTBSY_LINUX; if (x == EFBIG) return EFBIG_LINUX; if (x == ENOSPC) return ENOSPC_LINUX; if (x == ESPIPE) return ESPIPE_LINUX; if (x == EROFS) return EROFS_LINUX; if (x == EMLINK) return EMLINK_LINUX; if (x == EPIPE) return EPIPE_LINUX; if (x == EDOM) return EDOM_LINUX; if (x == ERANGE) return ERANGE_LINUX; if (x == EDEADLK) return EDEADLK_LINUX; if (x == ENAMETOOLONG) return ENAMETOOLONG_LINUX; if (x == ENOLCK) return ENOLCK_LINUX; if (x == ENOSYS) return ENOSYS_LINUX; if (x == ENOTEMPTY) return ENOTEMPTY_LINUX; if (x == ELOOP) return ELOOP_LINUX; if (x == ENOMSG) return ENOMSG_LINUX; if (x == EIDRM) return EIDRM_LINUX; #ifdef EREMOTE if (x == EREMOTE) return EREMOTE_LINUX; #endif if (x == EPROTO) return EPROTO_LINUX; if (x == EBADMSG) return EBADMSG_LINUX; if (x == EOVERFLOW) return EOVERFLOW_LINUX; if (x == EILSEQ) return EILSEQ_LINUX; #ifdef EUSERS if (x == EUSERS) return EUSERS_LINUX; #endif if (x == ENOTSOCK) return ENOTSOCK_LINUX; if (x == EDESTADDRREQ) return EDESTADDRREQ_LINUX; if (x == EMSGSIZE) return EMSGSIZE_LINUX; if (x == EPROTOTYPE) return EPROTOTYPE_LINUX; if (x == ENOPROTOOPT) return ENOPROTOOPT_LINUX; if (x == EPROTONOSUPPORT) return EPROTONOSUPPORT_LINUX; #ifdef ESOCKTNOSUPPORT if (x == ESOCKTNOSUPPORT) return ESOCKTNOSUPPORT_LINUX; #endif if (x == ENOTSUP) return ENOTSUP_LINUX; #if EOPNOTSUPP != ENOTSUP if (x == EOPNOTSUPP) return EOPNOTSUPP_LINUX; #endif #ifdef EPFNOSUPPORT if (x == EPFNOSUPPORT) return EPFNOSUPPORT_LINUX; #endif if (x == EAFNOSUPPORT) return EAFNOSUPPORT_LINUX; if (x == EADDRINUSE) return EADDRINUSE_LINUX; if (x == EADDRNOTAVAIL) return EADDRNOTAVAIL_LINUX; if (x == ENETDOWN) return ENETDOWN_LINUX; if (x == ENETUNREACH) return ENETUNREACH_LINUX; if (x == ENETRESET) return ENETRESET_LINUX; if (x == ECONNABORTED) return ECONNABORTED_LINUX; if (x == ECONNRESET) return ECONNRESET_LINUX; if (x == ENOBUFS) return ENOBUFS_LINUX; if (x == EISCONN) return EISCONN_LINUX; if (x == ENOTCONN) return ENOTCONN_LINUX; #ifdef ESHUTDOWN if (x == ESHUTDOWN) return ESHUTDOWN_LINUX; #endif #ifdef ETOOMANYREFS if (x == ETOOMANYREFS) return ETOOMANYREFS_LINUX; #endif if (x == ETIMEDOUT) return ETIMEDOUT_LINUX; if (x == ECONNREFUSED) return ECONNREFUSED_LINUX; #ifdef EHOSTDOWN if (x == EHOSTDOWN) return EHOSTDOWN_LINUX; #endif if (x == EHOSTUNREACH) return EHOSTUNREACH_LINUX; if (x == EALREADY) return EALREADY_LINUX; if (x == EINPROGRESS) return EINPROGRESS_LINUX; if (x == ESTALE) return ESTALE_LINUX; if (x == EDQUOT) return EDQUOT_LINUX; if (x == ECANCELED) return ECANCELED_LINUX; #ifdef EOWNERDEAD if (x == EOWNERDEAD) return EOWNERDEAD_LINUX; #endif #ifdef ENOTRECOVERABLE if (x == ENOTRECOVERABLE) return ENOTRECOVERABLE_LINUX; #endif #ifdef ETIME if (x == ETIME) return ETIME_LINUX; #endif #ifdef ENONET if (x == ENONET) return ENONET_LINUX; #endif #ifdef ERESTART if (x == ERESTART) return ERESTART_LINUX; #endif #ifdef ENOSR if (x == ENOSR) return ENOSR_LINUX; #endif #ifdef ENOSTR if (x == ENOSTR) return ENOSTR_LINUX; #endif #ifdef ENODATA if (x == ENODATA) return ENODATA_LINUX; #endif #ifdef EMULTIHOP if (x == EMULTIHOP) return EMULTIHOP_LINUX; #endif #ifdef ENOLINK if (x == ENOLINK) return ENOLINK_LINUX; #endif #ifdef ENOMEDIUM if (x == ENOMEDIUM) return ENOMEDIUM_LINUX; #endif #ifdef EMEDIUMTYPE if (x == EMEDIUMTYPE) return EMEDIUMTYPE_LINUX; #endif return x; } int XlatSignal(int x) { switch (x) { XLAT(SIGHUP_LINUX, SIGHUP); XLAT(SIGINT_LINUX, SIGINT); XLAT(SIGQUIT_LINUX, SIGQUIT); XLAT(SIGILL_LINUX, SIGILL); XLAT(SIGTRAP_LINUX, SIGTRAP); XLAT(SIGABRT_LINUX, SIGABRT); XLAT(SIGBUS_LINUX, SIGBUS); XLAT(SIGFPE_LINUX, SIGFPE); XLAT(SIGKILL_LINUX, SIGKILL); XLAT(SIGUSR1_LINUX, SIGUSR1); XLAT(SIGSEGV_LINUX, SIGSEGV); XLAT(SIGUSR2_LINUX, SIGUSR2); XLAT(SIGPIPE_LINUX, SIGPIPE); XLAT(SIGALRM_LINUX, SIGALRM); XLAT(SIGTERM_LINUX, SIGTERM); #ifdef SIGSTKFLT XLAT(SIGSTKFLT_LINUX, SIGSTKFLT); #endif XLAT(SIGCHLD_LINUX, SIGCHLD); XLAT(SIGCONT_LINUX, SIGCONT); XLAT(SIGSTOP_LINUX, SIGSTOP); XLAT(SIGTSTP_LINUX, SIGTSTP); XLAT(SIGTTIN_LINUX, SIGTTIN); XLAT(SIGTTOU_LINUX, SIGTTOU); XLAT(SIGURG_LINUX, SIGURG); XLAT(SIGXCPU_LINUX, SIGXCPU); XLAT(SIGXFSZ_LINUX, SIGXFSZ); XLAT(SIGVTALRM_LINUX, SIGVTALRM); XLAT(SIGPROF_LINUX, SIGPROF); XLAT(SIGWINCH_LINUX, SIGWINCH); #ifdef SIGIO XLAT(SIGIO_LINUX, SIGIO); #endif #ifdef SIGPWR XLAT(SIGPWR_LINUX, SIGPWR); #endif XLAT(SIGSYS_LINUX, SIGSYS); default: break; } #ifdef SIGRTMIN if ((SIGRTMIN_LINUX <= x && x <= SIGRTMAX_LINUX) && SIGRTMIN + (x - SIGRTMIN_LINUX) <= SIGRTMAX) { return SIGRTMIN + (x - SIGRTMIN_LINUX); } #endif return einval(); } int XlatResource(int x) { switch (x) { XLAT(RLIMIT_CPU_LINUX, RLIMIT_CPU); XLAT(RLIMIT_FSIZE_LINUX, RLIMIT_FSIZE); XLAT(RLIMIT_DATA_LINUX, RLIMIT_DATA); XLAT(RLIMIT_STACK_LINUX, RLIMIT_STACK); XLAT(RLIMIT_CORE_LINUX, RLIMIT_CORE); #ifdef RLIMIT_AS XLAT(RLIMIT_AS_LINUX, RLIMIT_AS); #endif #ifndef DISABLE_NONPOSIX #ifdef RLIMIT_RSS XLAT(RLIMIT_RSS_LINUX, RLIMIT_RSS); #endif #ifdef RLIMIT_NPROC XLAT(RLIMIT_NPROC_LINUX, RLIMIT_NPROC); #endif XLAT(RLIMIT_NOFILE_LINUX, RLIMIT_NOFILE); #ifdef RLIMIT_MEMLOCK XLAT(RLIMIT_MEMLOCK_LINUX, RLIMIT_MEMLOCK); #endif #ifdef RLIMIT_LOCKS XLAT(RLIMIT_LOCKS_LINUX, RLIMIT_LOCKS); #endif #ifdef RLIMIT_SIGPENDING XLAT(RLIMIT_SIGPENDING_LINUX, RLIMIT_SIGPENDING); #endif #ifdef RLIMIT_MSGQUEUE XLAT(RLIMIT_MSGQUEUE_LINUX, RLIMIT_MSGQUEUE); #endif #ifdef RLIMIT_NICE XLAT(RLIMIT_NICE_LINUX, RLIMIT_NICE); #endif #ifdef RLIMIT_RTPRIO XLAT(RLIMIT_RTPRIO_LINUX, RLIMIT_RTPRIO); #endif #ifdef RLIMIT_RTTIME XLAT(RLIMIT_RTTIME_LINUX, RLIMIT_RTTIME); #endif #endif /* DISABLE_NONPOSIX */ default: LOGF("rlimit %d not supported yet", x); return einval(); } } int UnXlatSignal(int x) { if (x == SIGHUP) return SIGHUP_LINUX; if (x == SIGINT) return SIGINT_LINUX; if (x == SIGQUIT) return SIGQUIT_LINUX; if (x == SIGILL) return SIGILL_LINUX; if (x == SIGTRAP) return SIGTRAP_LINUX; if (x == SIGABRT) return SIGABRT_LINUX; if (x == SIGBUS) return SIGBUS_LINUX; if (x == SIGFPE) return SIGFPE_LINUX; if (x == SIGKILL) return SIGKILL_LINUX; if (x == SIGUSR1) return SIGUSR1_LINUX; if (x == SIGSEGV) return SIGSEGV_LINUX; if (x == SIGUSR2) return SIGUSR2_LINUX; if (x == SIGPIPE) return SIGPIPE_LINUX; if (x == SIGALRM) return SIGALRM_LINUX; if (x == SIGTERM) return SIGTERM_LINUX; if (x == SIGCHLD) return SIGCHLD_LINUX; if (x == SIGCONT) return SIGCONT_LINUX; if (x == SIGTTIN) return SIGTTIN_LINUX; if (x == SIGTTOU) return SIGTTOU_LINUX; if (x == SIGXCPU) return SIGXCPU_LINUX; if (x == SIGXFSZ) return SIGXFSZ_LINUX; if (x == SIGVTALRM) return SIGVTALRM_LINUX; if (x == SIGPROF) return SIGPROF_LINUX; if (x == SIGWINCH) return SIGWINCH_LINUX; #ifdef SIGIO if (x == SIGIO) return SIGIO_LINUX; #endif #ifdef SIGPWR if (x == SIGPWR) return SIGPWR_LINUX; #endif #ifdef SIGSTKFLT if (x == SIGSTKFLT) return SIGSTKFLT_LINUX; #endif if (x == SIGSTOP) return SIGSTOP_LINUX; if (x == SIGSYS) return SIGSYS_LINUX; if (x == SIGTSTP) return SIGTSTP_LINUX; if (x == SIGURG) return SIGURG_LINUX; #ifdef SIGRTMIN if ((SIGRTMIN <= x && x <= SIGRTMAX) && SIGRTMIN_LINUX + (x - SIGRTMIN) <= SIGRTMAX_LINUX) { return SIGRTMIN_LINUX + (x - SIGRTMIN); } #endif return einval(); } int UnXlatSiCode(int sig, int code) { #ifdef SI_USER if (code == SI_USER) return SI_USER_LINUX; #endif #ifdef SI_QUEUE if (code == SI_QUEUE) return SI_QUEUE_LINUX; #endif #ifdef SI_TIMER if (code == SI_TIMER) return SI_TIMER_LINUX; #endif #ifdef SI_TKILL if (code == SI_TKILL) return SI_TKILL_LINUX; #endif #ifdef SI_MESGQ if (code == SI_MESGQ) return SI_MESGQ_LINUX; #endif #ifdef SI_ASYNCIO if (code == SI_ASYNCIO) return SI_ASYNCIO_LINUX; #endif #ifdef SI_ASYNCNL if (code == SI_ASYNCNL) return SI_ASYNCNL_LINUX; #endif #ifdef SI_KERNEL if (code == SI_KERNEL) return SI_KERNEL_LINUX; #endif #ifdef SI_NOINFO if (code == SI_NOINFO) return SI_NOINFO_LINUX; #endif switch (sig) { case SIGCHLD_LINUX: #ifdef CLD_EXITED if (code == CLD_EXITED) return CLD_EXITED_LINUX; #endif #ifdef CLD_KILLED if (code == CLD_KILLED) return CLD_KILLED_LINUX; #endif #ifdef CLD_DUMPED if (code == CLD_DUMPED) return CLD_DUMPED_LINUX; #endif #ifdef CLD_TRAPPED if (code == CLD_TRAPPED) return CLD_TRAPPED_LINUX; #endif #ifdef CLD_STOPPED if (code == CLD_STOPPED) return CLD_STOPPED_LINUX; #endif #ifdef CLD_CONTINUED if (code == CLD_CONTINUED) return CLD_CONTINUED_LINUX; #endif break; case SIGTRAP_LINUX: #ifdef TRAP_BRKPT if (code == TRAP_BRKPT) return TRAP_BRKPT_LINUX; #endif #ifdef TRAP_TRACE if (code == TRAP_TRACE) return TRAP_TRACE_LINUX; #endif break; case SIGSEGV_LINUX: #ifdef SEGV_MAPERR if (code == SEGV_MAPERR) return SEGV_MAPERR_LINUX; #endif #ifdef SEGV_ACCERR if (code == SEGV_ACCERR) return SEGV_ACCERR_LINUX; #endif #ifdef SEGV_PKUERR if (code == SEGV_PKUERR) return SEGV_PKUERR_LINUX; #endif break; case SIGFPE_LINUX: #ifdef FPE_INTDIV if (code == FPE_INTDIV) return FPE_INTDIV_LINUX; #endif #ifdef FPE_INTOVF if (code == FPE_INTOVF) return FPE_INTOVF_LINUX; #endif #ifdef FPE_FLTDIV if (code == FPE_FLTDIV) return FPE_FLTDIV_LINUX; #endif #ifdef FPE_FLTOVF if (code == FPE_FLTOVF) return FPE_FLTOVF_LINUX; #endif #ifdef FPE_FLTUND if (code == FPE_FLTUND) return FPE_FLTUND_LINUX; #endif #ifdef FPE_FLTRES if (code == FPE_FLTRES) return FPE_FLTRES_LINUX; #endif #ifdef FPE_FLTINV if (code == FPE_FLTINV) return FPE_FLTINV_LINUX; #endif #ifdef FPE_FLTSUB if (code == FPE_FLTSUB) return FPE_FLTSUB_LINUX; #endif break; case SIGILL_LINUX: #ifdef ILL_ILLOPC if (code == ILL_ILLOPC) return ILL_ILLOPC_LINUX; #endif #ifdef ILL_ILLOPN if (code == ILL_ILLOPN) return ILL_ILLOPN_LINUX; #endif #ifdef ILL_ILLADR if (code == ILL_ILLADR) return ILL_ILLADR_LINUX; #endif #ifdef ILL_ILLTRP if (code == ILL_ILLTRP) return ILL_ILLTRP_LINUX; #endif #ifdef ILL_PRVOPC if (code == ILL_PRVOPC) return ILL_PRVOPC_LINUX; #endif #ifdef ILL_PRVREG if (code == ILL_PRVREG) return ILL_PRVREG_LINUX; #endif #ifdef ILL_COPROC if (code == ILL_COPROC) return ILL_COPROC_LINUX; #endif #ifdef ILL_BADSTK if (code == ILL_BADSTK) return ILL_BADSTK_LINUX; #endif break; case SIGBUS_LINUX: #ifdef BUS_ADRALN if (code == BUS_ADRALN) return BUS_ADRALN_LINUX; #endif #ifdef BUS_ADRERR if (code == BUS_ADRERR) return BUS_ADRERR_LINUX; #endif #ifdef BUS_OBJERR if (code == BUS_OBJERR) return BUS_OBJERR_LINUX; #endif #ifdef BUS_OOMERR if (code == BUS_OOMERR) return BUS_OOMERR_LINUX; #endif #ifdef BUS_MCEERR_AR if (code == BUS_MCEERR_AR) return BUS_MCEERR_AR_LINUX; #endif #ifdef BUS_MCEERR_AO if (code == BUS_MCEERR_AO) return BUS_MCEERR_AO_LINUX; #endif break; case SIGIO_LINUX: #ifdef POLL_IN if (code == POLL_IN) return POLL_IN_LINUX; #endif #ifdef POLL_OUT if (code == POLL_OUT) return POLL_OUT_LINUX; #endif #ifdef POLL_MSG if (code == POLL_MSG) return POLL_MSG_LINUX; #endif #ifdef POLL_ERR if (code == POLL_ERR) return POLL_ERR_LINUX; #endif #ifdef POLL_PRI if (code == POLL_PRI) return POLL_PRI_LINUX; #endif #ifdef POLL_HUP if (code == POLL_HUP) return POLL_HUP_LINUX; #endif break; default: break; } return code; } int XlatRusage(int x) { switch (x) { XLAT(0, RUSAGE_SELF); XLAT(-1, RUSAGE_CHILDREN); default: LOGF("%s %d not supported yet", "rusage", x); return einval(); } } int XlatSocketFamily(int x) { switch (x) { XLAT(AF_UNSPEC_LINUX, AF_UNSPEC); XLAT(AF_UNIX_LINUX, AF_UNIX); XLAT(AF_INET_LINUX, AF_INET); XLAT(AF_INET6_LINUX, AF_INET6); default: LOGF("%s %d not supported yet", "socket family", x); errno = ENOPROTOOPT; return -1; } } int UnXlatSocketFamily(int x) { if (x == AF_UNSPEC) return AF_UNSPEC_LINUX; if (x == AF_UNIX) return AF_UNIX_LINUX; if (x == AF_INET) return AF_INET_LINUX; if (x == AF_INET6) return AF_INET6_LINUX; LOGF("don't know how to translate %s %d", "socket family", x); return x; } int XlatSocketType(int x) { switch (x) { XLAT(SOCK_STREAM_LINUX, SOCK_STREAM); XLAT(SOCK_DGRAM_LINUX, SOCK_DGRAM); XLAT(SOCK_RAW_LINUX, SOCK_RAW); default: LOGF("%s %d not supported yet", "socket type", x); return einval(); } } int XlatSocketProtocol(int x) { switch (x) { XLAT(0, 0); XLAT(IPPROTO_RAW_LINUX, IPPROTO_RAW); XLAT(IPPROTO_TCP_LINUX, IPPROTO_TCP); XLAT(IPPROTO_UDP_LINUX, IPPROTO_UDP); XLAT(IPPROTO_ICMP_LINUX, IPPROTO_ICMP); #ifdef IPPROTO_ICMPV6 XLAT(IPPROTO_ICMPV6_LINUX, IPPROTO_ICMPV6); #endif default: LOGF("%s %d not supported yet", "socket protocol", x); return einval(); } } int XlatSocketLevel(int x, int *level) { // Haiku defines SOL_SOCKET as -1 int res; switch (x) { CASE(SOL_SOCKET_LINUX, res = SOL_SOCKET); CASE(SOL_IP_LINUX, res = IPPROTO_IP); CASE(SOL_IPV6_LINUX, res = IPPROTO_IPV6); CASE(SOL_TCP_LINUX, res = IPPROTO_TCP); CASE(SOL_UDP_LINUX, res = IPPROTO_UDP); default: LOGF("%s %d not supported yet", "socket level", x); return einval(); } *level = res; return 0; } int XlatSocketOptname(int level, int optname) { switch (level) { case SOL_SOCKET_LINUX: switch (optname) { XLAT(SO_TYPE_LINUX, SO_TYPE); XLAT(SO_ERROR_LINUX, SO_ERROR); XLAT(SO_DEBUG_LINUX, SO_DEBUG); XLAT(SO_REUSEADDR_LINUX, SO_REUSEADDR); XLAT(SO_DONTROUTE_LINUX, SO_DONTROUTE); XLAT(SO_SNDBUF_LINUX, SO_SNDBUF); XLAT(SO_RCVBUF_LINUX, SO_RCVBUF); XLAT(SO_BROADCAST_LINUX, SO_BROADCAST); XLAT(SO_KEEPALIVE_LINUX, SO_KEEPALIVE); XLAT(SO_RCVTIMEO_LINUX, SO_RCVTIMEO); XLAT(SO_SNDTIMEO_LINUX, SO_SNDTIMEO); XLAT(SO_RCVLOWAT_LINUX, SO_RCVLOWAT); XLAT(SO_SNDLOWAT_LINUX, SO_SNDLOWAT); #ifndef DISABLE_NONPOSIX #ifdef SO_REUSEPORT XLAT(SO_REUSEPORT_LINUX, SO_REUSEPORT); #endif #endif default: break; } break; #ifndef DISABLE_NONPOSIX case SOL_IP_LINUX: switch (optname) { #ifdef IP_TOS XLAT(IP_TOS_LINUX, IP_TOS); #endif #ifdef IP_TTL XLAT(IP_TTL_LINUX, IP_TTL); #endif #ifdef IP_HDRINCL XLAT(IP_HDRINCL_LINUX, IP_HDRINCL); #endif #ifdef IP_OPTIONS XLAT(IP_OPTIONS_LINUX, IP_OPTIONS); #endif #ifdef IP_RECVTTL XLAT(IP_RECVTTL_LINUX, IP_RECVTTL); #endif #ifdef IP_RECVERR XLAT(IP_RECVERR_LINUX, IP_RECVERR); #endif #ifdef IP_RETOPTS XLAT(IP_RETOPTS_LINUX, IP_RETOPTS); #endif default: break; } break; case SOL_IPV6_LINUX: switch (optname) { #ifdef IPV6_RECVERR XLAT(IPV6_RECVERR_LINUX, IPV6_RECVERR); #endif default: break; } break; #endif /* DISABLE_NONPOSIX */ case SOL_TCP_LINUX: switch (optname) { XLAT(TCP_NODELAY_LINUX, TCP_NODELAY); #ifndef DISABLE_NONPOSIX #ifdef TCP_MAXSEG XLAT(TCP_MAXSEG_LINUX, TCP_MAXSEG); #endif #if defined(TCP_CORK) XLAT(TCP_CORK_LINUX, TCP_CORK); #elif defined(TCP_NOPUSH) XLAT(TCP_NOPUSH_LINUX, TCP_NOPUSH); #endif #ifdef TCP_KEEPIDLE XLAT(TCP_KEEPIDLE_LINUX, TCP_KEEPIDLE); #endif #ifdef TCP_KEEPINTVL XLAT(TCP_KEEPINTVL_LINUX, TCP_KEEPINTVL); #endif #ifdef TCP_KEEPCNT XLAT(TCP_KEEPCNT_LINUX, TCP_KEEPCNT); #endif #ifdef TCP_SYNCNT XLAT(TCP_SYNCNT_LINUX, TCP_SYNCNT); #endif #ifdef TCP_DEFER_ACCEPT XLAT(TCP_DEFER_ACCEPT_LINUX, TCP_DEFER_ACCEPT); #endif #ifdef TCP_WINDOW_CLAMP XLAT(TCP_WINDOW_CLAMP_LINUX, TCP_WINDOW_CLAMP); #endif #ifdef TCP_FASTOPEN XLAT(TCP_FASTOPEN_LINUX, TCP_FASTOPEN); #endif #ifdef TCP_NOTSENT_LOWAT XLAT(TCP_NOTSENT_LOWAT_LINUX, TCP_NOTSENT_LOWAT); #endif #ifdef TCP_FASTOPEN_CONNECT XLAT(TCP_FASTOPEN_CONNECT_LINUX, TCP_FASTOPEN_CONNECT); #endif #ifdef TCP_QUICKACK XLAT(TCP_QUICKACK_LINUX, TCP_QUICKACK); #endif #ifdef TCP_SAVE_SYN XLAT(TCP_SAVE_SYN_LINUX, TCP_SAVE_SYN); #endif #endif /* DISABLE_NONPOSIX */ default: break; } break; default: break; } LOGF("socket level %d optname %d not supported yet", level, optname); return einval(); } int XlatAccess(int x) { int r = 0; if (x == F_OK_LINUX) return F_OK; if (x & X_OK_LINUX) r |= X_OK, x &= ~X_OK_LINUX; if (x & W_OK_LINUX) r |= W_OK, x &= ~W_OK_LINUX; if (x & R_OK_LINUX) r |= R_OK, x &= ~R_OK_LINUX; if (x) return einval(); return r; } int XlatShutdown(int x) { if (x == SHUT_RD_LINUX) return SHUT_RD; if (x == SHUT_WR_LINUX) return SHUT_WR; if (x == SHUT_RDWR_LINUX) return SHUT_RDWR; return einval(); } int XlatWait(int x) { int r = 0; if (x & WNOHANG_LINUX) { r |= WNOHANG; x &= ~WNOHANG_LINUX; } if (x & WUNTRACED_LINUX) { r |= WUNTRACED; x &= ~WUNTRACED_LINUX; } #ifdef WCONTINUED if (x & WCONTINUED_LINUX) { r |= WCONTINUED; x &= ~WCONTINUED_LINUX; } #endif if (x) { LOGF("%s %d not supported yet", "wait", x); return einval(); } return r; } int XlatClock(int x, clock_t *clock) { // Haiku defines CLOCK_REALTIME as -1 clock_t res; switch (x) { CASE(CLOCK_REALTIME_LINUX, res = CLOCK_REALTIME); CASE(CLOCK_MONOTONIC_LINUX, res = CLOCK_MONOTONIC); CASE(CLOCK_PROCESS_CPUTIME_ID_LINUX, res = CLOCK_PROCESS_CPUTIME_ID); CASE(CLOCK_THREAD_CPUTIME_ID_LINUX, res = CLOCK_THREAD_CPUTIME_ID); #ifndef DISABLE_NONPOSIX #ifdef CLOCK_REALTIME_COARSE CASE(CLOCK_REALTIME_COARSE_LINUX, res = CLOCK_REALTIME_COARSE); #elif defined(CLOCK_REALTIME_FAST) CASE(CLOCK_REALTIME_FAST_LINUX, res = CLOCK_REALTIME_FAST); #endif #ifdef CLOCK_MONOTONIC_COARSE CASE(CLOCK_MONOTONIC_COARSE_LINUX, res = CLOCK_MONOTONIC_COARSE); #elif defined(CLOCK_REALTIME_FAST) CASE(CLOCK_MONOTONIC_FAST_LINUX, res = CLOCK_MONOTONIC_FAST); #endif #ifdef CLOCK_MONOTONIC_RAW CASE(CLOCK_MONOTONIC_RAW_LINUX, res = CLOCK_MONOTONIC_RAW); #endif #ifdef CLOCK_BOOTTIME CASE(CLOCK_BOOTTIME_LINUX, res = CLOCK_BOOTTIME); #endif #ifdef CLOCK_TAI CASE(CLOCK_TAI_LINUX, res = CLOCK_TAI); #endif #endif /* DISABLE_NONPOSIX */ default: LOGF("%s %d not supported yet", "clock", x); return einval(); } *clock = res; return 0; } int XlatAccMode(int x) { switch (x & O_ACCMODE_LINUX) { case O_RDONLY_LINUX: return O_RDONLY; case O_WRONLY_LINUX: return O_WRONLY; case O_RDWR_LINUX: return O_RDWR; default: return einval(); } } int UnXlatAccMode(int flags) { switch (flags & O_ACCMODE) { case O_RDONLY: return O_RDONLY_LINUX; case O_WRONLY: return O_WRONLY_LINUX; case O_RDWR: return O_RDWR_LINUX; default: return einval(); } } int XlatOpenFlags(int x) { int res; res = XlatAccMode(x); x &= ~O_ACCMODE_LINUX; if (x & O_APPEND_LINUX) res |= O_APPEND, x &= ~O_APPEND_LINUX; if (x & O_CREAT_LINUX) res |= O_CREAT, x &= ~O_CREAT_LINUX; if (x & O_EXCL_LINUX) res |= O_EXCL, x &= ~O_EXCL_LINUX; if (x & O_TRUNC_LINUX) res |= O_TRUNC, x &= ~O_TRUNC_LINUX; #ifdef O_PATH if (x & O_PATH_LINUX) res |= O_PATH, x &= ~O_PATH_LINUX; #elif defined(O_EXEC) if (x & O_PATH_LINUX) res |= O_EXEC, x &= ~O_PATH_LINUX; #else x &= ~O_PATH_LINUX; #endif #ifdef O_LARGEFILE if (x & O_LARGEFILE_LINUX) res |= O_LARGEFILE, x &= ~O_LARGEFILE_LINUX; #else x &= ~O_LARGEFILE_LINUX; #endif #ifdef O_NDELAY if (x & O_NDELAY_LINUX) res |= O_NDELAY, x &= ~O_NDELAY_LINUX; #endif #ifdef O_DIRECT if (x & O_DIRECT_LINUX) res |= O_DIRECT, x &= ~O_DIRECT_LINUX; #endif #ifdef O_SYNC if ((x & O_SYNC_LINUX) == O_SYNC_LINUX) { res |= O_SYNC; x &= ~O_SYNC_LINUX; } // order matters: O_DSYNC ⊂ O_SYNC #endif #ifdef O_DSYNC if (x & O_DSYNC_LINUX) { res |= O_DSYNC; x &= ~O_DSYNC_LINUX; } #endif #ifndef DISABLE_NONPOSIX #ifdef O_TMPFILE if ((x & O_TMPFILE_LINUX) == O_TMPFILE_LINUX) { res |= O_TMPFILE; x &= ~O_TMPFILE_LINUX; } // order matters: O_DIRECTORY ⊂ O_TMPFILE #endif #endif if (x & O_DIRECTORY_LINUX) { res |= O_DIRECTORY; x &= ~O_DIRECTORY_LINUX; } #ifdef O_NOFOLLOW if (x & O_NOFOLLOW_LINUX) res |= O_NOFOLLOW, x &= ~O_NOFOLLOW_LINUX; #endif if (x & O_CLOEXEC_LINUX) res |= O_CLOEXEC, x &= ~O_CLOEXEC_LINUX; if (x & O_NOCTTY_LINUX) res |= O_NOCTTY, x &= ~O_NOCTTY_LINUX; #ifndef DISABLE_NONPOSIX #ifdef O_ASYNC if (x & O_ASYNC_LINUX) res |= O_ASYNC, x &= ~O_ASYNC_LINUX; #endif #endif #ifndef DISABLE_NONPOSIX #ifdef O_NOATIME if (x & O_NOATIME_LINUX) res |= O_NOATIME, x &= ~O_NOATIME_LINUX; #endif #endif if (x) { LOGF("%s %#x not supported", "open flags", x); return einval(); } return res; } int UnXlatOpenFlags(int x) { int res; res = UnXlatAccMode(x); if ((x & O_APPEND) == O_APPEND) { res |= O_APPEND_LINUX; x &= ~O_APPEND; } if ((x & O_CREAT) == O_CREAT) { res |= O_CREAT_LINUX; x &= ~O_CREAT; } if ((x & O_EXCL) == O_EXCL) { res |= O_EXCL_LINUX; x &= ~O_EXCL; } if ((x & O_TRUNC) == O_TRUNC) { res |= O_TRUNC_LINUX; x &= ~O_TRUNC; } #ifdef O_PATH if ((x & O_PATH) == O_PATH) { res |= O_PATH_LINUX; x &= ~O_PATH; } #elif defined(O_EXEC) if ((x & O_EXEC) == O_EXEC) { res |= O_PATH_LINUX; x &= ~O_EXEC; } #endif #ifdef O_LARGEFILE if ((x & O_LARGEFILE) == O_LARGEFILE) { res |= O_LARGEFILE_LINUX; x &= ~O_LARGEFILE; } #endif #ifdef O_NDELAY if ((x & O_NDELAY) == O_NDELAY) { res |= O_NDELAY_LINUX; x &= ~O_NDELAY; } #endif #ifdef O_DIRECT if ((x & O_DIRECT) == O_DIRECT) { res |= O_DIRECT_LINUX; x &= ~O_DIRECT; } #endif #ifndef DISABLE_NONPOSIX #ifdef O_TMPFILE if ((x & O_TMPFILE) == O_TMPFILE) { res |= O_TMPFILE_LINUX; x &= ~O_TMPFILE; } #endif #endif if ((x & O_DIRECTORY) == O_DIRECTORY) { res |= O_DIRECTORY_LINUX; x &= ~O_DIRECTORY; } #ifdef O_SYNC if ((x & O_SYNC) == O_SYNC) { res |= O_SYNC_LINUX; x &= ~O_SYNC; } #endif #ifdef O_NOFOLLOW if ((x & O_NOFOLLOW) == O_NOFOLLOW) { res |= O_NOFOLLOW_LINUX; x &= ~O_NOFOLLOW; } #endif if ((x & O_CLOEXEC) == O_CLOEXEC) { res |= O_CLOEXEC_LINUX; x &= ~O_CLOEXEC; } if ((x & O_NOCTTY) == O_NOCTTY) { res |= O_NOCTTY_LINUX; x &= ~O_NOCTTY; } #ifndef DISABLE_NONPOSIX #ifdef O_ASYNC if ((x & O_ASYNC) == O_ASYNC) { res |= O_ASYNC_LINUX; x &= ~O_ASYNC; } #endif #endif #ifndef DISABLE_NONPOSIX #ifdef O_NOATIME if ((x & O_NOATIME) == O_NOATIME) { res |= O_NOATIME_LINUX; x &= ~O_NOATIME; } #endif #endif #ifdef O_DSYNC if ((x & O_DSYNC) == O_DSYNC) { res |= O_DSYNC_LINUX; x &= ~O_DSYNC; } #endif return res; } int UnXlatItimer(int x) { switch (x) { case ITIMER_REAL_LINUX: return ITIMER_REAL; case ITIMER_VIRTUAL_LINUX: return ITIMER_VIRTUAL; case ITIMER_PROF_LINUX: return ITIMER_PROF; default: LOGF("%s %#x not supported", "itimer", x); return einval(); } } int XlatSockaddrToHost(struct sockaddr_storage *dst, const struct sockaddr_linux *src, u32 srclen) { if (srclen < 2) { LOGF("sockaddr size %d too small for %s", (int)srclen, "family"); return einval(); } switch (Read16(src->family)) { case AF_UNSPEC_LINUX: memset(dst, 0, sizeof(*dst)); dst->ss_family = AF_UNSPEC; return sizeof(*dst); case AF_UNIX_LINUX: { size_t n; struct sockaddr_un *dst_un; const struct sockaddr_un_linux *src_un; if (srclen < offsetof(struct sockaddr_un_linux, path)) { LOGF("sockaddr size too small for %s", "sockaddr_un_linux"); return einval(); } dst_un = (struct sockaddr_un *)dst; src_un = (const struct sockaddr_un_linux *)src; n = strnlen(src_un->path, MIN(srclen - offsetof(struct sockaddr_un_linux, path), sizeof(src_un->path))); if (n >= sizeof(dst_un->sun_path)) { LOGF("sockaddr_un path too long for host"); return einval(); } memset(dst_un, 0, sizeof(*dst_un)); dst_un->sun_family = AF_UNIX; if (n) memcpy(dst_un->sun_path, src_un->path, n); dst_un->sun_path[n] = 0; return sizeof(struct sockaddr_un); } case AF_INET_LINUX: { struct sockaddr_in *dst_in; const struct sockaddr_in_linux *src_in; if (srclen < sizeof(struct sockaddr_in_linux)) { LOGF("sockaddr size too small for %s", "sockaddr_in_linux"); return einval(); } dst_in = (struct sockaddr_in *)dst; src_in = (const struct sockaddr_in_linux *)src; memset(dst_in, 0, sizeof(*dst_in)); dst_in->sin_family = AF_INET; dst_in->sin_port = src_in->port; dst_in->sin_addr.s_addr = src_in->addr; return sizeof(struct sockaddr_in); } case AF_INET6_LINUX: { struct sockaddr_in6 *dst_in; const struct sockaddr_in6_linux *src_in; _Static_assert(sizeof(dst_in->sin6_addr) == 16, ""); _Static_assert(sizeof(src_in->addr) == 16, ""); if (srclen < sizeof(struct sockaddr_in6_linux)) { LOGF("sockaddr size too small for %s", "sockaddr_in6_linux"); return einval(); } dst_in = (struct sockaddr_in6 *)dst; src_in = (const struct sockaddr_in6_linux *)src; memset(dst_in, 0, sizeof(*dst_in)); dst_in->sin6_family = AF_INET6; dst_in->sin6_port = src_in->port; memcpy(&dst_in->sin6_addr, src_in->addr, 16); return sizeof(struct sockaddr_in6); } default: LOGF("%s %d not supported yet", "socket family", Read16(src->family)); errno = EAFNOSUPPORT; return -1; } } int XlatSockaddrToLinux(struct sockaddr_storage_linux *dst, const struct sockaddr *src, socklen_t srclen) { if (srclen < 2) { LOGF("sockaddr size %d too small for %s", (int)srclen, "family"); return einval(); } if (src->sa_family == AF_UNIX) { size_t n; struct sockaddr_un_linux *dst_un; const struct sockaddr_un *src_un; if (srclen < offsetof(struct sockaddr_un, sun_path)) { LOGF("sockaddr size %d too small for %s", (int)srclen, "sockaddr_un"); return einval(); } dst_un = (struct sockaddr_un_linux *)dst; src_un = (const struct sockaddr_un *)src; n = strnlen(src_un->sun_path, MIN(srclen - offsetof(struct sockaddr_un, sun_path), sizeof(src_un->sun_path))); if (n >= sizeof(dst_un->path)) { LOGF("sockaddr_un path too long for linux"); return einval(); } memset(dst_un, 0, sizeof(*dst_un)); Write16(dst_un->family, AF_UNIX_LINUX); if (n) memcpy(dst_un->path, src_un->sun_path, n); dst_un->path[n] = 0; return offsetof(struct sockaddr_un, sun_path) + n + 1; } else if (src->sa_family == AF_INET) { struct sockaddr_in_linux *dst_in; const struct sockaddr_in *src_in; if (srclen < sizeof(struct sockaddr_in)) { LOGF("sockaddr size %d too small for %s", (int)srclen, "sockaddr_in"); return einval(); } dst_in = (struct sockaddr_in_linux *)dst; src_in = (const struct sockaddr_in *)src; memset(dst_in, 0, sizeof(*dst_in)); Write16(dst_in->family, AF_INET_LINUX); dst_in->port = src_in->sin_port; dst_in->addr = src_in->sin_addr.s_addr; return sizeof(struct sockaddr_in_linux); } else if (src->sa_family == AF_INET6) { struct sockaddr_in6_linux *dst_in; const struct sockaddr_in6 *src_in; if (srclen < sizeof(struct sockaddr_in6)) { LOGF("sockaddr size %d too small for %s", (int)srclen, "sockaddr_in6"); return einval(); } dst_in = (struct sockaddr_in6_linux *)dst; src_in = (const struct sockaddr_in6 *)src; memset(dst_in, 0, sizeof(*dst_in)); Write16(dst_in->family, AF_INET6_LINUX); dst_in->port = src_in->sin6_port; memcpy(dst_in->addr, &src_in->sin6_addr, 16); return sizeof(struct sockaddr_in6_linux); } else { LOGF("%s %d not supported yet", "socket family", src->sa_family); errno = EAFNOSUPPORT; return -1; } } void XlatStatToLinux(struct stat_linux *dst, const struct stat *src) { Write64(dst->dev, src->st_dev); Write64(dst->ino, src->st_ino); Write64(dst->nlink, src->st_nlink); Write32(dst->mode, src->st_mode); Write32(dst->uid, src->st_uid); Write32(dst->gid, src->st_gid); Write32(dst->pad_, 0); Write64(dst->rdev, src->st_rdev); Write64(dst->size, src->st_size); Write64(dst->blksize, src->st_blksize); Write64(dst->blocks, src->st_blocks); Write64(dst->dev, src->st_dev); Write64(dst->atim.sec, src->st_atim.tv_sec); Write64(dst->atim.nsec, src->st_atim.tv_nsec); Write64(dst->mtim.sec, src->st_mtim.tv_sec); Write64(dst->mtim.nsec, src->st_mtim.tv_nsec); Write64(dst->ctim.sec, src->st_ctim.tv_sec); Write64(dst->ctim.nsec, src->st_ctim.tv_nsec); } void XlatRusageToLinux(struct rusage_linux *dst, const struct rusage *src) { Write64(dst->utime.sec, src->ru_utime.tv_sec); Write64(dst->utime.usec, src->ru_utime.tv_usec); Write64(dst->stime.sec, src->ru_stime.tv_sec); Write64(dst->stime.usec, src->ru_stime.tv_usec); Write64(dst->maxrss, src->ru_maxrss); Write64(dst->ixrss, src->ru_ixrss); Write64(dst->idrss, src->ru_idrss); Write64(dst->isrss, src->ru_isrss); Write64(dst->minflt, src->ru_minflt); Write64(dst->majflt, src->ru_majflt); Write64(dst->nswap, src->ru_nswap); Write64(dst->inblock, src->ru_inblock); Write64(dst->oublock, src->ru_oublock); Write64(dst->msgsnd, src->ru_msgsnd); Write64(dst->msgrcv, src->ru_msgrcv); Write64(dst->nsignals, src->ru_nsignals); Write64(dst->nvcsw, src->ru_nvcsw); Write64(dst->nivcsw, src->ru_nivcsw); } static u64 XlatRlimitToLinuxScalar(u64 x) { if (x == RLIM_INFINITY) x = RLIM_INFINITY_LINUX; return x; } void XlatRlimitToLinux(struct rlimit_linux *dst, const struct rlimit *src) { Write64(dst->cur, XlatRlimitToLinuxScalar(src->rlim_cur)); Write64(dst->max, XlatRlimitToLinuxScalar(src->rlim_max)); } static u64 XlatLinuxToRlimitScalar(int r, u64 x) { if (x == RLIM_INFINITY_LINUX) { x = RLIM_INFINITY; } else if (r == RLIMIT_NOFILE) { x += 4; } else if (r == RLIMIT_CPU || // r == RLIMIT_DATA || // #ifdef RLIMIT_RSS r == RLIMIT_RSS || // #endif #ifdef RLIMIT_AS r == RLIMIT_AS || // #endif 0) { x *= 10; } return x; } void XlatLinuxToRlimit(int sysresource, struct rlimit *dst, const struct rlimit_linux *src) { dst->rlim_cur = XlatLinuxToRlimitScalar(sysresource, Read64(src->cur)); dst->rlim_max = XlatLinuxToRlimitScalar(sysresource, Read64(src->max)); } void XlatItimervalToLinux(struct itimerval_linux *dst, const struct itimerval *src) { Write64(dst->interval.sec, src->it_interval.tv_sec); Write64(dst->interval.usec, src->it_interval.tv_usec); Write64(dst->value.sec, src->it_value.tv_sec); Write64(dst->value.usec, src->it_value.tv_usec); } void XlatLinuxToItimerval(struct itimerval *dst, const struct itimerval_linux *src) { dst->it_interval.tv_sec = Read64(src->interval.sec); dst->it_interval.tv_usec = Read64(src->interval.usec); dst->it_value.tv_sec = Read64(src->value.sec); dst->it_value.tv_usec = Read64(src->value.usec); } void XlatWinsizeToLinux(struct winsize_linux *dst, const struct winsize *src) { memset(dst, 0, sizeof(*dst)); Write16(dst->row, src->ws_row); Write16(dst->col, src->ws_col); } void XlatWinsizeToHost(struct winsize *dst, const struct winsize_linux *src) { memset(dst, 0, sizeof(*dst)); dst->ws_row = Read16(src->row); dst->ws_col = Read16(src->col); } void XlatSigsetToLinux(u8 dst[8], const sigset_t *src) { u64 set = 0; int syssig, linuxsig; for (syssig = 1; syssig <= MIN(64, TOPSIG); ++syssig) { if (sigismember(src, syssig) == 1 && (linuxsig = UnXlatSignal(syssig)) != -1) { set |= (u64)1 << (linuxsig - 1); } } Write64(dst, set); } void XlatLinuxToSigset(sigset_t *dst, u64 set) { int syssig, linuxsig; sigemptyset(dst); for (linuxsig = 1; linuxsig <= MIN(64, TOPSIG); ++linuxsig) { if ((((u64)1 << (linuxsig - 1)) & set) && (syssig = XlatSignal(linuxsig)) != -1) { sigaddset(dst, syssig); } } } static int XlatTermiosCflag(int x) { int r = 0; if (x & CSTOPB_LINUX) r |= CSTOPB; if (x & CREAD_LINUX) r |= CREAD; if (x & PARENB_LINUX) r |= PARENB; if (x & PARODD_LINUX) r |= PARODD; if (x & HUPCL_LINUX) r |= HUPCL; if (x & CLOCAL_LINUX) r |= CLOCAL; if ((x & CSIZE_LINUX) == CS5_LINUX) { r |= CS5; } else if ((x & CSIZE_LINUX) == CS6_LINUX) { r |= CS6; } else if ((x & CSIZE_LINUX) == CS7_LINUX) { r |= CS7; } else if ((x & CSIZE_LINUX) == CS8_LINUX) { r |= CS8; } return r; } static int UnXlatTermiosCflag(int x) { int r = 0; if (x & CSTOPB) r |= CSTOPB_LINUX; if (x & CREAD) r |= CREAD_LINUX; if (x & PARENB) r |= PARENB_LINUX; if (x & PARODD) r |= PARODD_LINUX; if (x & HUPCL) r |= HUPCL_LINUX; if (x & CLOCAL) r |= CLOCAL_LINUX; if ((x & CSIZE) == CS5) { r |= CS5_LINUX; } else if ((x & CSIZE) == CS6) { r |= CS6_LINUX; } else if ((x & CSIZE) == CS7) { r |= CS7_LINUX; } else if ((x & CSIZE) == CS8) { r |= CS8_LINUX; } return r; } static int XlatTermiosLflag(int x) { int r = 0; if (x & ISIG_LINUX) r |= ISIG; if (x & ICANON_LINUX) r |= ICANON; if (x & ECHO_LINUX) r |= ECHO; if (x & ECHOE_LINUX) r |= ECHOE; if (x & ECHOK_LINUX) r |= ECHOK; if (x & ECHONL_LINUX) r |= ECHONL; if (x & NOFLSH_LINUX) r |= NOFLSH; if (x & TOSTOP_LINUX) r |= TOSTOP; if (x & IEXTEN_LINUX) r |= IEXTEN; #ifdef ECHOCTL if (x & ECHOCTL_LINUX) r |= ECHOCTL; #endif #ifdef ECHOPRT if (x & ECHOPRT_LINUX) r |= ECHOPRT; #endif #ifdef ECHOKE if (x & ECHOKE_LINUX) r |= ECHOKE; #endif #ifdef FLUSHO if (x & FLUSHO_LINUX) r |= FLUSHO; #endif #ifdef PENDIN if (x & PENDIN_LINUX) r |= PENDIN; #endif #ifdef XCASE if (x & XCASE_LINUX) r |= XCASE; #endif return r; } static int UnXlatTermiosLflag(int x) { int r = 0; if (x & ISIG) r |= ISIG_LINUX; if (x & ICANON) r |= ICANON_LINUX; if (x & ECHO) r |= ECHO_LINUX; if (x & ECHOE) r |= ECHOE_LINUX; if (x & ECHOK) r |= ECHOK_LINUX; if (x & ECHONL) r |= ECHONL_LINUX; if (x & NOFLSH) r |= NOFLSH_LINUX; if (x & TOSTOP) r |= TOSTOP_LINUX; if (x & IEXTEN) r |= IEXTEN_LINUX; #ifdef ECHOCTL if (x & ECHOCTL) r |= ECHOCTL_LINUX; #endif #ifdef ECHOPRT if (x & ECHOPRT) r |= ECHOPRT_LINUX; #endif #ifdef ECHOKE if (x & ECHOKE) r |= ECHOKE_LINUX; #endif #ifdef FLUSHO if (x & FLUSHO) r |= FLUSHO_LINUX; #endif #ifdef PENDIN if (x & PENDIN) r |= PENDIN_LINUX; #endif #ifdef XCASE if (x & XCASE) r |= XCASE_LINUX; #endif return r; } static int XlatTermiosIflag(int x) { int r = 0; if (x & IGNBRK_LINUX) r |= IGNBRK; if (x & BRKINT_LINUX) r |= BRKINT; if (x & IGNPAR_LINUX) r |= IGNPAR; if (x & PARMRK_LINUX) r |= PARMRK; if (x & INPCK_LINUX) r |= INPCK; if (x & ISTRIP_LINUX) r |= ISTRIP; if (x & INLCR_LINUX) r |= INLCR; if (x & IGNCR_LINUX) r |= IGNCR; if (x & ICRNL_LINUX) r |= ICRNL; if (x & IXON_LINUX) r |= IXON; #ifdef IXANY if (x & IXANY_LINUX) r |= IXANY; #endif if (x & IXOFF_LINUX) r |= IXOFF; #ifdef IMAXBEL if (x & IMAXBEL_LINUX) r |= IMAXBEL; #endif #ifdef IUTF8 if (x & IUTF8_LINUX) r |= IUTF8; #endif #ifdef IUCLC if (x & IUCLC_LINUX) r |= IUCLC; #endif return r; } static int UnXlatTermiosIflag(int x) { int r = 0; if (x & IGNBRK) r |= IGNBRK_LINUX; if (x & BRKINT) r |= BRKINT_LINUX; if (x & IGNPAR) r |= IGNPAR_LINUX; if (x & PARMRK) r |= PARMRK_LINUX; if (x & INPCK) r |= INPCK_LINUX; if (x & ISTRIP) r |= ISTRIP_LINUX; if (x & INLCR) r |= INLCR_LINUX; if (x & IGNCR) r |= IGNCR_LINUX; if (x & ICRNL) r |= ICRNL_LINUX; if (x & IXON) r |= IXON_LINUX; #ifdef IXANY if (x & IXANY) r |= IXANY_LINUX; #endif if (x & IXOFF) r |= IXOFF_LINUX; #ifdef IMAXBEL if (x & IMAXBEL) r |= IMAXBEL_LINUX; #endif #ifdef IUTF8 if (x & IUTF8) r |= IUTF8_LINUX; #endif #ifdef IUCLC if (x & IUCLC) r |= IUCLC_LINUX; #endif return r; } static int XlatTermiosOflag(int x) { int r = 0; if (x & OPOST_LINUX) r |= OPOST; #ifdef ONLCR if (x & ONLCR_LINUX) r |= ONLCR; #endif #ifdef OCRNL if (x & OCRNL_LINUX) r |= OCRNL; #endif #ifdef ONOCR if (x & ONOCR_LINUX) r |= ONOCR; #endif #ifdef ONLRET if (x & ONLRET_LINUX) r |= ONLRET; #endif #ifdef OFILL if (x & OFILL_LINUX) r |= OFILL; #endif #ifdef OFDEL if (x & OFDEL_LINUX) r |= OFDEL; #endif #ifdef NLDLY if ((x & NLDLY_LINUX) == NL0_LINUX) { r |= NL0; } else if ((x & NLDLY_LINUX) == NL1_LINUX) { r |= NL1; } #endif #ifdef CRDLY if ((x & CRDLY_LINUX) == CR0_LINUX) { r |= CR0; } else if ((x & CRDLY_LINUX) == CR1_LINUX) { r |= CR1; } else if ((x & CRDLY_LINUX) == CR2_LINUX) { r |= CR2; } else if ((x & CRDLY_LINUX) == CR3_LINUX) { r |= CR3; } #endif #ifdef TABDLY if ((x & TABDLY_LINUX) == TAB0_LINUX) { r |= TAB0; #ifdef TAB1 } else if ((x & TABDLY_LINUX) == TAB1_LINUX) { r |= TAB1; #endif #ifdef TAB1 } else if ((x & TABDLY_LINUX) == TAB2_LINUX) { r |= TAB2; #endif } else if ((x & TABDLY_LINUX) == TAB3_LINUX) { r |= TAB3; } #endif #ifdef BSDLY if ((x & BSDLY_LINUX) == BS0_LINUX) { r |= BS0; } else if ((x & BSDLY_LINUX) == BS1_LINUX) { r |= BS1; } #endif #ifdef VTBDLY if ((x & VTDLY_LINUX) == VT0_LINUX) { r |= VT0; } else if ((x & VTDLY_LINUX) == VT1_LINUX) { r |= VT1; } #endif #ifdef FFBDLY if ((x & FFDLY_LINUX) == FF0_LINUX) { r |= FF0; } else if ((x & FFDLY_LINUX) == FF1_LINUX) { r |= FF1; } #endif #ifdef OLCUC if (x & 0x0002) r |= OLCUC; #endif return r; } static int UnXlatTermiosOflag(int x) { int r = 0; if (x & OPOST) r |= OPOST_LINUX; #ifdef ONLCR if (x & ONLCR) r |= ONLCR_LINUX; #endif #ifdef OCRNL if (x & OCRNL) r |= OCRNL_LINUX; #endif #ifdef ONOCR if (x & ONOCR) r |= ONOCR_LINUX; #endif #ifdef ONLRET if (x & ONLRET) r |= ONLRET_LINUX; #endif #ifdef OFILL if (x & OFILL) r |= OFILL_LINUX; #endif #ifdef OFDEL if (x & OFDEL) r |= OFDEL_LINUX; #endif #ifdef NLDLY if ((x & NLDLY) == NL0) { r |= NL0_LINUX; } else if ((x & NLDLY) == NL1) { r |= NL1_LINUX; #ifdef NL2 } else if ((x & NLDLY) == NL2) { r |= 0x0000; // ??? #endif #ifdef NL3 } else if ((x & NLDLY) == NL3) { r |= 0x0000; // ??? #endif } #endif #ifdef CRDLY if ((x & CRDLY) == CR0) { r |= CR0_LINUX; } else if ((x & CRDLY) == CR1) { r |= CR1_LINUX; } else if ((x & CRDLY) == CR2) { r |= CR2_LINUX; } else if ((x & CRDLY) == CR3) { r |= CR3_LINUX; } #endif #ifdef TABDLY if ((x & TABDLY) == TAB0) { r |= TAB0_LINUX; #ifdef TAB1 } else if ((x & TABDLY) == TAB1) { r |= TAB1_LINUX; #endif #ifdef TAB2 } else if ((x & TABDLY) == TAB2) { r |= TAB2_LINUX; #endif } else if ((x & TABDLY) == TAB3) { r |= TAB3_LINUX; } #endif #ifdef BSDLY if ((x & BSDLY) == BS0) { r |= BS0_LINUX; } else if ((x & BSDLY) == BS1) { r |= BS1_LINUX; } #endif #ifdef VTDLY if ((x & VTDLY) == VT0) { r |= VT0_LINUX; } else if ((x & VTDLY) == VT1) { r |= VT1_LINUX; } #endif #ifdef FFDLY if ((x & FFDLY) == FF0) { r |= FF0_LINUX; } else if ((x & FFDLY) == FF1) { r |= FF1_LINUX; } #endif #ifdef OLCUC if (x & OLCUC) r |= OLCUC_LINUX; #endif return r; } static void XlatTermiosCc(struct termios *dst, const struct termios_linux *src) { dst->c_cc[VINTR] = src->cc[VINTR_LINUX]; dst->c_cc[VQUIT] = src->cc[VQUIT_LINUX]; dst->c_cc[VERASE] = src->cc[VERASE_LINUX]; dst->c_cc[VKILL] = src->cc[VKILL_LINUX]; dst->c_cc[VEOF] = src->cc[VEOF_LINUX]; dst->c_cc[VTIME] = src->cc[VTIME_LINUX]; dst->c_cc[VMIN] = src->cc[VMIN_LINUX]; dst->c_cc[VSTART] = src->cc[VSTART_LINUX]; dst->c_cc[VSTOP] = src->cc[VSTOP_LINUX]; dst->c_cc[VSUSP] = src->cc[VSUSP_LINUX]; dst->c_cc[VEOL] = src->cc[VEOL_LINUX]; #ifdef VSWTC dst->c_cc[VSWTC] = src->cc[VSWTC_LINUX]; #endif #ifdef VREPRINT dst->c_cc[VREPRINT] = src->cc[VREPRINT_LINUX]; #endif #ifdef VDISCARD dst->c_cc[VDISCARD] = src->cc[VDISCARD_LINUX]; #endif #ifdef VWERASE dst->c_cc[VWERASE] = src->cc[VWERASE_LINUX]; #endif #ifdef VLNEXT dst->c_cc[VLNEXT] = src->cc[VLNEXT_LINUX]; #endif #ifdef VEOL2 dst->c_cc[VEOL2] = src->cc[VEOL2_LINUX]; #endif } static void UnXlatTermiosCc(struct termios_linux *dst, const struct termios *src) { dst->cc[VINTR_LINUX] = src->c_cc[VINTR]; dst->cc[VQUIT_LINUX] = src->c_cc[VQUIT]; dst->cc[VERASE_LINUX] = src->c_cc[VERASE]; dst->cc[VKILL_LINUX] = src->c_cc[VKILL]; dst->cc[VEOF_LINUX] = src->c_cc[VEOF]; dst->cc[VTIME_LINUX] = src->c_cc[VTIME]; dst->cc[VMIN_LINUX] = src->c_cc[VMIN]; dst->cc[VSTART_LINUX] = src->c_cc[VSTART]; dst->cc[VSTOP_LINUX] = src->c_cc[VSTOP]; dst->cc[VSUSP_LINUX] = src->c_cc[VSUSP]; dst->cc[VEOL_LINUX] = src->c_cc[VEOL]; #ifdef VSWTC dst->cc[VSWTC_LINUX] = src->c_cc[VSWTC]; #endif #ifdef VREPRINT dst->cc[VREPRINT_LINUX] = src->c_cc[VREPRINT]; #endif #ifdef VDISCARD dst->cc[VDISCARD_LINUX] = src->c_cc[VDISCARD]; #endif #ifdef VWERASE dst->cc[VWERASE_LINUX] = src->c_cc[VWERASE]; #endif #ifdef VLNEXT dst->cc[VLNEXT_LINUX] = src->c_cc[VLNEXT]; #endif #ifdef VEOL2 dst->cc[VEOL2_LINUX] = src->c_cc[VEOL2]; #endif } void XlatLinuxToTermios(struct termios *dst, const struct termios_linux *src) { speed_t speed; memset(dst, 0, sizeof(*dst)); dst->c_iflag = XlatTermiosIflag(Read32(src->iflag)); dst->c_oflag = XlatTermiosOflag(Read32(src->oflag)); dst->c_cflag = XlatTermiosCflag(Read32(src->cflag)); dst->c_lflag = XlatTermiosLflag(Read32(src->lflag)); switch (Read32(src->cflag) & CBAUD_LINUX) { case B0_LINUX: speed = B0; break; case B50_LINUX: speed = B50; break; case B75_LINUX: speed = B75; break; case B110_LINUX: speed = B110; break; case B134_LINUX: speed = B134; break; case B150_LINUX: speed = B150; break; case B200_LINUX: speed = B200; break; case B300_LINUX: speed = B300; break; case B600_LINUX: speed = B600; break; case B1200_LINUX: speed = B1200; break; case B1800_LINUX: speed = B1800; break; case B2400_LINUX: speed = B2400; break; case B4800_LINUX: speed = B4800; break; case B9600_LINUX: speed = B9600; break; case B19200_LINUX: speed = B19200; break; case B38400_LINUX: speed = B38400; break; #ifdef B57600 case B57600_LINUX: speed = B57600; break; #endif #ifdef B115200 case B115200_LINUX: speed = B115200; break; #endif #ifdef B230400 case B230400_LINUX: speed = B230400; break; #endif #ifdef B460800 case B460800_LINUX: speed = B460800; break; #endif #ifdef B500000 case B500000_LINUX: speed = B500000; break; #endif #ifdef B576000 case B576000_LINUX: speed = B576000; break; #endif #ifdef B921600 case B921600_LINUX: speed = B921600; break; #endif #ifdef B1000000 case B1000000_LINUX: speed = B1000000; break; #endif #ifdef B1152000 case B1152000_LINUX: speed = B1152000; break; #endif #ifdef B1500000 case B1500000_LINUX: speed = B1500000; break; #endif #ifdef B2000000 case B2000000_LINUX: speed = B2000000; break; #endif #ifdef B2500000 case B2500000_LINUX: speed = B2500000; break; #endif #ifdef B3000000 case B3000000_LINUX: speed = B3000000; break; #endif #ifdef B3500000 case B3500000_LINUX: speed = B3500000; break; #endif #ifdef B4000000 case B4000000_LINUX: speed = B4000000; break; #endif default: LOGF("unknown baud rate: %#x", Read32(src->cflag) & CBAUD_LINUX); speed = B38400; break; } cfsetispeed(dst, speed); cfsetospeed(dst, speed); XlatTermiosCc(dst, src); } void XlatTermiosToLinux(struct termios_linux *dst, const struct termios *src) { int speed; speed_t srcspeed; memset(dst, 0, sizeof(*dst)); Write32(dst->iflag, UnXlatTermiosIflag(src->c_iflag)); Write32(dst->oflag, UnXlatTermiosOflag(src->c_oflag)); Write32(dst->cflag, UnXlatTermiosCflag(src->c_cflag)); Write32(dst->lflag, UnXlatTermiosLflag(src->c_lflag)); if ((srcspeed = cfgetospeed(src)) != (speed_t)-1) { if (srcspeed == B0) { speed = B0_LINUX; } else if (srcspeed == B50) { speed = B50_LINUX; } else if (srcspeed == B75) { speed = B75_LINUX; } else if (srcspeed == B110) { speed = B110_LINUX; } else if (srcspeed == B134) { speed = B134_LINUX; } else if (srcspeed == B150) { speed = B150_LINUX; } else if (srcspeed == B200) { speed = B200_LINUX; } else if (srcspeed == B300) { speed = B300_LINUX; } else if (srcspeed == B600) { speed = B600_LINUX; } else if (srcspeed == B1200) { speed = B1200_LINUX; } else if (srcspeed == B1800) { speed = B1800_LINUX; } else if (srcspeed == B2400) { speed = B2400_LINUX; } else if (srcspeed == B4800) { speed = B4800_LINUX; } else if (srcspeed == B9600) { speed = B9600_LINUX; } else if (srcspeed == B19200) { speed = B19200_LINUX; } else if (srcspeed == B38400) { speed = B38400_LINUX; #ifdef B57600 } else if (srcspeed == B57600) { speed = B57600_LINUX; #endif #ifdef B115200 } else if (srcspeed == B115200) { speed = B115200_LINUX; #endif #ifdef B230400 } else if (srcspeed == B230400) { speed = B230400_LINUX; #endif #ifdef B460800 } else if (srcspeed == B460800) { speed = B460800_LINUX; #endif #ifdef B500000 } else if (srcspeed == B500000) { speed = B500000_LINUX; #endif #ifdef B576000 } else if (srcspeed == B576000) { speed = B576000_LINUX; #endif #ifdef B921600 } else if (srcspeed == B921600) { speed = B921600_LINUX; #endif #ifdef B1000000 } else if (srcspeed == B1000000) { speed = B1000000_LINUX; #endif #ifdef B1152000 } else if (srcspeed == B1152000) { speed = B1152000_LINUX; #endif #ifdef B1500000 } else if (srcspeed == B1500000) { speed = B1500000_LINUX; #endif #ifdef B2000000 } else if (srcspeed == B2000000) { speed = B2000000_LINUX; #endif #ifdef B2500000 } else if (srcspeed == B2500000) { speed = B2500000_LINUX; #endif #ifdef B3000000 } else if (srcspeed == B3000000) { speed = B3000000_LINUX; #endif #ifdef B3500000 } else if (srcspeed == B3500000) { speed = B3500000_LINUX; #endif #ifdef B4000000 } else if (srcspeed == B4000000) { speed = B4000000_LINUX; #endif } else { LOGF("unrecognized baud rate: %ld", (long)srcspeed); speed = B38400; } } else { LOGF("failed to get baud rate: %s", DescribeHostErrno(errno)); speed = B38400; } Write32(dst->cflag, (Read32(dst->cflag) & ~CBAUD_LINUX) | speed); UnXlatTermiosCc(dst, src); } int XlatWhence(int x) { switch (x) { XLAT(SEEK_SET_LINUX, SEEK_SET); XLAT(SEEK_CUR_LINUX, SEEK_CUR); XLAT(SEEK_END_LINUX, SEEK_END); default: LOGF("unrecognized whence: %d", x); return einval(); } } ================================================ FILE: blink/xlat.h ================================================ #ifndef BLINK_XLAT_H_ #define BLINK_XLAT_H_ #include #include #include #include #include #include #include #include #include #include "blink/linux.h" int UnXlatSiCode(int, int); int UnXlatOpenFlags(int); int UnXlatAccMode(int); int UnXlatSignal(int); int UnXlatItimer(int); int XlatAccess(int); int XlatClock(int, clock_t *); int XlatErrno(int); int XlatOpenFlags(int); int XlatAccMode(int); int XlatResource(int); int XlatRusage(int); int XlatShutdown(int); int XlatSignal(int); int XlatSocketFamily(int); int XlatSocketLevel(int, int *); int XlatSocketOptname(int, int); int XlatSocketProtocol(int); int XlatSocketType(int); int XlatWait(int); int XlatWhence(int); int XlatSockaddrToHost(struct sockaddr_storage *, const struct sockaddr_linux *, u32); int XlatSockaddrToLinux(struct sockaddr_storage_linux *, const struct sockaddr *, socklen_t); void XlatStatToLinux(struct stat_linux *, const struct stat *); void XlatRusageToLinux(struct rusage_linux *, const struct rusage *); void XlatItimervalToLinux(struct itimerval_linux *, const struct itimerval *); void XlatLinuxToItimerval(struct itimerval *, const struct itimerval_linux *); void XlatLinuxToTermios(struct termios *, const struct termios_linux *); void XlatTermiosToLinux(struct termios_linux *, const struct termios *); void XlatWinsizeToLinux(struct winsize_linux *, const struct winsize *); void XlatWinsizeToHost(struct winsize *, const struct winsize_linux *); void XlatSigsetToLinux(u8[8], const sigset_t *); void XlatLinuxToSigset(sigset_t *, u64); void XlatRlimitToLinux(struct rlimit_linux *, const struct rlimit *); void XlatLinuxToRlimit(int, struct rlimit *, const struct rlimit_linux *); #endif /* BLINK_XLAT_H_ */ ================================================ FILE: blink/xmm.h ================================================ #ifndef BLINK_XMM_H_ #define BLINK_XMM_H_ #include "blink/builtin.h" #include "blink/types.h" #ifdef __CYGWIN__ #define XMM_TYPE void #define RETURN_XMM(ax, dx) asm volatile("" : : "a"(ax), "d"(dx)) #else struct Xmm { u64 lo; u64 hi; }; #define XMM_TYPE struct Xmm #define RETURN_XMM(ax, dx) \ return (struct Xmm) { \ ax, dx \ } #endif #endif /* BLINK_XMM_H_ */ ================================================ FILE: blink/xmmtype.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/xmmtype.h" #include "blink/rde.h" static void UpdateXmmTypes(u64 rde, struct XmmType *xt, int regtype, int rmtype) { xt->type[RexrReg(rde)] = regtype; if (IsModrmRegister(rde)) { xt->type[RexbRm(rde)] = rmtype; } } static void UpdateXmmSizes(u64 rde, struct XmmType *xt, int regsize, int rmsize) { xt->size[RexrReg(rde)] = regsize; if (IsModrmRegister(rde)) { xt->size[RexbRm(rde)] = rmsize; } } void UpdateXmmType(u64 rde, struct XmmType *xt) { switch (Mopcode(rde)) { case 0x110: case 0x111: /* MOVSS,MOVSD */ if (Rep(rde) == 3) { UpdateXmmTypes(rde, xt, kXmmFloat, kXmmFloat); } else if (Rep(rde) == 2) { UpdateXmmTypes(rde, xt, kXmmDouble, kXmmDouble); } break; case 0x12E: /* UCOMIS */ case 0x12F: /* COMIS */ case 0x151: /* SQRT */ case 0x152: /* RSQRT */ case 0x153: /* RCP */ case 0x158: /* ADD */ case 0x159: /* MUL */ case 0x15C: /* SUB */ case 0x15D: /* MIN */ case 0x15E: /* DIV */ case 0x15F: /* MAX */ case 0x1C2: /* CMP */ if (Osz(rde) || Rep(rde) == 2) { UpdateXmmTypes(rde, xt, kXmmDouble, kXmmDouble); } else { UpdateXmmTypes(rde, xt, kXmmFloat, kXmmFloat); } break; case 0x12A: /* CVTPI2PS,CVTSI2SS,CVTPI2PD,CVTSI2SD */ if (Osz(rde) || Rep(rde) == 2) { UpdateXmmSizes(rde, xt, 8, 4); UpdateXmmTypes(rde, xt, kXmmDouble, kXmmIntegral); } else { UpdateXmmSizes(rde, xt, 4, 4); UpdateXmmTypes(rde, xt, kXmmFloat, kXmmIntegral); } break; case 0x15A: /* CVT{P,S}{S,D}2{P,S}{S,D} */ if (Osz(rde) || Rep(rde) == 2) { UpdateXmmTypes(rde, xt, kXmmFloat, kXmmDouble); } else { UpdateXmmTypes(rde, xt, kXmmDouble, kXmmFloat); } break; case 0x15B: /* CVT{,T}{DQ,PS}2{PS,DQ} */ UpdateXmmSizes(rde, xt, 4, 4); if (Osz(rde) || Rep(rde) == 3) { UpdateXmmTypes(rde, xt, kXmmIntegral, kXmmFloat); } else { UpdateXmmTypes(rde, xt, kXmmFloat, kXmmIntegral); } break; case 0x17C: /* HADD */ case 0x17D: /* HSUB */ case 0x1D0: /* ADDSUB */ if (Osz(rde)) { UpdateXmmTypes(rde, xt, kXmmDouble, kXmmDouble); } else { UpdateXmmTypes(rde, xt, kXmmFloat, kXmmFloat); } break; case 0x164: /* PCMPGTB */ case 0x174: /* PCMPEQB */ case 0x1D8: /* PSUBUSB */ case 0x1DA: /* PMINUB */ case 0x1DC: /* PADDUSB */ case 0x1DE: /* PMAXUB */ case 0x1E0: /* PAVGB */ case 0x1E8: /* PSUBSB */ case 0x1EC: /* PADDSB */ case 0x1F8: /* PSUBB */ case 0x1FC: /* PADDB */ UpdateXmmSizes(rde, xt, 1, 1); UpdateXmmTypes(rde, xt, kXmmIntegral, kXmmIntegral); break; case 0x165: /* PCMPGTW */ case 0x175: /* PCMPEQW */ case 0x171: /* PSRLW,PSRAW,PSLLW */ case 0x1D1: /* PSRLW */ case 0x1D5: /* PMULLW */ case 0x1D9: /* PSUBUSW */ case 0x1DD: /* PADDUSW */ case 0x1E1: /* PSRAW */ case 0x1E3: /* PAVGW */ case 0x1E4: /* PMULHUW */ case 0x1E5: /* PMULHW */ case 0x1E9: /* PSUBSW */ case 0x1EA: /* PMINSW */ case 0x1ED: /* PADDSW */ case 0x1EE: /* PMAXSW */ case 0x1F1: /* PSLLW */ case 0x1F6: /* PSADBW */ case 0x1F9: /* PSUBW */ case 0x1FD: /* PADDW */ UpdateXmmSizes(rde, xt, 2, 2); UpdateXmmTypes(rde, xt, kXmmIntegral, kXmmIntegral); break; case 0x166: /* PCMPGTD */ case 0x176: /* PCMPEQD */ case 0x172: /* PSRLD,PSRAD,PSLLD */ case 0x1D2: /* PSRLD */ case 0x1E2: /* PSRAD */ case 0x1F2: /* PSLLD */ case 0x1FA: /* PSUBD */ case 0x1FE: /* PADDD */ UpdateXmmSizes(rde, xt, 4, 4); UpdateXmmTypes(rde, xt, kXmmIntegral, kXmmIntegral); break; case 0x173: /* PSRLQ,PSRLQ,PSRLDQ,PSLLQ,PSLLDQ */ case 0x1D3: /* PSRLQ */ case 0x1D4: /* PADDQ */ case 0x1F3: /* PSLLQ */ case 0x1F4: /* PMULUDQ */ case 0x1FB: /* PSUBQ */ UpdateXmmSizes(rde, xt, 8, 8); UpdateXmmTypes(rde, xt, kXmmIntegral, kXmmIntegral); break; case 0x16B: /* PACKSSDW */ case 0x1F5: /* PMADDWD */ UpdateXmmSizes(rde, xt, 4, 2); UpdateXmmTypes(rde, xt, kXmmIntegral, kXmmIntegral); break; case 0x163: /* PACKSSWB */ case 0x167: /* PACKUSWB */ UpdateXmmSizes(rde, xt, 1, 2); UpdateXmmTypes(rde, xt, kXmmIntegral, kXmmIntegral); break; case 0x128: /* MOVAPS Vps Wps */ if (IsModrmRegister(rde)) { xt->type[RexrReg(rde)] = xt->type[RexbRm(rde)]; xt->size[RexrReg(rde)] = xt->size[RexbRm(rde)]; } break; case 0x129: /* MOVAPS Wps Vps */ if (IsModrmRegister(rde)) { xt->type[RexbRm(rde)] = xt->type[RexrReg(rde)]; xt->size[RexbRm(rde)] = xt->size[RexrReg(rde)]; } break; case 0x16F: /* MOVDQA Vdq Wdq */ if (Osz(rde) && IsModrmRegister(rde)) { xt->type[RexrReg(rde)] = xt->type[RexbRm(rde)]; xt->size[RexrReg(rde)] = xt->size[RexbRm(rde)]; } break; default: return; } } ================================================ FILE: blink/xmmtype.h ================================================ #ifndef BLINK_XMMTYPE_H_ #define BLINK_XMMTYPE_H_ #include "blink/machine.h" #define kXmmIntegral 0 #define kXmmDouble 1 #define kXmmFloat 2 struct XmmType { u8 type[16]; u8 size[16]; }; void UpdateXmmType(u64, struct XmmType *); #endif /* BLINK_XMMTYPE_H_ */ ================================================ FILE: blink/xnu.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/machine.h" // @asyncsignalsafe int FixXnuSignal(struct Machine *m, int sig, siginfo_t *si) { u64 pte; // The fruit platform will raise SIGBUS on writes to anon mappings // which don't have the PROT_WRITE protection, even when aligned!! // We only create this kind of memory for getting notifications if // RWX memory is modified. The XNU codebase implements a hack that // prevents this from happening for stack memory, but for anything // else we're on our own. if (HasLinearMapping() && sig == SIGBUS && si->si_code == BUS_ADRALN) { ConvertHostToGuestAddress(m->system, si->si_addr, &pte); // check that fault address mapped to an actual guest address, and // that either (1) the page doesn't have read+write permission, or // (2) it's an RWX page and therefore likely to be sneak protected if ((pte & PAGE_V) && ((pte & (PAGE_U | PAGE_RW)) != (PAGE_U | PAGE_RW) || (pte & (PAGE_U | PAGE_RW | PAGE_XD)) == (PAGE_U | PAGE_RW))) { // we're now quite certain this is actually a segmentation fault sig = SIGSEGV; si->si_signo = SIGSEGV; si->si_code = SEGV_ACCERR; } } return sig; } ================================================ FILE: build/config.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ TAGS ?= /usr/bin/ctags IMAGE_BASE_VIRTUAL = 0x23000000 ifeq ($(HOST_SYSTEM), Haiku) CFLAGS += -fpic endif CPPFLAGS += -iquote. ifeq ($(HOST_SYSTEM), Haiku) LDLIBS += -lroot -lnetwork -lbsd endif ifeq ($(HOST_OS), Cygwin) LDLIBS += -lntdll endif ifeq ($(HOST_SYSTEM), OpenBSD) CFLAGS += -gdwarf-2 endif # FreeBSD loads executables to 0x200000 by default which is likely to # overlap the static Linux guest binary, we usually load to 0x400000. ifeq ($(HOST_SYSTEM), FreeBSD) LDFLAGS += -Wl,--image-base=$(IMAGE_BASE_VIRTUAL) endif # Tune the build when using our prebuilt musl-cross-make toolchains. CPPFLAGS_STATIC = \ -DMUSL_CROSS_MAKE LDFLAGS_STATIC = \ -static \ -fno-exceptions \ -fno-unwind-tables \ -fno-asynchronous-unwind-tables \ -Wl,-z,max-page-size=4096 \ -Wl,-z,common-page-size=4096 \ -Wl,-z,norelro \ -Wl,-Ttext-segment=$(IMAGE_BASE_VIRTUAL) TAGSFLAGS = \ -e \ -a \ --if0=no \ --langmap=c:.c.h.i \ --line-directives=yes # some distros like alpine have a file /usr/include/fortify/string.h # which wraps functions like memcpy() with inline branch traps which # check for things like overlapping parameters and buffer overrun in # situations where the array size is known. memcpy() is important in # avoiding aliasing memory and proving no aliases exist so that code # goes faster and is more portable. for example, here we use it when # moving values to/from the cpu register file therefore the size and # boundaries are always known, and as such, fortification needlessly # causes an explosive growth in object code size in files like sse.c CFLAGS += -U_FORTIFY_SOURCE # ifeq ($(USER), jart) # CFLAGS := -Wall -Werror $(CFLAGS) # endif ifeq ($(MODE), zero) CFLAGS += -O0 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer endif ifeq ($(MODE), dbg) CFLAGS += -O0 -g -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer CPPFLAGS += -DDEBUG endif ifeq ($(MODE), rel) CPPFLAGS += -DNDEBUG CFLAGS += -O2 -mtune=generic -fno-align-functions -fno-align-jumps -fno-align-labels -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables endif ifeq ($(MODE), rel-llvm) CC = clang CPPFLAGS += -DNDEBUG CFLAGS += -O2 -mtune=generic endif ifeq ($(MODE), tiny) CPPFLAGS += -DNDEBUG -DTINY CFLAGS += -Os -fomit-frame-pointer -mtune=generic -fno-align-functions -fno-align-jumps -fno-align-labels -fno-align-loops -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables LDFLAGS += #-Wl,--cref,-Map=$@.map endif ifeq ($(MODE), tiny-llvm) CC = clang CPPFLAGS += -DNDEBUG -DTINY CFLAGS += -Oz endif ifeq ($(MODE), opt) CPPFLAGS += -DNDEBUG CFLAGS += -O3 -march=native endif ifeq ($(MODE), opt-llvm) CC = clang CPPFLAGS += -DNDEBUG CFLAGS += -O2 TARGET_ARCH = -march=native endif # ./configure MODE=prof # make -j8 # o/prof/blink/blink third_party/cosmo/2/mu_test.com # gprof o/prof/blink/blink gmon.out | less ifeq ($(MODE), prof) CFLAGS += -pg -O0 LDFLAGS += -pg -O0 endif # make m=cov check # gcov -ukqjo o/cov/blink blink/*.c # less alu.c.gcov ifeq ($(MODE), cov) CPPFLAGS += -DNOJIT CFLAGS += -fprofile-arcs -ftest-coverage LDFLAGS += -fprofile-arcs -ftest-coverage endif ifeq ($(MODE), asan) CFLAGS += -O0 CPPFLAGS += -DDEBUG CPPFLAGS += -fsanitize=address LDLIBS += -fsanitize=address endif ifeq ($(MODE), ubsan) CPPFLAGS += -DDEBUG -DNOJIT -DUBSAN CFLAGS += -Werror -Wno-unused-parameter -Wno-missing-field-initializers CFLAGS += -fsanitize=undefined LDLIBS += -fsanitize=undefined endif ifeq ($(MODE), tsan) CC = clang++ CPPFLAGS += -DTSAN CFLAGS += -xc++ -Werror -Wno-unused-parameter -Wno-missing-field-initializers CFLAGS += -fsanitize=thread LDLIBS += -fsanitize=thread endif ifeq ($(MODE), msan) CC = clang CPPFLAGS += -DDEBUG CFLAGS += -Werror -Wno-unused-parameter -Wno-missing-field-initializers CFLAGS += -fsanitize=memory LDLIBS += -fsanitize=memory endif ifeq ($(MODE), llvm) CC = clang CPPFLAGS += -DDEBUG CFLAGS += -Werror -Wno-unused-parameter -Wno-unused-function -Wno-missing-field-initializers LDFLAGS += --rtlib=compiler-rt endif ifeq ($(MODE), llvm++) CC = clang++ CPPFLAGS += -DDEBUG CFLAGS += -xc++ -Werror -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers LDFLAGS += --rtlib=compiler-rt endif ================================================ FILE: build/htags ================================================ #!/bin/sh #-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ #── vi: set et ft=sh ts=2 sts=2 fenc=utf-8 :vi ─────────────┘ # # OVERVIEW # # Header Symbol Index Generator # # DESCRIPTION # # This is a static source analyzer that lets us configure Emacs # keybindings to insert #include lines. # # EXAMPLES # # build/htags -o HTAGS $(find . -name \*.h) # # (defun jart-add-include () # (interactive) # (let* ((tag-file "HTAGS") # (case-fold-search nil) # (search (thing-at-point 'symbol)) # (buffer (find-file-noselect (format "%s/%s" # (locate-dominating-file # (buffer-name) tag-file) # tag-file))) # (header (with-current-buffer buffer # (save-excursion # (goto-char 0) # (when (re-search-forward # (concat "\177" search "\001") nil t) # (when (re-search-backward "\f\n\\([^,]*\\)," nil t) # (match-string 1))))))) # (when header # (save-excursion # (goto-char 0) # (re-search-forward "#include") # (re-search-forward "^$") # (insert (concat "#include \"" header "\"\n")))))) # (defun jart-c-mode-common-hook () # (define-key c-mode-base-map (kbd "C-c C-h") 'jart-add-include)) # (eval-after-load 'markdown-mode # '(progn # (add-hook 'c-mode-common-hook 'jart-c-mode-common-hook))) # ctags doesn't understand atomics, e.g. # extern char **environ; set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@" # ctags doesn't understand variable prototypes, e.g. # extern char **environ; set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@" # ctags doesn't understand function prototypes, e.g. # bool isheap(void *p) dontthrow nocallback; set -- --regex-c='/^[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)(.*/\2/b' "$@" # ctags doesn't understand function pointers, e.g. # extern int32_t (*const SetEvent)(int64_t hEvent) wincall; set -- --regex-c='/^extern [^(]*(\*const \([^)]*\))(/\1/b' "$@" # ctags doesn't understand forward declarations, e.g. # struct WorstSoftwareEver; set -- --regex-c='/^struct.*;$/uehocruehcroue/b' "$@" exec ${TAGS:-ctags} \ -e \ --langmap=c:.c.h \ --exclude=libc/nt/struct/imagefileheader.internal.h \ --exclude=libc/nt/struct/imageseparatedebugheader.internal.h \ --exclude=libc/nt/struct/importobjectheader.h \ --exclude=libc/nt/struct/nonpageddebuginfo.h \ --exclude=libc/nt/struct/ansistring.h \ --exclude=libc/nt/struct/filesegmentelement.h \ "$@" ================================================ FILE: build/objdump ================================================ #!/bin/sh exec objdump "$@" ================================================ FILE: build/rules.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ o/$(MODE)/%.o: %.s @mkdir -p $(@D) $(AS) -o $@ $< o/$(MODE)/%.o: %.S @mkdir -p $(@D) $(CC) $(CPPFLAGS) -c -o $@ $< o/$(MODE)/%.o: %.c @mkdir -p $(@D) $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/%.h.ok: %.h @mkdir -p $(@D) $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -x c -g0 -o $@ $< o/$(MODE)/%.a: rm -f $@ $(AR) rcs $@ $^ o/$(MODE)/i486/%.a: rm -f $@ $(VM) o/third_party/gcc/i486/bin/i486-linux-musl-ar rcsD $@ $^ o/$(MODE)/m68k/%.a: rm -f $@ $(VM) o/third_party/gcc/m68k/bin/m68k-linux-musl-ar rcsD $@ $^ o/$(MODE)/x86_64/%.a: rm -f $@ $(VM) o/third_party/gcc/x86_64/bin/x86_64-linux-musl-ar rcsD $@ $^ o/$(MODE)/x86_64-gcc49/%.a: rm -f $@ $(VM) o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-ar rcsD $@ $^ o/$(MODE)/arm/%.a: rm -f $@ $(VM) o/third_party/gcc/arm/bin/arm-linux-musleabi-ar rcsD $@ $^ o/$(MODE)/aarch64/%.a: rm -f $@ $(VM) o/third_party/gcc/aarch64/bin/aarch64-linux-musl-ar rcsD $@ $^ o/$(MODE)/riscv64/%.a: rm -f $@ $(VM) o/third_party/gcc/riscv64/bin/riscv64-linux-musl-ar rcsD $@ $^ o/$(MODE)/mips/%.a: rm -f $@ $(VM) o/third_party/gcc/mips/bin/mips-linux-musl-ar rcsD $@ $^ o/$(MODE)/mipsel/%.a: rm -f $@ $(VM) o/third_party/gcc/mipsel/bin/mipsel-linux-musl-ar rcsD $@ $^ o/$(MODE)/mips64/%.a: rm -f $@ $(VM) o/third_party/gcc/mips64/bin/mips64-linux-musl-ar rcsD $@ $^ o/$(MODE)/mips64el/%.a: rm -f $@ $(VM) o/third_party/gcc/mips64el/bin/mips64el-linux-musl-ar rcsD $@ $^ o/$(MODE)/s390x/%.a: rm -f $@ $(VM) o/third_party/gcc/s390x/bin/s390x-linux-musl-ar rcsD $@ $^ o/$(MODE)/microblaze/%.a: rm -f $@ $(VM) o/third_party/gcc/microblaze/bin/microblaze-linux-musl-ar rcsD $@ $^ o/$(MODE)/powerpc/%.a: rm -f $@ $(VM) o/third_party/gcc/powerpc/bin/powerpc-linux-musl-ar rcsD $@ $^ o/$(MODE)/powerpc64le/%.a: rm -f $@ $(VM) o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-ar rcsD $@ $^ o/$(MODE)/%-gcc.asm: %.c @mkdir -p $(@D) $(CC) $(CFLAGS) -fno-stack-protector -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -iquote. $(CPPFLAGS) $(TARGET_ARCH) -S -g0 $(OUTPUT_OPTION) $< o/$(MODE)/%-clang.asm: %.c @mkdir -p $(@D) $(CC) $(CFLAGS) -fno-stack-protector -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -iquote. $(CPPFLAGS) $(TARGET_ARCH) -S -g0 $(OUTPUT_OPTION) $< ================================================ FILE: config.h.in ================================================ #ifndef BLINK_CONFIG_H_ #define BLINK_CONFIG_H_ // #define DISABLE_JIT // #define DISABLE_X87 // #define DISABLE_THREADS // #define DISABLE_SOCKETS // #define DISABLE_OVERLAYS #define DISABLE_VFS // #define DISABLE_NONPOSIX // #define DISABLE_ANCILLARY // #define DISABLE_DISASSEMBLER // #define DISABLE_BACKTRACE // #define DISABLE_STRACE // #define DISABLE_METAL // #define DISABLE_MMX // #define DISABLE_BCD // #define DISABLE_ROM // #define DISABLE_BMI2 // #define HAVE_FORK // #define HAVE_SYNC // #define HAVE_DUP3 // #define HAVE_PIPE2 // #define HAVE_WAIT4 // #define HAVE_SYSCTL // #define HAVE_INT128 // #define HAVE_SA_LEN // #define HAVE_PREADV // #define HAVE_MKFIFO // #define HAVE_WCWIDTH // #define HAVE_SYSINFO // #define HAVE_FEXECVE // #define HAVE_SCHED_H // #define HAVE_MEMCCPY // #define HAVE_SEEKDIR // #define HAVE_MKFIFOAT // #define HAVE_REALPATH // #define HAVE_SETREUID // #define HAVE_FDATASYNC // #define HAVE_STRCHRNUL // #define HAVE_VASPRINTF // #define HAVE_SETRESUID // #define HAVE_KERN_ARND // #define HAVE_GETRANDOM // #define HAVE_SETGROUPS // #define HAVE_LIBUNWIND // #define HAVE_GETENTROPY // #define HAVE_MAP_SHARED // #define HAVE_SENDTO_ZERO // #define HAVE_SIOCGIFCONF // #define HAVE_F_GETOWN_EX // #define HAVE_DEV_URANDOM // #define HAVE_SCHED_YIELD // #define HAVE_RTLGENRANDOM // #define HAVE_EPOLL_PWAIT1 // #define HAVE_EPOLL_PWAIT2 // #define HAVE_GETDOMAINNAME // #define HAVE_MAP_ANONYMOUS // #define HAVE_CLOCK_SETTIME // #define HAVE_SYS_GETRANDOM // #define HAVE_SYS_GETENTROPY // #define HAVE_SCM_CREDENTIALS // #define HAVE_STRUCT_TIMEZONE // #define HAVE_SCHED_GETAFFINITY // #define HAVE_PTHREAD_PROCESS_SHARED // #define HAVE_SYS_MOUNT_H // #define HAVE_PTHREAD_SETCANCELSTATE // #define HAVE_SOCKATMARK #endif /* BLINK_CONFIG_H_ */ ================================================ FILE: configure ================================================ #!/bin/sh # Blinkenlights Configuration Script # Run ./configure --help for usage CONFIG_COMMAND="$0 $*" # Evaluate FOO=bar environment variables passed as arguments (carefully # ignoring --foo=bar flags) and then remove MODE=foo from the arguments cleared= for x; do test "$cleared" || set -- ; cleared=1 if [ x"${x%%=*}" != x"$x" ] && [ x"${x#--}" = x"$x" ]; then eval "${x%%=*}='${x#*=}'" fi if [ x"${x%%=*}" != x"MODE" ]; then set -- "$@" "$x" fi done CC="${CC:-cc}" AR="${AR:-ar}" PREFIX="/usr/local" MODE="${MODE:-${m}}" TMPDIR="${TMPDIR:-o/tmp}" CFLAGS="${CFLAGS:--g -O2}" UOPFLAGS="${UOPFLAGS:--O2}" CPPFLAGS="${CPPFLAGS:--D_FILE_OFFSET_BITS=64 -D_DARWIN_C_SOURCE -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE}" HOST_ARCH=$(uname -m) HOST_SYSTEM=$(uname -s) HOST_OS=$(uname -o 2>/dev/null) if [ "${HOST_ARCH}" = "amd64" ] || [ "${HOST_ARCH}" = "x86_64" ] || [ "${HOST_ARCH}" = "arm64" ] || [ "${HOST_ARCH}" = "aarch64" ]; then JIT_POSSIBLE=1 else JIT_POSSIBLE= fi if [ "$1" = "--help" ]; then echo "usage: ./configure [OPTION]... [VARIABLE=VAL]..." echo echo "options" echo echo " --help" echo " shows this help" echo echo " --static" echo " compile blink as a statically-linked binary" echo echo " --prefix=PATH" echo " configures system install path (defaults to /usr/local)" echo echo " --enable-vfs" echo " enables true filesystem emulation support (overlays alternative)" echo echo " --disable-jit" echo " forces jit compilation to be disabled (shaves ~26kb off MODE=tiny)" echo echo " --disable-x87" echo " disables x87 fpu and long double support (shaves ~23kb off MODE=tiny)" echo echo " --disable-threads" echo " disables clone() and removes locks / barriers (shaves ~12kb off MODE=tiny)" echo echo " --disable-sockets" echo " disables socket() and related system calls (shaves ~5kb off MODE=tiny)" echo if [ "${MODE%%-*}" != "tiny" ] && [ "${MODE%%-*}" != "rel" ] && [ "${MODE%%-*}" != "opt" ]; then echo " --disable-disassembler" echo " disables printing disassembled opcodes on crash (shaves ~48kb off MODE='')" echo echo " --disable-strace" echo " disables system call logging functionality (shaves ~40kb off MODE='')" echo echo " --disable-backtrace" echo " disables printing guest backtrace on crash (shaves ~5kb off MODE='')" echo fi echo " --disable-metal" echo " disables i8086, i386, and ring-0 instructions (shaves ~3kb off MODE=tiny)" echo echo " --disable-mmx" echo " disables rarely used intel mmx legacy instructions (shaves ~3kb off MODE=tiny)" echo echo " --disable-fork" echo " disables fork() and interprocess communication (shaves ~3kb off MODE=tiny)" echo echo " --disable-overlays" echo " disables filesystem overlays and chroot() support (shaves ~3kb off MODE=tiny)" echo echo " --disable-nonposix" echo " disables linux apis that aren't part of posix (shaves ~6kb off MODE=tiny)" echo " intended for testing compliance of guest programs" echo echo " --disable-bmi2" echo " disables bmi2 and adx instruction sets (shaves ~3kb off MODE=tiny)" echo echo " --disable-ancillary" echo " disables sendmsg/recvmsg control data support (shaves ~2kb off MODE=tiny)" echo echo " --disable-bcd" echo " disables i8086 binary coded decimal support (shaves ~1kb off MODE=tiny)" echo echo " --disable-rom" echo " disables write protection of metal bios (shaves ~600 bytes off MODE=tiny)" echo echo " --disable-all" echo " disable all optional features (shaves ~81kb off MODE=tiny)" echo " you may use --enable-FOO to turn features back on" echo echo " --posix" echo " strictly conform to POSIX.1-2008 XSI and C11 standards (clobbers \$CPPFLAGS)" echo " linux-specific apis are still provided by blink when they can be polyfilled" echo " intended for testing compliance of blink's codebase" echo echo "variables" echo echo " MODE" echo " tunes makefile by choosing a preset configuration. defaults" echo " to empty string which is recommended. may alternatively be" echo " set to: tiny, opt, rel, dbg, cosmo, prof, cov, asan, ubsan," echo " tsan, msan, llvm, llvm++, rel-llvm, or tiny-llvm." echo echo " CC" echo " used to compile and link code [currently: $CC]" echo echo " CFLAGS" echo " shall be passed to \$CC when compiling c sources [currently: $CFLAGS]" echo echo " CPPFLAGS" echo " shall be passed to \$CC when using the c preprocessor [currently: $CPPFLAGS]" echo echo " LDFLAGS" echo " shall be passed to \$CC when linking binaries [currently: $LDFLAGS]" echo echo " TARGET_ARCH" echo " shall be passed to \$CC when compiling objects [currently: $TARGET_ARCH]" echo echo " LOADLIBES" echo " may supply additional libraries to link earlier [currently: $LOADLIBES]" echo echo " LDLIBS" echo " may supply additional libraries to link [currently: $LDLIBS]" echo echo " TMPDIR" echo " used to store temporary files [currently: $TMPDIR]" echo echo " AR" echo " used to create static archives [currently: $AR]" echo exit 0 fi if ! [ -f blink/blink.c ]; then echo "error: not in blink project root directory" >&2 echo "please change the current directory" >&2 exit 1 fi # POSIX compliant realpath solution for Darwin # https://stackoverflow.com/a/18443300/1653720 realpath() ( OURPWD=$PWD cd "$(dirname "$1")" LINK=$(readlink "$(basename "$1")") while [ "$LINK" ]; do cd "$(dirname "$LINK")" LINK=$(readlink "$(basename "$1")") done REALPATH="$PWD/$(basename "$1")" cd "$OURPWD" echo "$REALPATH" ) mkdir -p "${TMPDIR}" || exit mkdir -p o/tool/config || exit export TMPDIR=$(realpath "$TMPDIR") printf "checking for flock... " >&2 if command -v flock >/dev/null; then echo yes >&2 FLOCK=flock elif [ -x o/tool/flock ]; then echo o/tool/flock >&2 FLOCK=o/tool/flock else echo no >&2 printf "building tool/flock.c... " >&2 f=$(mktemp "${TMPDIR}/flock.XXXXXX") if ${CC} -o "${f}" tool/flock.c; then echo ok >&2 mv -f "${f}" o/tool/flock || exit FLOCK=o/tool/flock else echo "error: need the flock command" >&2 exit 1 fi fi CONFIG=$(mktemp "${TMPDIR}/blink-config.h.XXXXXX") BUILD=$(mktemp "${TMPDIR}/blink-config.mk.XXXXXX") LOCK=$(mktemp "${TMPDIR}/blink-config.lock.XXXXXX") cp config.h.in "${CONFIG}" || exit rm -f config.log run() { ( printf '%s\n' "$*" if nice "$@"; then exit 0 else rc=$? echo "exit code $rc" exit $rc fi ) >&6 2>&6 } compile() { run ${CC:-cc} \ ${EXTRA_CFLAGS} \ ${CFLAGS} \ ${EXTRA_CPPFLAGS} \ ${CPPFLAGS} \ ${EXTRA_LDFLAGS} \ ${LDFLAGS} \ ${TARGET_ARCH} \ "$@" \ ${LOADLIBES} \ ${EXTRA_LDLIBS} \ ${LDLIBS} } config() { PROGRAM="$1" # If running on cygwin, msys2 or wsl then enable testing mingw-w64 produced binaries if test "${CC#*w64-mingw}" != "${CC}"; then RUNPROGRAM="$1.exe" elif [ "${HOST_OS}" = "Cygwin" ]; then RUNPROGRAM="$1.exe" else RUNPROGRAM="$1" fi MESSAGE="$2" shift 2 LOG=$(mktemp "${TMPDIR}/blink-config.log.XXXXXX") exec 6<>"${LOG}" echo >&6 echo ======================================================================== >&6 echo "${MESSAGE}" >&6 echo ======================================================================== >&6 echo >&6 if [ ! -f "tool/config/${PROGRAM}.c" ]; then echo "tool/config/${PROGRAM}.c: not found" >&2 exit 1 fi if compile -Werror -o "o/tool/config/${PROGRAM}" "tool/config/${PROGRAM}.c" && run "o/tool/config/${RUNPROGRAM}"; then printf '%s\n' "${MESSAGE} yes" >&2 if [ $# -gt 0 ]; then "$@" fi rc=0 else printf '%s\n' "${MESSAGE} no" >&2 rc=1 fi cat <"${LOG}" >>config.log rm -f "${LOG}" exec 6<&- EXTRA_CFLAGS= EXTRA_CPPFLAGS= EXTRA_LDFLAGS= EXTRA_LDLIBS= return $rc } hassstr() { if ! grep "$1" <"${CONFIG}" >/dev/null 2>&1; then echo "config.h.in didn't contain $1" >&2 fi } replace() { exec 7<>"${LOCK}" "${FLOCK}" -x 7 sed "s@$1@$2@" <"${CONFIG}" >"${CONFIG}.tmp" && mv -f "${CONFIG}.tmp" "${CONFIG}" exec 7<&- } comment() { hassstr "$1" replace "$1" "// $1" } uncomment() { hassstr "$1" replace "// $1" "$1" } for x; do if [ x"${x%=*}" != x"$x" ] && [ x"${x#--}" = x"$x" ]; then continue fi if [ x"$x" = x"--disable-all" ]; then uncomment "#define DISABLE" DISABLE_NONPOSIX=1 DISABLE_THREADS=1 DISABLE_SOCKETS=1 DISABLE_FORK=1 DISABLE_X87=1 DISABLE_JIT=1 elif [ x"${x%%=*}" = x"--prefix" ]; then PREFIX="${x#*=}" elif [ x"$x" = x"--static" ]; then STATIC=1 elif [ x"$x" = x"--enable-fork" ]; then unset DISABLE_FORK elif [ x"$x" = x"--disable-fork" ]; then DISABLE_FORK=1 elif [ x"$x" = x"--enable-jit" ]; then comment "#define DISABLE_JIT" unset DISABLE_JIT elif [ x"$x" = x"--disable-jit" ]; then uncomment "#define DISABLE_JIT" DISABLE_JIT=1 elif [ x"$x" = x"--enable-x87" ]; then comment "#define DISABLE_X87" unset DISABLE_X87 elif [ x"$x" = x"--disable-x87" ]; then uncomment "#define DISABLE_X87" DISABLE_X87=1 elif [ x"$x" = x"--enable-mmx" ]; then comment "#define DISABLE_MMX" elif [ x"$x" = x"--disable-mmx" ]; then uncomment "#define DISABLE_MMX" elif [ x"$x" = x"--enable-metal" ]; then comment "#define DISABLE_METAL" elif [ x"$x" = x"--disable-metal" ]; then uncomment "#define DISABLE_METAL" elif [ x"$x" = x"--enable-strace" ]; then comment "#define DISABLE_STRACE" elif [ x"$x" = x"--disable-strace" ]; then uncomment "#define DISABLE_STRACE" elif [ x"$x" = x"--enable-threads" ]; then comment "#define DISABLE_THREADS" unset DISABLE_THREADS elif [ x"$x" = x"--disable-threads" ]; then uncomment "#define DISABLE_THREADS" DISABLE_THREADS=1 elif [ x"$x" = x"--enable-sockets" ]; then comment "#define DISABLE_SOCKETS" unset DISABLE_SOCKETS elif [ x"$x" = x"--disable-sockets" ]; then uncomment "#define DISABLE_SOCKETS" DISABLE_SOCKETS=1 elif [ x"$x" = x"--enable-overlays" ]; then comment "#define DISABLE_OVERLAYS" uncomment "#define DISABLE_VFS" elif [ x"$x" = x"--disable-overlays" ]; then uncomment "#define DISABLE_OVERLAYS" elif [ x"$x" = x"--enable-vfs" ]; then comment "#define DISABLE_VFS" uncomment "#define DISABLE_OVERLAYS" elif [ x"$x" = x"--disable-vfs" ]; then uncomment "#define DISABLE_VFS" elif [ x"$x" = x"--enable-ancillary" ]; then comment "#define DISABLE_ANCILLARY" elif [ x"$x" = x"--disable-ancillary" ]; then uncomment "#define DISABLE_ANCILLARY" elif [ x"$x" = x"--enable-disassembler" ]; then comment "#define DISABLE_DISASSEMBLER" elif [ x"$x" = x"--disable-disassembler" ]; then uncomment "#define DISABLE_DISASSEMBLER" elif [ x"$x" = x"--enable-backtrace" ]; then comment "#define DISABLE_BACKTRACE" elif [ x"$x" = x"--disable-backtrace" ]; then uncomment "#define DISABLE_BACKTRACE" elif [ x"$x" = x"--enable-nonposix" ]; then comment "#define DISABLE_NONPOSIX" unset DISABLE_NONPOSIX elif [ x"$x" = x"--disable-nonposix" ]; then uncomment "#define DISABLE_NONPOSIX" DISABLE_NONPOSIX=1 elif [ x"$x" = x"--enable-bmi2" ]; then comment "#define DISABLE_BMI2" elif [ x"$x" = x"--disable-bmi2" ]; then uncomment "#define DISABLE_BMI2" elif [ x"$x" = x"--enable-bcd" ]; then comment "#define DISABLE_BCD" elif [ x"$x" = x"--disable-bcd" ]; then uncomment "#define DISABLE_BCD" elif [ x"$x" = x"--enable-rom" ]; then comment "#define DISABLE_ROM" elif [ x"$x" = x"--disable-rom" ]; then uncomment "#define DISABLE_ROM" elif [ x"$x" = x"--posix" ]; then CPPFLAGS="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -std=c11" POSIX=1 elif [ x"$x" = x"--pedantic" ]; then CFLAGS="$CFLAGS -std=c11 -pedantic -Wall -Werror" else echo "error: unrecognized flag: $x" >&2 echo "use $0 --help for help" >&2 exit 1 fi done if [ "${STATIC}" ]; then LDFLAGS="-static ${LDFLAGS}" EXTRA_CFLAGS=-fno-pie EXTRA_LDFLAGS=-no-pie if config noop "checking for no-pie... "; then CFLAGS="-fno-pie ${CFLAGS}" LDFLAGS="-no-pie ${LDFLAGS}" fi fi # position independent executables # 1. help ensure blink won't overlap static binaries in memory # 2. gcc and clang generates tinier code for switch statements EXTRA_CFLAGS=-fpie EXTRA_LDFLAGS=-pie if [ -z "${STATIC}" ] && config noop "checking for pie... "; then CFLAGS="-fpie ${CFLAGS}" LDFLAGS="-pie ${LDFLAGS}" else # otherwise relocate blink somewhere irregular BASE=-Wl,--image-base=0x23000000 EXTRA_LDFLAGS="${BASE}" if config noop "checking for ${BASE}... "; then LDFLAGS="${BASE} ${LDFLAGS}" else BASE=-Wl,-Ttext-segment=0x23000000 EXTRA_LDFLAGS="${BASE}" if config noop "checking for ${BASE}... "; then LDFLAGS="${BASE} ${LDFLAGS}" fi fi fi # ensure binaries will run on apple m1, cygwin, etc. # blink can't map a program into memory without this GOODELF=-Wl,-z,common-page-size=65536,-z,max-page-size=65536 EXTRA_LDFLAGS="${GOODELF}" if config noop "checking for ${GOODELF}..."; then LDFLAGS="${GOODELF} ${LDFLAGS}" # with 64kb pages these two security blankets would otherwise cause # blink's minimum binary size to increase from 120kb to 250kb. yuck NORELRO=-Wl,-z,norelro EXTRA_LDFLAGS="${NORELRO}" if config noop "checking for ${NORELRO}... "; then LDFLAGS="${NORELRO} ${LDFLAGS}" fi NORODATAPHDR=-Wl,-z,noseparate-code EXTRA_LDFLAGS="${NORODATAPHDR}" if config noop "checking for ${NORODATAPHDR}... "; then LDFLAGS="${NORODATAPHDR} ${LDFLAGS}" fi fi # check for the math library EXTRA_LDLIBS=-lm if config lm "checking for -lm... "; then LDLIBS="-lm ${LDLIBS}" fi # check for the posix threads library if [ -z "${DISABLE_THREADS}" ]; then EXTRA_CFLAGS=-pthread EXTRA_LDFLAGS=-pthread if config pthread "checking for -pthread... "; then CFLAGS="-pthread ${CFLAGS}" LDFLAGS="-pthread ${LDFLAGS}" else EXTRA_LDLIBS=-lpthread if config pthread "checking for -lpthread... "; then LDLIBS="-lpthread ${LDLIBS}" else if config pthread "checking for pthreads... "; then LDLIBS="-lpthread ${LDLIBS}" else uncomment "#define DISABLE_THREADS" fi fi fi fi # check for the posix.1b realtime extensions library # note: librt depends on pthreads, on rhel5 at least EXTRA_LDLIBS=-lrt if config lrt "checking for -lrt... "; then LDLIBS="-lrt ${LDLIBS}" fi # should be the default and macos build fails without it EXTRA_CFLAGS=-fno-common if config noop "checking for -fno-common... "; then CFLAGS="-fno-common ${CFLAGS}" fi # make sure sanitizers aren't enabled on micro-op functions EXTRA_CFLAGS=-fno-sanitize=all if config noop "checking for -fno-sanitize=all... "; then UOPFLAGS="-fno-sanitize=all ${UOPFLAGS}" fi # blink's jit will align the functions that matter if [ -n "${JIT_POSSIBLE}" ] && [ -z "${DISABLE_JIT}" ]; then EXTRA_CFLAGS=-fno-align-functions if config noop "checking for -fno-align-functions... "; then CFLAGS="-fno-align-functions ${CFLAGS}" fi fi # blink's jit can't extract and relocate micro-op function bodies if the # compiler inserts things like static memory references into them. EXTRA_CFLAGS=-fno-stack-protector if config noop "checking for -fno-stack-protector... "; then UOPFLAGS="-fno-stack-protector ${UOPFLAGS}" fi # avoid cosmo libc function call tracing messing up micro-ops EXTRA_CFLAGS=-fpatchable-function-entry=0,0 if config noop "checking for -fpatchable-function-entry=0,0... "; then UOPFLAGS="-fpatchable-function-entry=0,0 ${UOPFLAGS}" fi # avoid creating stack frames in micro-op functions if [ "${MODE}" != "prof" ]; then EXTRA_CFLAGS=-fomit-frame-pointer if config noop "checking for -fomit-frame-pointer... "; then UOPFLAGS="${UOPFLAGS} -fomit-frame-pointer" fi fi # for everything else, stack frames are extremely important if [ "${MODE}" != "tiny" ]; then EXTRA_CFLAGS=-fno-omit-frame-pointer if config noop "checking for -fno-omit-frame-pointer... "; then CFLAGS="${CFLAGS} -fno-omit-frame-pointer" fi fi # c11 atomics are no-op'd when both fork and threads are disabled # this causes code to break modern compiler strict aliasing rules # TODO(jart) is it safe to quash warning w/o -fno-strict-aliasing if [ -n "${DISABLE_THREADS}" ] && [ -n "${DISABLE_FORK}" ]; then EXTRA_CFLAGS=-Wno-strict-aliasing if config noop "checking for -Wno-strict-aliasing... "; then CFLAGS="${CFLAGS} -Wno-strict-aliasing" fi fi # this optimization harms our ability to backtrace binaries # blink doesn't rely on tail call optimization so we don't need it if [ -z "${MODE}" ] && [ -n "${JIT_POSSIBLE}" ] && [ -z "${DISABLE_JIT}" ]; then EXTRA_CFLAGS=-fno-optimize-sibling-calls if config noop "checking for -fno-optimize-sibling-calls... "; then CFLAGS="${CFLAGS} -fno-optimize-sibling-calls" fi fi # the new intel cet instructions may interfere with jit, and only # offer improved security if the os and cpu both know about them; # we can revisit cet later when it becomes more mainstream if [ -n "${JIT_POSSIBLE}" ] && [ -z "${DISABLE_JIT}" ]; then EXTRA_CFLAGS=-fcf-protection=none if config noop "checking for -fcf-protection=none... "; then CFLAGS="${CFLAGS} -fcf-protection=none" fi fi # use the system zlib if available # otherwise, use our vendored copy ZLIB_CFLAGS="$(pkg-config --cflags zlib 2>/dev/null)" if ! ZLIB_LDLIBS="$(pkg-config --libs zlib 2>/dev/null)"; then ZLIB_LDLIBS="-lz" fi EXTRA_CFLAGS="${ZLIB_CFLAGS}" EXTRA_LDLIBS="${ZLIB_LDLIBS}" if config zlib "checking for zlib... "; then CFLAGS="${ZLIB_CFLAGS} ${CFLAGS}" LDLIBS="${ZLIB_LDLIBS} ${LDLIBS}" ZLIB= else ZLIB='o/$(MODE)/third_party/libz/zlib.a' fi # try to get blink backtraces if possible if [ "${MODE}" != "tiny" ] && [ "${MODE}" != "rel" ]; then UNWIND_CFLAGS="$(pkg-config --cflags libunwind 2>/dev/null)" if ! UNWIND_LDLIBS="$(pkg-config --libs libunwind 2>/dev/null)"; then UNWIND_LDLIBS="-lunwind -llzma" fi EXTRA_CFLAGS="${UNWIND_CFLAGS}" EXTRA_LDLIBS="${UNWIND_LDLIBS}" if config libunwind "checking for libunwind... "; then CFLAGS="${UNWIND_CFLAGS} ${CFLAGS}" LDLIBS="${UNWIND_LDLIBS} ${LDLIBS}" uncomment "#define HAVE_LIBUNWIND" fi fi # attempt to polyfill c11 atomics if it's not available if ! config stdatomic "checking for stdatomic.h... "; then CPPFLAGS="-isystem tool/stdatomic ${CPPFLAGS}" fi if [ -z "${DISABLE_FORK}" ]; then ( config fork "checking for fork()... " uncomment "#define HAVE_FORK" ) & else echo "checking for fork()... disabled" fi if [ -z "${POSIX}" ]; then ( config dup3 "checking for dup3()... " uncomment "#define HAVE_DUP3" ) & ( config pipe2 "checking for pipe2()... " uncomment "#define HAVE_PIPE2" ) & ( config getrandom "checking for getrandom()... " uncomment "#define HAVE_GETRANDOM" ) & ( config getentropy "checking for getentropy() in unistd.h... " uncomment "#define HAVE_GETENTROPY" ) & ( config dev_urandom "checking for /dev/urandom... " uncomment "#define HAVE_DEV_URANDOM" ) & ( config rtlgenrandom "checking for RtlGenRandom()... " uncomment "#define HAVE_RTLGENRANDOM" ) & ( config sys_getrandom "checking for syscall(SYS_getrandom)... " uncomment "#define HAVE_SYS_GETRANDOM" ) & ( config sys_getentropy "checking for getentropy() in sys/random.h... " uncomment "#define HAVE_SYS_GETENTROPY" ) & ( config getdomainname "checking for getdomainname()... " uncomment "#define HAVE_GETDOMAINNAME" ) & ( config kern_arnd "checking for sysctl(KERN_ARND)... " uncomment "#define HAVE_KERN_ARND" ) & ( config siocgifconf "checking for SIOCGIFCONF... " uncomment "#define HAVE_SIOCGIFCONF" ) & ( config epoll_pwait1 "checking for epoll_pwait()... " uncomment "#define HAVE_EPOLL_PWAIT1" ) & wait ( config epoll_pwait2 "checking for epoll_pwait2()... " uncomment "#define HAVE_EPOLL_PWAIT2" ) & ( config map_anonymous "checking for mmap(MAP_ANONYMOUS)... " uncomment "#define HAVE_MAP_ANONYMOUS" ) & ( config sched_getaffinity "checking for sched_getaffinity()... " uncomment "#define HAVE_SCHED_GETAFFINITY" ) & ( config scm_credentials "checking for SCM_CREDENTIALS... " uncomment "#define HAVE_SCM_CREDENTIALS" ) & ( config f_getown_ex "checking for F_GETOWN_EX... " uncomment "#define HAVE_F_GETOWN_EX" ) & ( config setgroups "checking for setgroups()... " uncomment "#define HAVE_SETGROUPS" ) & ( config vasprintf "checking for vasprintf()... " uncomment "#define HAVE_VASPRINTF" ) & ( config strchrnul "checking for strchrnul()... " uncomment "#define HAVE_STRCHRNUL" ) & ( config mkfifo "checking for mkfifo()... " uncomment "#define HAVE_MKFIFO" ) & ( config mkfifoat "checking for mkfifoat()... " uncomment "#define HAVE_MKFIFOAT" ) & ( config preadv "checking for preadv() and pwritev()... " uncomment "#define HAVE_PREADV" ) & ( config wait4 "checking for wait4()... " uncomment "#define HAVE_WAIT4" ) & ( config setresuid "checking for setresuid()... " uncomment "#define HAVE_SETRESUID" ) & ( config sys_mount_h "checking for sys/mount.h... " uncomment "#define HAVE_SYS_MOUNT_H" ) & fi ( config sync "checking for sync()... " uncomment "#define HAVE_SYNC" ) & ( config sysctl "checking for sysctl()... " uncomment "#define HAVE_SYSCTL" ) & ( config sysinfo "checking for sysinfo()... " uncomment "#define HAVE_SYSINFO" ) & ( config fexecve "checking for fexecve()... " uncomment "#define HAVE_FEXECVE" ) & ( config wcwidth "checking for wcwidth()... " uncomment "#define HAVE_WCWIDTH" ) & ( config memccpy "checking for memccpy()... " uncomment "#define HAVE_MEMCCPY" ) & ( config seekdir "checking for seekdir()... " uncomment "#define HAVE_SEEKDIR" ) & ( config realpath "checking for realpath()... " uncomment "#define HAVE_REALPATH" ) & ( config setreuid "checking for setreuid()... " uncomment "#define HAVE_SETREUID" ) & ( config fdatasync "checking for fdatasync()... " uncomment "#define HAVE_FDATASYNC" ) & ( config sendto_zero "checking for sendto(0.0.0.0)... " uncomment "#define HAVE_SENDTO_ZERO" ) & wait ( config struct_timezone "checking for struct timezone... " uncomment "#define HAVE_STRUCT_TIMEZONE" ) & ( config sa_len "checking for sockaddr::sa_len... " uncomment "#define HAVE_SA_LEN" ) & ( config map_shared "checking for mmap(MAP_SHARED)... " uncomment "#define HAVE_MAP_SHARED" ) & ( config sched_yield "checking for sched_yield()... " uncomment "#define HAVE_SCHED_YIELD" ) & ( config clock_settime "checking for clock_settime()... " uncomment "#define HAVE_CLOCK_SETTIME" ) & ( config sched_h "checking for sched.h... " uncomment "#define HAVE_SCHED_H" ) & ( config pthread_process_shared "checking for PTHREAD_PROCESS_SHARED... " uncomment "#define HAVE_PTHREAD_PROCESS_SHARED" ) & ( config pthread_setcancelstate "checking for pthread_setcancelstate()... " uncomment "#define HAVE_PTHREAD_SETCANCELSTATE" ) & ( config sockatmark "checking for sockatmark()... " uncomment "#define HAVE_SOCKATMARK" ) & wait rm -f "${LOCK}" BLINK_UNAME_V= if test "${DISABLE_NONPOSIX}"; then BLINK_UNAME_V="${BLINK_UNAME_V} POSIX" fi if test "${DISABLE_JIT}" || test -z "${JIT_POSSIBLE}"; then BLINK_UNAME_V="${BLINK_UNAME_V} NOJIT" fi if test "${DISABLE_SOCKETS}"; then BLINK_UNAME_V="${BLINK_UNAME_V} NOSOCK" fi if test -z "${BLINK_UNAME_V}"; then if test -z "$*"; then BLINK_UNAME_V="${BLINK_UNAME_V:-DEFAULT}" else BLINK_UNAME_V="${BLINK_UNAME_V:-CUSTOM}" fi fi for x; do if [ x"${x%=*}" != x"$x" ] && [ x"${x#--}" = x"$x" ]; then printf '%s\n' "$x" >>"${BUILD}" fi done cat >>"${BUILD}" <&2 echo "creating config.mk" >&2 mv "${BUILD}" config.mk || exit echo "creating config.h" >&2 mv "${CONFIG}" config.h || exit ================================================ FILE: test/asm/README.md ================================================ # Blink's Assembly Tests Blink's "assembly tests" are tests written in pure assembly that we run both in Blink and on bare metal. Compilers only utilize a subset of what the instruction set architecture is capable of doing. For example, `CMPXCHG` is able to set the overflow flag under certain conditions, but that would never matter to any C code that's compiled by GCC. Another example is the clearing of the upper half of registers on 32-bit operations. We need to ensure that Blink will always do that when appropriate, just as the host hardware would. However C code may be unlikely to catch when this happening. In host environments that aren't AMD64 Linux, bare metal testing will be stubbed out using `$(VM)`. Therefore this test suite will still pass, but it'll only be 100% useful when it's run on an `x86_64-linux` system. ================================================ FILE: test/asm/add.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // make -j8 o//blink o//test/asm/add.elf // o//blink/blinkenlights o//test/asm/add.elf .test "add64" mov $0x1234567812345678,%rax mov $0x0000000000000001,%rbx mov $0x1234567812345679,%rcx add %rbx,%rax .nz .nc .ns .no .np cmp %rcx,%rax .e .test "add32" mov $0x1234567812345678,%rax mov $0x0001000100000001,%rbx mov $0x0000000012345679,%rcx mov $0x0001000100000001,%rdx add %ebx,%eax .nz .nc .ns .no .np cmp %rcx,%rax .e cmp %rdx,%rbx .e .test "add16" mov $0x1234567812345678,%rax mov $0x0001000100010001,%rbx mov $0x1234567812345679,%rcx mov $0x0001000100010001,%rdx add %bx,%ax .nz .nc .ns .no .np cmp %rcx,%rax .e cmp %rdx,%rbx .e "test succeeded": .exit ================================================ FILE: test/asm/adx.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $10,%r15 "test jit too": // unsigned addition with special flags // make -j8 o//blink o//test/asm/adx.elf // o//blink/blinkenlights o//test/asm/adx.elf mov $7,%eax # extended features xor %ecx,%ecx cpuid bt $19,%ebx # adx jnc "test not possible" .test "adcx" mov $0xF0000000,%eax mov $0x10000000,%ebx stc adcx %ebx,%eax .c cmp $0x00000001,%eax .e dec %r15 jnz "test jit too" "test succeeded": .exit "test not possible": .exit ================================================ FILE: test/asm/asm.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ TEST_ASM_FILES := $(wildcard test/asm/*) TEST_ASM_SRCS = $(filter %.S,$(TEST_ASM_FILES)) TEST_ASM_OBJS = $(TEST_ASM_SRCS:%.S=o/$(MODE)/x86_64-gcc49/%.o) TEST_ASM_BINS = $(TEST_ASM_SRCS:%.S=o/$(MODE)/%.elf) TEST_ASM_COMS = $(TEST_ASM_SRCS:%.S=o/$(MODE)/%.com) TEST_ASM_CHECKS = $(TEST_ASM_SRCS:%.S=o/$(MODE)/%.com.ok) TEST_ASM_EMULATES = $(foreach ARCH,$(ARCHITECTURES),$(foreach SRC,$(TEST_ASM_SRCS),$(SRC:%.S=o/$(MODE)/$(ARCH)/%.elf.emulates))) TEST_ASM_LINK = $(VM) \ o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-ld.bfd \ -static \ --omagic \ -z noexecstack \ -z max-page-size=65536 \ -z common-page-size=65536 \ $< \ -o $@ o/$(MODE)/test/asm/%.com.ok: \ o/$(MODE)/test/asm/%.com $< @touch $@ .PRECIOUS: o/$(MODE)/test/asm/%.elf o/$(MODE)/test/asm/%.elf: \ o/$(MODE)/x86_64-gcc49/test/asm/%.o \ o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc \ $(VM) @mkdir -p $(@D) $(TEST_ASM_LINK) $(TEST_ASM_OBJS): test/asm/asm.mk test/asm/mac.inc # the .com extension is for cosmo/tool/emacs/ integration .PRECIOUS: o/$(MODE)/test/asm/%.com o/$(MODE)/test/asm/%.com: \ o/$(MODE)/test/asm/%.elf \ o/$(MODE)/blink/blink \ o/third_party/qemu/4/qemu-x86_64 \ $(VM) @mkdir -p $(@D) @echo "#!/bin/sh" >$@ @echo "echo [test] $(VM) $< >&2" >>$@ @echo "$(VM) $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink $< >&2" >>$@ @echo "o/$(MODE)/blink/blink $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink -m $< >&2" >>$@ @echo "o/$(MODE)/blink/blink -m $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink -jm $< >&2" >>$@ @echo "o/$(MODE)/blink/blink -jm $< || exit" >>$@ @echo "echo [test] o/third_party/qemu/4/qemu-x86_64 -cpu core2duo $< >&2" >>$@ @echo "$(VM) o/third_party/qemu/4/qemu-x86_64 -cpu core2duo $< || exit" >>$@ @chmod +x $@ .PHONY: o/$(MODE)/test/asm o/$(MODE)/test/asm: \ $(TEST_ASM_CHECKS) .PHONY: o/$(MODE)/test/asm/emulates o/$(MODE)/test/asm/emulates: \ $(TEST_ASM_EMULATES) ================================================ FILE: test/asm/bzhi.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $10,%r15 "test jit too": // clear high bits // make -j8 o//blink o//test/asm/bzhi.elf // o//blink/blinkenlights o//test/asm/bzhi.elf mov $7,%eax # extended features xor %ecx,%ecx cpuid bt $8,%ebx # bmi2 jnc "test not possible" .test "bzhi 1" mov $0xffffffff,%eax # input value mov $0x31337133,%ebx # random data mov $0xffffff08,%ecx # clear bit 8 and above bzhi %ecx,%eax,%ebx cmp $0xffffffff,%eax # unchanged .e cmp $0x000000ff,%ebx # output value .e dec %r15 jnz "test jit too" "test succeeded": .exit "test not possible": .exit ================================================ FILE: test/asm/cmc.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // complement carry flag tests // make -j8 o//blink o//test/asm/page.elf // o//blink/blinkenlights o//test/asm/page.elf .test "carry flag manipulation" stc .c clc .nc cmc .c cmc .nc stc .c "test succeeded": .exit ================================================ FILE: test/asm/cmov.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // make -j8 o//blink o//test/asm/cmov.elf // o//blink/blinkenlights o//test/asm/cmov.elf .test "cmovq taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov $0x5555555155555550,%rcx mov $0x5555555155555550,%rdx stc cmovc %rbx,%rax cmp %rcx,%rax .e cmp %rdx,%rbx .e .test "cmovl taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov $0x0000000055555550,%rcx mov $0x5555555155555550,%rdx stc cmovc %ebx,%eax cmp %rcx,%rax .e cmp %rdx,%rbx .e .test "cmovl not taken clears upper half" mov $0x1234567812345678,%rax mov $0x5555555555555555,%rbx mov $0x0000000012345678,%rcx mov $0x5555555555555555,%rdx clc cmovc %ebx,%eax cmp %rcx,%rax .e cmp %rdx,%rbx .e "test succeeded": .exit ================================================ FILE: test/asm/cmp.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $10,%r15 "test jit too": // cmp compares registers and memory // make -j8 o//blink o//test/asm/cmp.elf // o//blink/blinkenlights -j o//test/asm/cmp.elf .test "cmp hi reg" mov $3,%bh movb $3,(%rsp) cmp %bh,(%rsp) .e .test "cmp jit test" mov $3,%ecx 1: mov $1,%eax mov $1,%ebx cmp %eax,%ebx .e loop 1b dec %r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/asm/cmpxchg.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // compare and exchange tests // make -j8 o//blink o//test/asm/cmpxchg.elf // o//blink/blinkenlights o//test/asm/cmpxchg.elf xor %ebp,%ebp and $-16,%rsp push %rbp mov %rsp,%rbp sub $16,%rsp //////////////////////////////////////////////////////////////////////////////// // locked .test "lock cmpxchg 64 taken" mov $0x7fffffff,%eax add $1,%eax mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rax,-8(%rbp) lock cmpxchg %rbx,-8(%rbp) .z .no .ns .nc .p mov $0x1234567812345678,%rcx mov $0x5555555155555550,%rdx cmp %rcx,%rax # rax stays the same .e cmp %rdx,%rbx # reg stays the same .e cmp %rdx,-8(%rbp) # memory got swapped .e .test "lock cmpxchg 64 not taken" mov $0x7fffffff,%eax add $1,%eax mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rbx,-8(%rbp) lock cmpxchg %rbx,-8(%rbp) .nz .no .s .c .p mov $0x5555555155555550,%rdx cmp %rdx,%rax # mem is put in rax .e cmp %rdx,%rbx # reg stays the same .e cmp %rdx,-8(%rbp) # memory is the same .e .test "lock cmpxchg 64 unaligned taken" mov $0x7fffffff,%eax add $1,%eax mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rax,-9(%rbp) lock cmpxchg %rbx,-9(%rbp) .z .no .ns .nc .p mov $0x1234567812345678,%rcx mov $0x5555555155555550,%rdx cmp %rcx,%rax # rax stays the same .e cmp %rdx,%rbx # reg stays the same .e cmp %rdx,-9(%rbp) # memory got swapped .e "are we running in qemu": mov $0x40000001,%eax cpuid cmp %ebx,qemu je "qemu cmpxchg 32 broken" .exit .test "lock cmpxchg 32 taken" mov $0x7fffffff,%eax add $1,%eax mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rax,-8(%rbp) lock cmpxchg %ebx,-8(%rbp) .z .p .ns .nc .no mov $0x1234567812345678,%rcx mov $0x5555555155555550,%rdx mov $0x1234567855555550,%r8 cmp %rcx,%rax # rax stays the same .e # is NOT upper zerod cmp %rdx,%rbx # reg stays the same .e # is NOT upper zerod cmp %r8,-8(%rbp) # memory got swapped .e "qemu cmpxchg 32 broken": .test "lock cmpxchg 32 not taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rbx,-8(%rbp) lock cmpxchg %ebx,-8(%rbp) .nz .p .s .c .no mov $0x0000000055555550,%rdx # mem is put in rax cmp %rdx,%rax .e mov $0x5555555155555550,%rdx # reg stays the same cmp %rdx,%rbx .e cmp %rdx,-8(%rbp) # memory is the same .e .test "lock cmpxchg 8 taken" mov $0x7fffffff,%eax add $1,%eax mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rax,-8(%rbp) lock cmpxchg %bl,-8(%rbp) .z .p .ns .nc .no mov $0x1234567812345678,%rcx mov $0x5555555155555550,%rdx mov $0x1234567812345650,%r8 cmp %rcx,%rax # rax stays the same .e # is NOT upper zerod cmp %rdx,%rbx # reg stays the same .e # is NOT upper zerod cmp %r8,-8(%rbp) # memory got swapped .e .test "lock cmpxchg 8 not taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rbx,-8(%rbp) lock cmpxchg %bl,-8(%rbp) .nz .p .ns .nc .no mov $0x1234567812345650,%rdx # mem is put in rax cmp %rdx,%rax .e mov $0x5555555155555550,%rdx # reg stays the same cmp %rdx,%rbx .e cmp %rdx,-8(%rbp) # memory is the same .e //////////////////////////////////////////////////////////////////////////////// // unlocked .test "cmpxchg 64 taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rax,-8(%rbp) cmpxchg %rbx,-8(%rbp) .z mov $0x1234567812345678,%rcx mov $0x5555555155555550,%rdx cmp %rcx,%rax # rax stays the same .e cmp %rdx,%rbx # reg stays the same .e cmp %rdx,-8(%rbp) # memory got swapped .e .test "cmpxchg 64 not taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rbx,-8(%rbp) cmpxchg %rbx,-8(%rbp) .nz mov $0x5555555155555550,%rdx cmp %rdx,%rax # mem is put in rax .e cmp %rdx,%rbx # reg stays the same .e cmp %rdx,-8(%rbp) # memory is the same .e .test "cmpxchg 32 taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rax,-8(%rbp) cmpxchg %ebx,-8(%rbp) .z mov $0x1234567812345678,%rcx mov $0x5555555155555550,%rdx mov $0x1234567855555550,%r8 cmp %rcx,%rax # rax stays the same .e # is NOT upper zerod cmp %rdx,%rbx # reg stays the same .e # is NOT upper zerod cmp %r8,-8(%rbp) # memory got swapped .e .test "cmpxchg 32 not taken" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rbx,-8(%rbp) cmpxchg %ebx,-8(%rbp) .nz mov $0x0000000055555550,%rdx # mem is put in rax cmp %rdx,%rax .e mov $0x5555555155555550,%rdx # reg stays the same cmp %rdx,%rbx .e cmp %rdx,-8(%rbp) # memory is the same .e "test succeeded": .exit qemu: .ascii "TCGTCGTCGTCG" ================================================ FILE: test/asm/cmpxchg16b.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // compare and exchange tests // make -j8 o//blink o//test/asm/cmpxchg16b.elf // o//blink/blinkenlights o//test/asm/cmpxchg16b.elf mov $0,%rax mov %rax,-16(%rsp) mov %rax,-8(%rsp) .test "lock cmpxchg16b 64 not taken" // if memory is equal to me mov $0x5555555155555550,%rdx mov $0x1234567812345678,%rax // replace it with me mov $0x5500005155550050,%rcx mov $0x1200067810000078,%rbx lock cmpxchg16b -16(%rsp) .nz cmp $0,%rdx .z cmp $0,%rax .z .test "lock cmpxchg16b 64 taken" // if memory is equal to me mov $0x5555555155555550,%rdx mov $0x1234567812345678,%rax mov %rax,-16(%rsp) mov %rdx,-8(%rsp) // replace it with me mov $0x5500005155550050,%rcx mov $0x1200067810000078,%rbx lock cmpxchg16b -16(%rsp) .z cmp %rbx,-16(%rsp) .z cmp %rcx,-8(%rsp) .z "test succeeded": .exit ================================================ FILE: test/asm/enter.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // make -j8 o//blink o//test/asm/enter.elf // o//blink/blinkenlights o//test/asm/enter.elf #define MAGIC1 0x2b8cfa3db6a78c9a #define MAGIC2 0x58b8 #define MAGIC3 0x225e #define MAGIC4 0x4ea0 .test "enterq stores frame pointer of size 8" movabs $MAGIC1,%rbx lea -8-MAGIC2(%rsp),%rax lea -8(%rsp),%rcx mov %rsp,%rdx mov %rbx,%rbp enterq $MAGIC2,$0 cmp %rsp,%rax .e cmp %rbp,%rcx .e cmp (%rbp),%rbx .e .test "leaveq restores frame pointer of size 8" leaveq cmp %rdx,%rsp .e cmp %rbx,%rbp .e .test "enterw stores frame pointer of size 2" xor %sp,%sp // make sure %sp does not wrap sub $8,%rsp // around 64 KiB boundary mov %rsp,%rbx mov $MAGIC3,%bx lea -2-MAGIC4(%rsp),%rax lea -2(%rsp),%rcx mov %rsp,%rdx mov %rbx,%rbp enterw $MAGIC4,$0 cmp %rsp,%rax .e cmp %rbp,%rcx .e cmp (%rbp),%bx .e .test "leavew restores frame pointer of size 2" leavew cmp %rdx,%rsp .e mov %bx,%dx cmp %rdx,%rbp .e "test succeeded": .exit ================================================ FILE: test/asm/exit.S ================================================ // exit(0) example // make -j8 o//blink o//test/asm/exit.elf // o//blink/blinkenlights o//test/asm/exit.elf .globl _start _start: mov $0,%edi mov $231,%eax syscall ================================================ FILE: test/asm/lahf.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // make -j8 o//blink o//test/asm/lahf.elf // o//blink/blinkenlights o//test/asm/lahf.elf .test "LAHF stores flags into AH" mov $0x7fffffff,%eax add $4,%eax .sop mov $-1,%eax lahf // we need to remove AF from the result to be // consistent with the actual hardware result // // cf ──┐ // 1 ──┐│ // pf ──┐││ // 0 ──┐│││ // af ──┐││││ // 0 ──┐│││││ // zf ──┐││││││ // sf ──┐│││││││ // ││││││││ and $0b11111111111111111111011111111111,%eax cmp $0b11111111111111111001011011111111,%eax .e "test succeeded": .exit ================================================ FILE: test/asm/lock.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // make -j8 o//blink o//test/asm/lock.elf // o//blink/blinkenlights o//test/asm/lock.elf .test "lock aligned" movl $0,(%rsp) lock incl (%rsp) lock incl (%rsp) cmpl $2,(%rsp) .e .test "lock misaligned" movl $0,1(%rsp) lock incl 1(%rsp) lock incl 1(%rsp) cmpl $2,1(%rsp) .e "test succeeded": .exit ================================================ FILE: test/asm/mac.inc ================================================ // -*- mode: unix-assembly; indent-tabs-mode: t; tab-width: 8; coding: utf-8 -*- .macro .exit mov $0,%edi mov $231,%eax syscall .endm .macro .test name:req prologue\@: jmp 101f 100: int3 101: nop "\name": .endm .macro .c jnc 100b .endm .macro .nc jc 100b .endm .macro .e jne 100b .endm .macro .ne je 100b .endm .macro .z jnz 100b .endm .macro .nz jz 100b .endm .macro .s jns 100b .endm .macro .ns js 100b .endm .macro .o jno 100b .endm .macro .no jo 100b .endm .macro .p jnp 100b .endm .macro .np jp 100b .endm .macro .sop .nz .s .nc .o .p .endm ================================================ FILE: test/asm/movi.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $3,%r15 "test jit too": // immediate moves // make -j8 o//blink o//test/asm/movi.elf // o//blink/blinkenlights o//test/asm/movi.elf .test "mov imm reg 32" mov $0x3133731337,%rax mov $0x3133731337,%rdx mov $0x31337,%eax mov $0x31337,%edx push $0x31337 pop %r8 cmp %r8,%rax .e cmp %r8,%rdx .e .test "mov imm reg 16" mov $0x3133731337,%rax mov $0x3133731337,%rdx mov $0xdead,%ax mov $0xdead,%dx mov $0x313373dead,%r8 cmp %r8,%rax .e cmp %r8,%rdx .e .test "mov imm reg 8" mov $0x3133731337,%rax mov $0x3133731337,%rdx mov $0xbb,%al mov $0xcc,%dh mov $0x31337313bb,%r8 cmp %r8,%rax .e mov $0x313373cc37,%r8 cmp %r8,%rdx .e dec %r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/asm/movmskpd.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $3,%r15 "test jit too": // extract floating point sign mask // make -j8 o//blink o//test/asm/movmskpd.elf // o//blink/blinkenlights o//test/asm/movmskpd.elf .test "movmskpd neg neg" movaps negneg(%rip),%xmm0 movmskpd %xmm0,%eax cmp $0b11,%eax .e .test "movmskpd neg pos" movaps negpos(%rip),%xmm0 movmskpd %xmm0,%eax cmp $0b01,%eax .e .test "movmskpd pos pos" movaps pospos(%rip),%xmm0 movmskpd %xmm0,%eax cmp $0b00,%eax .e .test "movmskps neg neg neg neg" movaps nnnn(%rip),%xmm0 movmskps %xmm0,%eax cmp $0b1111,%eax .e .test "movmskps neg pos neg pos" movaps npnp(%rip),%xmm0 movmskps %xmm0,%eax cmp $0b0101,%eax .e dec %r15 jnz "test jit too" "test succeeded": .exit .section .rodata .align 16 negneg: .double -1.1, -2.2 negpos: .double -1.1, +2.2 pospos: .double +1.1, +2.2 nnnn: .float -1.1, -2.2, -2.2, -4.2 npnp: .float -1.1, +2.2, -2.2, +4.2 ================================================ FILE: test/asm/movntdq.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $10,%r15 "test jit too": // non-temporal move // make -j8 o//blink o//test/asm/movntdq.elf // o//blink/blinkenlights o//test/asm/movntdq.elf .test "movntdq" movdqa data,%xmm12 movntdq %xmm12,(%rsp) cmpq $123,(%rsp) .e cmpq $456,8(%rsp) .e dec %r15 jnz "test jit too" "test succeeded": .exit .align 16 data: .quad 123 .quad 456 ================================================ FILE: test/asm/movsreg.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $3,%r15 "test jit too": // make -j8 o//blink o//test/asm/movsreg.elf // o//blink/blinkenlights -j o//test/asm/movsreg.elf .test "mov cs" mov %cs,%eax mov %al,%dl and $3,%dl cmp $3,%dl // default cs should have RPL 3 .e shr $2,%ax // default cs should not be null .ne .test "mov ss" mov %ss,%eax mov %al,%dl and $3,%dl cmp $3,%dl // default ss should have RPL 3 .e shr $2,%ax .ne // default ss should not be null dec %r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/asm/movsxd.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $5,%r15 "test jit too": // sign extending moves // make -j8 o//blink o//test/asm/movsxd.elf // o//blink/blinkenlights o//test/asm/movsxd.elf .test "sign extend 32-bit to 32-bit" push $-2147483648 .byte 0x63,0x04,0x24 # movsll (%rsp),%eax movabs $0x0000000080000000,%rcx cmp %rcx,%rax .e .test "sign extend 32-bit to 64-bit" push $-2147483648 movslq (%rsp),%rax mov $0xffffffff80000000,%rcx cmp %rcx,%rax .e sub $1,%r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/asm/movz.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $3,%r15 "test jit too": // zero-extending moves // make -j8 o//blink o//test/asm/cmp.elf // o//blink/blinkenlights -j o//test/asm/cmp.elf .test "movzbl reg" mov $0x0102030405060708,%rax movzbl %al,%eax mov $0x0000000000000008,%rbx cmp %rbx,%rax .e .test "movzwl reg" mov $0x0102030405060708,%rax movzwl %ax,%eax mov $0x0000000000000708,%rbx cmp %rbx,%rax .e .test "movzwl mem" mov $0x0102030405060708,%rax mov %rax,(%rsp) or $-1,%rax movzwl (%rsp),%eax mov $0x0000000000000708,%rbx cmp %rbx,%rax .e dec %r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/asm/mulx.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $10,%r15 "test jit too": // unsigned multiply w/o affecting flags // make -j8 o//blink o//test/asm/mulx.elf // o//blink/blinkenlights o//test/asm/mulx.elf mov $7,%eax # extended features xor %ecx,%ecx cpuid bt $8,%ebx # bmi2 jnc "test not possible" .test "mulx 1" mov $2,%eax mov $3,%ebx mov $4,%ecx mov $5,%edx mulx %eax,%ebx,%ecx cmp $2,%eax # unchanged .e cmp $5,%edx # unchanged .e cmp $10,%ebx # (2 * 5) & 0xffffffff .e cmp $0,%ecx # (2 * 5) >> 32 .e .test "mulx 2" mov $2,%r10d mov $3,%ebx mov $4,%ecx mov $5,%edx mulx %r10d,%ebx,%ecx cmp $2,%r10d # unchanged .e cmp $5,%edx # unchanged .e cmp $10,%ebx # (2 * 5) & 0xffffffff .e cmp $0,%ecx # (2 * 5) >> 32 .e .test "mulx 3" mov $2,%eax mov $3,%r10d mov $4,%ecx mov $5,%edx mulx %eax,%r10d,%ecx cmp $2,%eax # unchanged .e cmp $5,%edx # unchanged .e cmp $10,%r10d # (2 * 5) & 0xffffffff .e cmp $0,%ecx # (2 * 5) >> 32 .e .test "mulx 4" mov $2,%eax mov $3,%ebx mov $4,%r10d mov $5,%edx mulx %eax,%ebx,%r10d cmp $2,%eax # unchanged .e cmp $5,%edx # unchanged .e cmp $10,%ebx # (2 * 5) & 0xffffffff .e cmp $0,%r10d # (2 * 5) >> 32 .e dec %r15 jnz "test jit too" "test succeeded": .exit "test not possible": .exit ================================================ FILE: test/asm/nop.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // make -j8 o//blink o//test/asm/nop.elf // o//blink/blinkenlights o//test/asm/nop.elf nop nopl (%rax) nop nop nopl (%rax) nop nopl (%rax) nop nop push $0 mov %rsp,%rdi xchg (%rdi),%r12 .test "nop doesn't clear high bits of %rax" mov $0x0102030405060708,%rax mov %rax,%rbx nop cmp %rbx,%rax .e .test "rexb nop clears high bits and swaps with %r8d" mov $0x7172737475767778,%r8 rex.b nop mov $0x0000000075767778,%rbx cmp %rbx,%rax .e mov $0x0000000005060708,%rbx cmp %rbx,%r8 .e "test succeeded": .exit ================================================ FILE: test/asm/overflow.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $3,%r15 "test jit too": // make -j8 o//blink o//test/asm/overflow.elf // o//blink/blinkenlights o//test/asm/overflow.elf //////////////////////////////////////////////////////////////////////////////// // ADD INSTRUCTION .test "overflow add 64" xor %eax,%eax mov $0x7ffffffffffffffe,%rax add $1,%rax .no add $1,%rax .o .test "overflow add 32" xor %eax,%eax mov $0x7ffffffe,%eax add $1,%eax .no add $1,%eax .o .test "overflow add 16" xor %ax,%ax mov $0x7ffe,%ax add $1,%ax .no add $1,%ax .o .test "overflow add lo" xor %al,%al mov $0x7e,%al add $1,%al .no add $1,%al .o .test "overflow add hi" xor %ah,%ah mov $0x7e,%ah add $1,%ah .no add $1,%ah .o //////////////////////////////////////////////////////////////////////////////// // SUB INSTRUCTION .test "overflow sub 64" xor %eax,%eax mov $0x7ffffffffffffffe,%rax sub $-1,%rax .no sub $-1,%rax .o .test "overflow sub 32" xor %eax,%eax mov $0x7ffffffe,%eax sub $-1,%eax .no sub $-1,%eax .o .test "overflow sub 16" xor %ax,%ax mov $0x7ffe,%ax sub $-1,%ax .no sub $-1,%ax .o .test "overflow sub lo" xor %al,%al mov $0x7e,%al sub $-1,%al .no sub $-1,%al .o .test "overflow sub hi" xor %ah,%ah mov $0x7e,%ah sub $-1,%ah .no sub $-1,%ah .o dec %r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/asm/page.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // memory page tests // make -j8 o//blink o//test/asm/page.elf // o//blink/blinkenlights o//test/asm/page.elf sub $8,%rsp and $-4096,%rsp .test "read/write page overlap" mov $0x1234567812345678,%rax mov %rax,-1(%rsp) mov -1(%rsp),%rbx cmp %rbx,%rax .e "test succeeded": .exit ================================================ FILE: test/asm/push.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // make -j8 o//blink o//test/asm/push.elf // o//blink/blinkenlights o//test/asm/push.elf sub $1,%rsp .test "push moves stack by 8" mov %rsp,%rax push %rax mov %rsp,%rbx sub %rbx,%rax cmp $8,%rax .e .test "asz does not affect stack pointer size for push" mov %rsp,%rax orq $-1,-8(%rsp) addr32 push %rax mov %rsp,%rbx cmp %rax,(%rbx) .e sub %rbx,%rax cmp $8,%rax .e .test "osz push moves stack by 2" mov %rsp,%rax pushw $0x439d mov %rsp,%rbx sub %rbx,%rax cmp $2,%rax .e .test "osz push changes two bytes" xor %eax,%eax mov %rsp,%rbp movl $0xffffffff,-4(%rbp) push %ax cmpl $0x0000ffff,-4(%rbp) .e .test "osz pop changes low two bytes only" or $-1,%rax pop %ax mov $0xffffffffffff0000,%rbx cmp %rbx,%rax .e .test "asz does not affect stack pointer size for pop" addr32 pop %ax mov $0xffffffffffff439d,%rbx cmp %rbx,%rax .e "test succeeded": .exit ================================================ FILE: test/asm/repmovsb.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // rep movsb // make -j8 o//blink o//test/asm/repmovsb.elf // o//blink/blinkenlights o//test/asm/repmovsb.elf .test "rep movsb" or $0,A1 lea A1+4,%rdi lea A1,%rsi mov $A2-A1-4,%rcx rep movsb lea A1-1,%rdi lea B1-1,%rsi mov $A2-A1+2,%rcx repz cmpsb .e .test "reverse rep movsb" or $0,C1 lea C1+(C2-C1-4),%rdi lea C1+(C2-C1-1),%rsi mov $C2-C1-3,%rcx std rep movsb cld lea C1-1,%rdi lea D1-1,%rsi mov $C2-C1+2,%rcx repz cmpsb .e "test succeeded": .exit .data // test case 1 .align 64 .byte 0 .align 64 A1: .ascii "hello world!" A2: .align 64 B1: .ascii "hellhellhell" B2: .byte 0 .align 64 // test case 2 .align 64 .byte 0 .align 64 C1: .ascii "hello world!" C2: .align 64 D1: .ascii "ld!ld!ld!ld!" D2: .byte 0 .align 64 ================================================ FILE: test/asm/rol.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // left rotate (rol) example // make -j8 o//blink o//test/asm/rol.elf // o//blink/blinkenlights o//test/asm/rol.elf .test "rol1" stc mov $1,%eax rol $0,%eax .c cmp $1,%eax .e .test "rol2" clc mov $1,%eax rol $0,%eax .nc .no cmp $1,%eax .e .test "rol3" clc mov $0x0000000080000000,%rax mov $1,%cl rol %cl,%rax .nc .no mov $0x0000000100000000,%rcx cmp %rcx,%rax .e .test "rol4" clc mov $0x0000000080000000,%rax rol %rax .nc .no mov $0x0000000100000000,%rcx cmp %rcx,%rax .e .test "rol5" mov $1,%eax rol $1,%eax .nc .no cmp $2,%eax .e .test "rol 32-bit by 1" mov $0x8000000080000000,%rax rol %eax .c .o mov $0x0000000000000001,%rcx cmp %rcx,%rax .e .test "rol 16-bit doesn't zero extend" mov $0x8000000000008000,%rax rol %ax .c .o mov $0x8000000000000001,%rcx cmp %rcx,%rax .e .test "rol 8-bit doesn't zero extend" mov $0x8000000000000080,%rax rol %al .c .o mov $0x8000000000000001,%rcx cmp %rcx,%rax .e .test "rol 8-bit hi register" mov $0x8000000000008007,%rax rol %ah .c .o mov $0x8000000000000107,%rcx cmp %rcx,%rax .e .test "rol 8-bit rex register" mov $0x8000000000000080,%rdi rol %dil .c .o mov $0x8000000000000001,%rcx cmp %rcx,%rdi .e .test "rolq by 2" mov $0b1000000000000000000000000000000000000000000000001000000000000111,%rax rol $2,%rax .nc mov $0b0000000000000000000000000000000000000000000000100000000000011110,%rcx cmp %rcx,%rax .e .test "rolq by 2 carry" mov $0b0100000000000000000000000000000000000000000000001000000000000111,%rax rol $2,%rax .c mov $0b0000000000000000000000000000000000000000000000100000000000011101,%rcx cmp %rcx,%rax .e .test "rol64imm(1,1) == 2" mov $1,%rax rol $1,%rax cmp $2,%rax .e .test "rol32imm(0x1234ul<<32|(u32)INT_MIN,1) == 1" mov $0x123480000000,%rax rol $1,%eax cmp $1,%rax .e .test "rol32(0x1234ul<<32|(u32)INT_MIN,0x1234ul<<32|(u32)1) == 1" mov $0x123480000000,%rax mov $0x123400000001,%rcx rol %cl,%eax cmp $1,%rax .e mov $0x123400000001,%rax cmp %rax,%rcx .e .test "prepare for rol flags test" mov $0x7fffffff,%eax add $4,%eax .sop .test "rol32 doesn't change flags if count is zero (imm)" rol $0,%eax .sop .test "If the masked count is 0, the flags are not affected (32-bit imm)" rol $0xffffffe0,%eax .sop .test "If the masked count is 0, the flags are not affected (16-bit imm)" rol $0xffffffe0,%ax .sop .test "If the masked count is 0, the flags are not affected (8-bit imm)" rol $0xffffffe0,%ax .sop .test "rol32 doesn't change flags if count is zero (cl)" mov $0,%cl rol %cl,%eax .sop .test "rol16 doesn't change flags if count is zero (imm)" rol $0,%ax .sop .test "rol16 doesn't change flags if count is zero (cl)" mov $0,%cl rol %cl,%ax .sop .test "rol8 doesn't change flags if count is zero (imm)" rol $0,%al .sop .test "rol8 doesn't change flags if count is zero (cl)" mov $0,%cl rol %cl,%al .sop .test "rolb doesn't change flags if count is zero (mem imm)" rolb $0,(%rsp) .sop .test "rolw doesn't change flags if count is zero (mem imm)" rolw $0,(%rsp) .sop .test "roll doesn't change flags if count is zero (mem imm)" roll $0,(%rsp) .sop .test "rolq doesn't change flags if count is zero (mem imm)" rolq $0,(%rsp) .sop "test succeeded": .exit ================================================ FILE: test/asm/rorx.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $10,%r15 "test jit too": // rol w/o flags // make -j8 o//blink o//test/asm/rorx.elf // o//blink/blinkenlights o//test/asm/rorx.elf mov $7,%eax # extended features xor %ecx,%ecx cpuid bt $8,%ebx # bmi2 jnc "test not possible" .test "rorx 1" stc mov $0xf0000fff,%eax # input value mov $0x31337133,%ebx # random data rorx $4*2,%eax,%ebx .c cmp $0xf0000fff,%eax # unchanged .e cmp $0xfff0000f,%ebx # output value .e .test "rorx $0 does nothing" stc mov $0xf0000fff,%eax # input value mov $0x31337133,%ebx # random data rorx $0,%eax,%ebx .c cmp $0xf0000fff,%eax # unchanged .e cmp $0xf0000fff,%ebx # output value .e dec %r15 jnz "test jit too" "test succeeded": .exit "test not possible": .exit ================================================ FILE: test/asm/setcc.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $5,%r15 "test jit too": // condition code moves // make -j8 o//blink o//test/asm/setcc.elf // o//blink/blinkenlights o//test/asm/setcc.elf .test "set carry reg true" or $-1,%eax stc setc %al cmp $1,%al .e .test "set carry reg false" or $-1,%eax clc setc %ah cmp $0,%ah .e .test "set carry reg doesn't extend" or $-1,%eax stc setc %al cmp $0xffffff01,%eax .e .test "set carry mem" movl $-1,(%rsp) stc setc (%rsp) cmpl $0xffffff01,(%rsp) .e .test "set carry reg true r14" stc setc %r14b cmp $1,%r14b .e sub $1,%r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/asm/shufpd.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $3,%r15 "test jit too": // packed interleave shuffle of pairs of double floats // make -j8 o//blink o//test/asm/shufpd.elf // o//blink/blinkenlights o//test/asm/shufpd.elf .test "shufpd $1 A==B" movaps A,%xmm0 shufpd $1,%xmm0,%xmm0 movq %xmm0,%rax # test lower half cmp %rax,B+0 .e punpckhqdq %xmm0,%xmm0 # test upper half movq %xmm0,%rax cmp %rax,B+8 .e dec %r15 jnz "test jit too" "test succeeded": .exit .section .rodata .align 16 A: .quad 1,2 B: .quad 2,1 ================================================ FILE: test/asm/shx.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $10,%r15 "test jit too": // sarx/shlx/shrx -- shift w/o flags // make -j8 o//blink o//test/asm/shx.elf // o//blink/blinkenlights o//test/asm/shx.elf mov $7,%eax # extended features xor %ecx,%ecx cpuid bt $8,%ebx # bmi2 jnc "test not possible" .test "shlx 1" stc mov $0xf0000fff,%eax # input value mov $0x31337133,%ebx # random data mov $4,%ecx shlx %ecx,%eax,%ebx .c cmp $0xf0000fff,%eax # unchanged .e cmp $0x0000fff0,%ebx # output value .e .test "shrx 1" stc mov $0xf0000fff,%eax # input value mov $0x31337133,%ebx # random data mov $4,%ecx shrx %ecx,%eax,%ebx .c cmp $0xf0000fff,%eax # unchanged .e cmp $0x0f0000ff,%ebx # output value .e .test "sarx 1" stc mov $0xf0000fff,%eax # input value mov $0x31337133,%ebx # random data mov $4,%ecx sarx %ecx,%eax,%ebx .c cmp $0xf0000fff,%eax # unchanged .e cmp $0xff0000ff,%ebx # output value .e dec %r15 jnz "test jit too" "test succeeded": .exit "test not possible": .exit ================================================ FILE: test/asm/ssemov.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $5,%r15 "test jit too": // sse moves // make -j8 o//blink o//test/asm/ssemov.elf // o//blink/blinkenlights o//test/asm/ssemov.elf .test "sse mov unaligned" and $-16,%rsp sub $17,%rsp movdqu onetwo(%rip),%xmm0 movdqu %xmm0,%xmm0 movdqu %xmm0,(%rsp) mov (%rsp),%rax mov 8(%rsp),%rdx mov $0x1111111111111111,%rcx cmp %rcx,%rax .e mov $0x2222222222222222,%rcx cmp %rcx,%rdx .e .test "sse mov aligned" and $-16,%rsp sub $16,%rsp movdqa onetwo(%rip),%xmm9 movdqa %xmm9,%xmm6 movdqa %xmm6,(%rsp) mov (%rsp),%rax mov 8(%rsp),%rdx mov $0x1111111111111111,%rcx cmp %rcx,%rax .e mov $0x2222222222222222,%rcx cmp %rcx,%rdx .e .test "sse mov unaligned #2" and $-16,%rsp sub $16,%rsp movups onetwo(%rip),%xmm9 movups %xmm9,%xmm6 movups %xmm6,(%rsp) mov (%rsp),%rax mov 8(%rsp),%rdx mov $0x1111111111111111,%rcx cmp %rcx,%rax .e mov $0x2222222222222222,%rcx cmp %rcx,%rdx .e sub $1,%r15 jnz "test jit too" "test succeeded": .exit .section .rodata .align 16 onetwo: .quad 0x1111111111111111,0x2222222222222222 ================================================ FILE: test/asm/write.S ================================================ #include "test/asm/mac.inc" .globl _start _start: // exit(0) example // make -j8 o//blink o//test/asm/exit.elf // o//blink/blinkenlights o//test/asm/exit.elf #define SYS_write 1 #define SYS_exit 231 #define EBADF 9 .test "call write(1, msg, len)" mov $1,%edi lea 1f(%rip),%rsi mov $2f-1f,%edx mov $SYS_write,%eax syscall cmp $2f-1f,%rax .e .test "write(-1, 0, 0) -> EBADF" mov $-1,%edi mov $0,%esi mov $0,%edx mov $SYS_write,%eax syscall cmp $-EBADF,%rax .e .test "call exit(0)" mov $0,%edi mov $SYS_exit,%eax syscall 1: .ascii "hello world\n" 2: ================================================ FILE: test/asm/xchg.S ================================================ #include "test/asm/mac.inc" .globl _start _start: mov $3,%r15 "test jit too": // equivalent exchange // make -j8 o//blink o//test/asm/xchg.elf // o//blink/blinkenlights o//test/asm/xchg.elf .test "xchgl reg/reg zero-extends" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx xchg %eax,%ebx mov $0x0000000012345678,%rcx mov $0x0000000055555550,%rdx cmp %rdx,%rax .e cmp %rcx,%rbx .e .test "xchgl mem/reg zero-extends" mov $0x1234567812345678,%rax mov $0x5555555155555550,%rbx mov %rbx,(%rsp) xchg %eax,(%rsp) mov $0x5555555112345678,%rcx mov $0x0000000055555550,%rdx cmp %rdx,%rax .e cmp %rcx,(%rsp) .e dec %r15 jnz "test jit too" "test succeeded": .exit ================================================ FILE: test/blink/disinst_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/dis.h" #include "blink/high.h" #include "blink/modrm.h" #include "test/test.h" #define ILD(OP, MODE) \ ASSERT_EQ(0, DecodeInstruction(d->xedd, OP, sizeof(OP), MODE)) char b1[64]; char b2[64]; struct Dis d[1]; void SetUp(void) { d->notab = true; g_high.enabled = false; } void TearDown(void) { } TEST(DisInst, testInt3) { u8 op[] = {0xcc}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("int3 ", b1); } TEST(DisInst, testImmMem_needsSuffix) { u8 op[] = {0x80, 0x3c, 0x07, 0x00}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("cmpb $0,(%rdi,%rax)", b1); } TEST(DisInst, testImmReg_doesntNeedSuffix) { u8 op[] = {0xb8, 0x08, 0x70, 0x40, 0x00}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("mov $0x407008,%eax", b1); } TEST(DisInst, testPuttingOnTheRiz) { static u8 ops[][15] = { {0x8d, 0b00110100, 0b00100110}, {0x67, 0x8d, 0b00110100, 0b11100110}, {0x67, 0x8d, 0b10110100, 0b11100101, 0, 0, 0, 0}, {0x8d, 0b00110100, 0b11100101, 0x37, 0x13, 0x03, 0}, {0x8d, 0b10110100, 0b11100101, 0, 0, 0, 0}, }; ILD(ops[0], XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("lea (%rsi),%esi", b1); ILD(ops[1], XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("lea (%esi,%eiz,8),%esi", b1); ILD(ops[2], XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("lea 0(%ebp,%eiz,8),%esi", b1); ILD(ops[3], XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("lea 0x31337,%esi", b1); ILD(ops[4], XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("lea 0(%rbp,%riz,8),%esi", b1); } TEST(DisInst, testSibIndexOnly) { u8 op[] = {76, 141, 4, 141, 0, 0, 0, 0}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("lea 0(,%rcx,4),%r8", b1); } #ifndef DISABLE_METAL TEST(DisInst, testRealMode) { u8 op[] = {0x89, 0xe5}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("mov %sp,%bp", b1); } #endif TEST(DisInst, testNop) { u8 op[] = {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("nopw %cs:0(%rax,%rax)", b1); } TEST(DisInst, testJne) { u8 op[] = {0x75, (u8)-24}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("jne -24", b1); } TEST(DisInst, testPush) { u8 op[] = {0x41, 0x5c}; ILD(op, XED_MODE_LONG); EXPECT_EQ(4, ModrmSrm(d->xedd->op.rde)); EXPECT_EQ(1, Rexb(d->xedd->op.rde)); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("pop %r12", b1); } TEST(DisInst, testMovb) { u8 op[] = {0x8a, 0x1e, 0x0c, 0x32}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("mov (%rsi),%bl", b1); #ifndef DISABLE_METAL ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("mov 0x320c,%bl", b1); #endif } #ifndef DISABLE_METAL TEST(DisInst, testLes) { u8 op[] = {0xc4, 0x3e, 0x16, 0x32}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("les 0x3216,%di", b1); } #endif TEST(DisInst, testStosbLong) { u8 op[] = {0xAA}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("stosb %al,(%rdi)", b1); } #ifndef DISABLE_METAL TEST(DisInst, testStosbReal) { u8 op[] = {0xAA}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("stosb %al,(%di)", b1); } #endif #ifndef DISABLE_METAL TEST(DisInst, testStosbLegacy) { u8 op[] = {0xAA}; ILD(op, XED_MODE_LEGACY); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("stosb %al,(%edi)", b1); } #endif TEST(DisInst, testStosbLongAsz) { u8 op[] = {0x67, 0xAA}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("stosb %al,(%edi)", b1); } TEST(DisInst, testAddLong) { u8 op[] = {0x01, 0xff}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("add %edi,%edi", b1); } TEST(DisInst, testAddLegacy) { u8 op[] = {0x01, 0xff}; ILD(op, XED_MODE_LEGACY); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("add %edi,%edi", b1); } #ifndef DISABLE_METAL TEST(DisInst, testAddReal) { u8 op[] = {0x01, 0xff}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("add %di,%di", b1); } #endif TEST(DisInst, testAddLongOsz) { u8 op[] = {0x66, 0x01, 0xff}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("add %di,%di", b1); } TEST(DisInst, testAddLegacyOsz) { u8 op[] = {0x66, 0x01, 0xff}; ILD(op, XED_MODE_LEGACY); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("add %di,%di", b1); } #ifndef DISABLE_METAL TEST(DisInst, testAddRealOsz) { u8 op[] = {0x66, 0x01, 0xff}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("add %edi,%edi", b1); } #endif TEST(DisInst, testFxam) { u8 op[] = {0xd9, 0xe5}; ILD(op, XED_MODE_LONG); ASSERT_EQ(4, ModrmReg(d->xedd->op.rde)); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("fxam ", b1); } #ifndef DISABLE_METAL TEST(DisInst, testOrImmCode16gcc) { u8 op[] = {0x67, 0x81, 0x4c, 0x24, 0x0c, 0x00, 0x0c}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("orw $0xc00,12(%esp)", b1); } #endif TEST(DisInst, testPause) { u8 op[] = {0xf3, 0x90}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("pause ", b1); } #ifndef DISABLE_METAL TEST(DisInst, testJmpEw) { u8 op[] = {0xff, 0xe0}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("jmp *%ax", b1); } #endif #ifndef DISABLE_METAL TEST(DisInst, testJmpEv16) { u8 op[] = {0x66, 0xff, 0xe0}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("jmp *%eax", b1); } #endif #ifndef DISABLE_METAL TEST(DisInst, testJmpEv32) { u8 op[] = {0xff, 0xe0}; ILD(op, XED_MODE_LEGACY); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("jmp *%eax", b1); } #endif TEST(DisInst, testJmpEq) { u8 op[] = {0x66, 0xff, 0xe0}; ILD(op, XED_MODE_LONG); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("jmp *%rax", b1); } #ifndef DISABLE_METAL TEST(DisInst, testMovswSs) { u8 op[] = {0x36, 0xA5}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("movs %ss:(%si),(%di)", b1); } #endif #ifndef DISABLE_METAL TEST(DisInst, testRealModrm_sibOverlap_showsNoDisplacement) { u8 op[] = {0x8b, 0b00100101}; ILD(op, XED_MODE_REAL); DisInst(d, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("mov (%di),%sp", b1); } #endif ================================================ FILE: test/blink/divmul_imul64_test.inc ================================================ /* clang-format off */ M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0x1,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0x80000000,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0x7fffffff,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0x80000001,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0x7ffffffe,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0xffffffff,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0xdeadbeef,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0xb6,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0xb504,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0xb505,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0xb504f334,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0x7fffffffffffffff,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0,0x8000000000000000,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0x1,0,0x1,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0x80000000,0,0x80000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0x7fffffff,0,0x7fffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0x80000001,0,0x80000001,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0x7ffffffe,0,0x7ffffffe,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0xffffffff,0,0xffffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0xdeadbeef,0,0xdeadbeef,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0xb6,0,0xb6,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0xb504,0,0xb504,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0xb505,0,0xb505,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0xb504f334,0,0xb504f334,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0x7fffffffffffffff,0,0x7fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x1,0x8000000000000000,0,0x8000000000000000,0xffffffffffffffff,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0x1,0,0x80000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0x80000000,0,0x4000000000000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0x7fffffff,0,0x3fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0x80000001,0,0x4000000080000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0x7ffffffe,0,0x3fffffff00000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0xffffffff,0,0x7fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0xdeadbeef,0,0x6f56df7780000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0xb6,0,0x5b00000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0xb504,0,0x5a8200000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0xb505,0,0x5a8280000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0xb504f334,0,0x5a82799a00000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0x7fffffffffffffff,0,0xffffffff80000000,0x3fffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000000,0x8000000000000000,0,0,0xffffffffc0000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0x1,0,0x7fffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0x80000000,0,0x3fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0x7fffffff,0,0x3fffffff00000001,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0x80000001,0,0x3fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0x7ffffffe,0,0x3ffffffe80000002,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0xffffffff,0,0x7ffffffe80000001,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0xdeadbeef,0,0x6f56df76a1524111,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0xb6,0,0x5affffff4a,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0xb504,0,0x5a81ffff4afc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0xb505,0,0x5a827fff4afb,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0xb504f334,0,0x5a8279994afb0ccc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0x7fffffffffffffff,0,0x7fffffff80000001,0x3fffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffff,0x8000000000000000,0,0x8000000000000000,0xffffffffc0000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0x1,0,0x80000001,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0x80000000,0,0x4000000080000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0x7fffffff,0,0x3fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0x80000001,0,0x4000000100000001,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0x7ffffffe,0,0x3fffffff7ffffffe,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0xffffffff,0,0x800000007fffffff,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0xdeadbeef,0,0x6f56df785eadbeef,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0xb6,0,0x5b000000b6,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0xb504,0,0x5a820000b504,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0xb505,0,0x5a828000b505,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0xb504f334,0,0x5a82799ab504f334,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0x7fffffffffffffff,0,0x7fffffff7fffffff,0x40000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x80000001,0x8000000000000000,0,0x8000000000000000,0xffffffffbfffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0x1,0,0x7ffffffe,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0x80000000,0,0x3fffffff00000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0x7fffffff,0,0x3ffffffe80000002,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0x80000001,0,0x3fffffff7ffffffe,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0x7ffffffe,0,0x3ffffffe00000004,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0xffffffff,0,0x7ffffffd80000002,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0xdeadbeef,0,0x6f56df75c2a48222,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0xb6,0,0x5afffffe94,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0xb504,0,0x5a81fffe95f8,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0xb505,0,0x5a827ffe95f6,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0xb504f334,0,0x5a82799895f61998,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0x7fffffffffffffff,0,0xffffffff80000002,0x3ffffffe,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7ffffffe,0x8000000000000000,0,0,0xffffffffc0000001,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0x1,0,0xffffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0x80000000,0,0x7fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0x7fffffff,0,0x7ffffffe80000001,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0x80000001,0,0x800000007fffffff,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0x7ffffffe,0,0x7ffffffd80000002,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0xffffffff,0,0xfffffffe00000001,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0xdeadbeef,0,0xdeadbeee21524111,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0xb6,0,0xb5ffffff4a,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0xb504,0,0xb503ffff4afc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0xb505,0,0xb504ffff4afb,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0xb504f334,0,0xb504f3334afb0ccc,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0x7fffffffffffffff,0,0x7fffffff00000001,0x7fffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xffffffff,0x8000000000000000,0,0x8000000000000000,0xffffffff80000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0x1,0,0xdeadbeef,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0x80000000,0,0x6f56df7780000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0x7fffffff,0,0x6f56df76a1524111,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0x80000001,0,0x6f56df785eadbeef,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0x7ffffffe,0,0x6f56df75c2a48222,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0xffffffff,0,0xdeadbeee21524111,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0xdeadbeef,0,0xc1b1cd12216da321,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0xb6,0,0x9e4f85bdea,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0xb504,0,0x9d7452b5f6bc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0xb505,0,0x9d753163b5ab,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0xb504f334,0,0x9d7526421e43a58c,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0x7fffffffffffffff,0,0x7fffffff21524111,0x6f56df77,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xdeadbeef,0x8000000000000000,0,0x8000000000000000,0xffffffff90a92088,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0x1,0,0xb6,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0x80000000,0,0x5b00000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0x7fffffff,0,0x5affffff4a,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0x80000001,0,0x5b000000b6,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0x7ffffffe,0,0x5afffffe94,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0xffffffff,0,0xb5ffffff4a,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0xdeadbeef,0,0x9e4f85bdea,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0xb6,0,0x8164,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0xb504,0,0x80b0d8,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0xb505,0,0x80b18e,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0xb504f334,0,0x80b184e6f8,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0x7fffffffffffffff,0,0xffffffffffffff4a,0x5a,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb6,0x8000000000000000,0,0,0xffffffffffffffa5,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0x1,0,0xb504,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0x80000000,0,0x5a8200000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0x7fffffff,0,0x5a81ffff4afc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0x80000001,0,0x5a820000b504,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0x7ffffffe,0,0x5a81fffe95f8,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0xffffffff,0,0xb503ffff4afc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0xdeadbeef,0,0x9d7452b5f6bc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0xb6,0,0x80b0d8,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0xb504,0,0x7ffea810,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0xb505,0,0x7fff5d14,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0xb504f334,0,0x7fff540790d0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0x7fffffffffffffff,0,0xffffffffffff4afc,0x5a81,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504,0x8000000000000000,0,0,0xffffffffffffa57e,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0x1,0,0xb505,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0x80000000,0,0x5a8280000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0x7fffffff,0,0x5a827fff4afb,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0x80000001,0,0x5a828000b505,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0x7ffffffe,0,0x5a827ffe95f6,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0xffffffff,0,0xb504ffff4afb,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0xdeadbeef,0,0x9d753163b5ab,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0xb6,0,0x80b18e,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0xb504,0,0x7fff5d14,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0xb505,0,0x80001219,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0xb504f334,0,0x8000090c8404,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0x7fffffffffffffff,0,0x7fffffffffff4afb,0x5a82,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb505,0x8000000000000000,0,0x8000000000000000,0xffffffffffffa57d,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0x1,0,0xb504f334,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0x80000000,0,0x5a82799a00000000,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0x7fffffff,0,0x5a8279994afb0ccc,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0x80000001,0,0x5a82799ab504f334,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0x7ffffffe,0,0x5a82799895f61998,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0xffffffff,0,0xb504f3334afb0ccc,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0xdeadbeef,0,0x9d7526421e43a58c,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0xb6,0,0x80b184e6f8,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0xb504,0,0x7fff540790d0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0xb505,0,0x8000090c8404,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0xb504f334,0,0x8000000008abc290,0,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0x7fffffffffffffff,0,0xffffffff4afb0ccc,0x5a827999,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0xb504f334,0x8000000000000000,0,0,0xffffffffa57d8666,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0x1,0,0x7fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0x80000000,0,0xffffffff80000000,0x3fffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0x7fffffff,0,0x7fffffff80000001,0x3fffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0x80000001,0,0x7fffffff7fffffff,0x40000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0x7ffffffe,0,0xffffffff80000002,0x3ffffffe,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0xffffffff,0,0x7fffffff00000001,0x7fffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0xdeadbeef,0,0x7fffffff21524111,0x6f56df77,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0xb6,0,0xffffffffffffff4a,0x5a,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0xb504,0,0xffffffffffff4afc,0x5a81,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0xb505,0,0x7fffffffffff4afb,0x5a82,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0xb504f334,0,0xffffffff4afb0ccc,0x5a827999,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0x7fffffffffffffff,0,0x1,0x3fffffffffffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x7fffffffffffffff,0x8000000000000000,0,0x8000000000000000,0xc000000000000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0,0,0,0,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0x1,0,0x8000000000000000,0xffffffffffffffff,0,0) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0x80000000,0,0,0xffffffffc0000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0x7fffffff,0,0x8000000000000000,0xffffffffc0000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0x80000001,0,0x8000000000000000,0xffffffffbfffffff,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0x7ffffffe,0,0,0xffffffffc0000001,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0xffffffff,0,0x8000000000000000,0xffffffff80000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0xdeadbeef,0,0x8000000000000000,0xffffffff90a92088,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0xb6,0,0,0xffffffffffffffa5,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0xb504,0,0,0xffffffffffffa57e,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0xb505,0,0x8000000000000000,0xffffffffffffa57d,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0xb504f334,0,0,0xffffffffa57d8666,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0x7fffffffffffffff,0,0x8000000000000000,0xc000000000000000,1,1) M(OpMulRdxRaxEvqpSigned,REXW|MOD(3)|RM(CX),0x8000000000000000,0x8000000000000000,0,0,0x4000000000000000,1,1) ================================================ FILE: test/blink/divmul_mul64_test.inc ================================================ /* clang-format off */ M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0x1,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0x80000000,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0x7fffffff,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0x80000001,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0x7ffffffe,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0xffffffff,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0xb6,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0xb504,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0xb505,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0xb504f333,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0xb504f334,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0x7fffffffffffffff,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0,0x8000000000000000,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0x1,0,0x1,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0x80000000,0,0x80000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0x7fffffff,0,0x7fffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0x80000001,0,0x80000001,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0x7ffffffe,0,0x7ffffffe,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0xffffffff,0,0xffffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0xb6,0,0xb6,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0xb504,0,0xb504,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0xb505,0,0xb505,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0xb504f333,0,0xb504f333,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0xb504f334,0,0xb504f334,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0x7fffffffffffffff,0,0x7fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x1,0x8000000000000000,0,0x8000000000000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0x1,0,0x80000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0x80000000,0,0x4000000000000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0x7fffffff,0,0x3fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0x80000001,0,0x4000000080000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0x7ffffffe,0,0x3fffffff00000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0xffffffff,0,0x7fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0xb6,0,0x5b00000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0xb504,0,0x5a8200000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0xb505,0,0x5a8280000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0xb504f333,0,0x5a82799980000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0xb504f334,0,0x5a82799a00000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0x7fffffffffffffff,0,0xffffffff80000000,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000000,0x8000000000000000,0,0,0x40000000,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0x1,0,0x7fffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0x80000000,0,0x3fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0x7fffffff,0,0x3fffffff00000001,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0x80000001,0,0x3fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0x7ffffffe,0,0x3ffffffe80000002,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0xffffffff,0,0x7ffffffe80000001,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0xb6,0,0x5affffff4a,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0xb504,0,0x5a81ffff4afc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0xb505,0,0x5a827fff4afb,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0xb504f333,0,0x5a827998cafb0ccd,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0xb504f334,0,0x5a8279994afb0ccc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0x7fffffffffffffff,0,0x7fffffff80000001,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffff,0x8000000000000000,0,0x8000000000000000,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0x1,0,0x80000001,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0x80000000,0,0x4000000080000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0x7fffffff,0,0x3fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0x80000001,0,0x4000000100000001,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0x7ffffffe,0,0x3fffffff7ffffffe,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0xffffffff,0,0x800000007fffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0xb6,0,0x5b000000b6,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0xb504,0,0x5a820000b504,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0xb505,0,0x5a828000b505,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0xb504f333,0,0x5a82799a3504f333,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0xb504f334,0,0x5a82799ab504f334,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0x7fffffffffffffff,0,0x7fffffff7fffffff,0x40000000,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x80000001,0x8000000000000000,0,0x8000000000000000,0x40000000,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0x1,0,0x7ffffffe,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0x80000000,0,0x3fffffff00000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0x7fffffff,0,0x3ffffffe80000002,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0x80000001,0,0x3fffffff7ffffffe,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0x7ffffffe,0,0x3ffffffe00000004,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0xffffffff,0,0x7ffffffd80000002,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0xb6,0,0x5afffffe94,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0xb504,0,0x5a81fffe95f8,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0xb505,0,0x5a827ffe95f6,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0xb504f333,0,0x5a82799815f6199a,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0xb504f334,0,0x5a82799895f61998,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0x7fffffffffffffff,0,0xffffffff80000002,0x3ffffffe,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7ffffffe,0x8000000000000000,0,0,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0x1,0,0xffffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0x80000000,0,0x7fffffff80000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0x7fffffff,0,0x7ffffffe80000001,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0x80000001,0,0x800000007fffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0x7ffffffe,0,0x7ffffffd80000002,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0xffffffff,0,0xfffffffe00000001,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0xb6,0,0xb5ffffff4a,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0xb504,0,0xb503ffff4afc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0xb505,0,0xb504ffff4afb,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0xb504f333,0,0xb504f3324afb0ccd,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0xb504f334,0,0xb504f3334afb0ccc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0x7fffffffffffffff,0,0x7fffffff00000001,0x7fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xffffffff,0x8000000000000000,0,0x8000000000000000,0x7fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0x1,0,0xb6,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0x80000000,0,0x5b00000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0x7fffffff,0,0x5affffff4a,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0x80000001,0,0x5b000000b6,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0x7ffffffe,0,0x5afffffe94,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0xffffffff,0,0xb5ffffff4a,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0xb6,0,0x8164,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0xb504,0,0x80b0d8,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0xb505,0,0x80b18e,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0xb504f333,0,0x80b184e642,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0xb504f334,0,0x80b184e6f8,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0x7fffffffffffffff,0,0xffffffffffffff4a,0x5a,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb6,0x8000000000000000,0,0,0x5b,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0x1,0,0xb504,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0x80000000,0,0x5a8200000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0x7fffffff,0,0x5a81ffff4afc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0x80000001,0,0x5a820000b504,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0x7ffffffe,0,0x5a81fffe95f8,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0xffffffff,0,0xb503ffff4afc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0xb6,0,0x80b0d8,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0xb504,0,0x7ffea810,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0xb505,0,0x7fff5d14,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0xb504f333,0,0x7fff5406dbcc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0xb504f334,0,0x7fff540790d0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0x7fffffffffffffff,0,0xffffffffffff4afc,0x5a81,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504,0x8000000000000000,0,0,0x5a82,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0x1,0,0xb505,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0x80000000,0,0x5a8280000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0x7fffffff,0,0x5a827fff4afb,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0x80000001,0,0x5a828000b505,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0x7ffffffe,0,0x5a827ffe95f6,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0xffffffff,0,0xb504ffff4afb,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0xb6,0,0x80b18e,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0xb504,0,0x7fff5d14,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0xb505,0,0x80001219,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0xb504f333,0,0x8000090bceff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0xb504f334,0,0x8000090c8404,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0x7fffffffffffffff,0,0x7fffffffffff4afb,0x5a82,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb505,0x8000000000000000,0,0x8000000000000000,0x5a82,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0x1,0,0xb504f333,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0x80000000,0,0x5a82799980000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0x7fffffff,0,0x5a827998cafb0ccd,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0x80000001,0,0x5a82799a3504f333,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0x7ffffffe,0,0x5a82799815f6199a,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0xffffffff,0,0xb504f3324afb0ccd,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0xb6,0,0x80b184e642,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0xb504,0,0x7fff5406dbcc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0xb505,0,0x8000090bceff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0xb504f333,0,0x7ffffffe9ea1dc29,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0xb504f334,0,0x7fffffff53a6cf5c,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0x7fffffffffffffff,0,0x7fffffff4afb0ccd,0x5a827999,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f333,0x8000000000000000,0,0x8000000000000000,0x5a827999,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0x1,0,0xb504f334,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0x80000000,0,0x5a82799a00000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0x7fffffff,0,0x5a8279994afb0ccc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0x80000001,0,0x5a82799ab504f334,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0x7ffffffe,0,0x5a82799895f61998,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0xffffffff,0,0xb504f3334afb0ccc,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0xb6,0,0x80b184e6f8,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0xb504,0,0x7fff540790d0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0xb505,0,0x8000090c8404,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0xb504f333,0,0x7fffffff53a6cf5c,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0xb504f334,0,0x8000000008abc290,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0x7fffffffffffffff,0,0xffffffff4afb0ccc,0x5a827999,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0xb504f334,0x8000000000000000,0,0,0x5a82799a,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0x1,0,0x7fffffffffffffff,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0x80000000,0,0xffffffff80000000,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0x7fffffff,0,0x7fffffff80000001,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0x80000001,0,0x7fffffff7fffffff,0x40000000,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0x7ffffffe,0,0xffffffff80000002,0x3ffffffe,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0xffffffff,0,0x7fffffff00000001,0x7fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0xb6,0,0xffffffffffffff4a,0x5a,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0xb504,0,0xffffffffffff4afc,0x5a81,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0xb505,0,0x7fffffffffff4afb,0x5a82,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0xb504f333,0,0x7fffffff4afb0ccd,0x5a827999,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0xb504f334,0,0xffffffff4afb0ccc,0x5a827999,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0x7fffffffffffffff,0,0x1,0x3fffffffffffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x7fffffffffffffff,0x8000000000000000,0,0x8000000000000000,0x3fffffffffffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0,0,0,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0x1,0,0x8000000000000000,0,0,0) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0x80000000,0,0,0x40000000,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0x7fffffff,0,0x8000000000000000,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0x80000001,0,0x8000000000000000,0x40000000,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0x7ffffffe,0,0,0x3fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0xffffffff,0,0x8000000000000000,0x7fffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0xb6,0,0,0x5b,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0xb504,0,0,0x5a82,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0xb505,0,0x8000000000000000,0x5a82,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0xb504f333,0,0x8000000000000000,0x5a827999,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0xb504f334,0,0,0x5a82799a,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0x7fffffffffffffff,0,0x8000000000000000,0x3fffffffffffffff,1,1) M(OpMulRdxRaxEvqpUnsigned,REXW | MOD(3) | RM(CX),0x8000000000000000,0x8000000000000000,0,0,0x4000000000000000,1,1) ================================================ FILE: test/blink/divmul_mul8_test.inc ================================================ /* clang-format off */ M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0x1,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0x80,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0x7f,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0x81,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0x7e,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0xff,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0,0xb6,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0x1,0,0x1,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0x80,0,0x80,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0x7f,0,0x7f,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0x81,0,0x81,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0x7e,0,0x7e,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0xff,0,0xff,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x1,0xb6,0,0xb6,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0x1,0,0x80,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0x80,0,0x4000,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0x7f,0,0x3f80,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0x81,0,0x4080,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0x7e,0,0x3f00,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0xff,0,0x7f80,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x80,0xb6,0,0x5b00,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0x1,0,0x7f,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0x80,0,0x3f80,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0x7f,0,0x3f01,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0x81,0,0x3fff,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0x7e,0,0x3e82,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0xff,0,0x7e81,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7f,0xb6,0,0x5a4a,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0x1,0,0x81,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0x80,0,0x4080,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0x7f,0,0x3fff,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0x81,0,0x4101,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0x7e,0,0x3f7e,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0xff,0,0x807f,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x81,0xb6,0,0x5bb6,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0x1,0,0x7e,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0x80,0,0x3f00,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0x7f,0,0x3e82,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0x81,0,0x3f7e,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0x7e,0,0x3e04,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0xff,0,0x7d82,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0x7e,0xb6,0,0x5994,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0x1,0,0xff,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0x80,0,0x7f80,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0x7f,0,0x7e81,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0x81,0,0x807f,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0x7e,0,0x7d82,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0xff,0,0xfe01,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xff,0xb6,0,0xb54a,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0,0,0,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0x1,0,0xb6,0,0,0) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0x80,0,0x5b00,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0x7f,0,0x5a4a,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0x81,0,0x5bb6,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0x7e,0,0x5994,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0xff,0,0xb54a,0,1,1) M(OpMulAxAlEbUnsigned,MOD(3)|RM(CX),0xb6,0xb6,0,0x8164,0,1,1) ================================================ FILE: test/blink/divmul_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/endian.h" #include "blink/flags.h" #include "blink/macros.h" #include "test/test.h" #define CX 1 #define OSZ 00000000040 #define REXW 00000000100 #define RM(x) (0000001600 & ((x) << 007)) #define MOD(x) (0060000000 & ((x) << 026)) struct Machine m[1]; struct { const char *name; void (*f)(P); u64 rde; u64 ax; u64 cx; u64 dx; u64 out_ax; u64 out_dx; bool out_cf; bool out_of; } kVector[] = { #define M(f, m, a, c, d, oa, od, cf, of) {#f, f, m, a, c, d, oa, od, cf, of}, #include "test/blink/divmul_imul64_test.inc" #include "test/blink/divmul_mul64_test.inc" #include "test/blink/divmul_mul8_test.inc" }; void SetUp(void) { } void TearDown(void) { } TEST(divmul, test) { int i; for (i = 0; i < ARRAYLEN(kVector); ++i) { Write64(m->ax, kVector[i].ax); Write64(m->cx, kVector[i].cx); Write64(m->dx, kVector[i].dx); kVector[i].f(m, kVector[i].rde, 0, 0); ASSERT_EQ(kVector[i].out_ax, Read64(m->ax), "%d: %s", i, kVector[i].name); ASSERT_EQ(kVector[i].out_dx, Read64(m->dx), "%d: %s", i, kVector[i].name); ASSERT_EQ(kVector[i].out_cf, GetFlag(m->flags, FLAGS_CF), "%d: %s", i, kVector[i].name); ASSERT_EQ(kVector[i].out_of, GetFlag(m->flags, FLAGS_OF), "%d: %s", i, kVector[i].name); } } ================================================ FILE: test/blink/ldbl_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include "blink/ldbl.h" #include "test/test.h" void SetUp(void) { } void TearDown(void) { } double RoundTrip(double x) { uint8_t b[10]; return DeserializeLdbl(SerializeLdbl(b, x)); } TEST(SerializeLdbl, testRoundTrip) { EXPECT_STREQ("0", Format("%g", RoundTrip(0))); EXPECT_STREQ("-0", Format("%g", RoundTrip(-0.))); EXPECT_STREQ("nan", Format("%g", RoundTrip(NAN))); EXPECT_STREQ("inf", Format("%g", RoundTrip(INFINITY))); EXPECT_STREQ("-inf", Format("%g", RoundTrip(-INFINITY))); EXPECT_STREQ(Format("%.17g", DBL_MIN), Format("%.17g", RoundTrip(DBL_MIN))); EXPECT_STREQ(Format("%.17g", DBL_MAX), Format("%.17g", RoundTrip(DBL_MAX))); // TODO(jart): What's up with Apple Silicon here? // EXPECT_STREQ("-nan", Format("%g", RoundTrip(-NAN))); } ================================================ FILE: test/blink/modrm_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/assert.h" #include "blink/endian.h" #include "blink/machine.h" #include "blink/map.h" #include "blink/modrm.h" #include "blink/x86.h" #include "test/test.h" struct System *s; struct Machine *m; struct XedDecodedInst xedd; void SetUp(void) { InitMap(); unassert((s = NewSystem(XED_MACHINE_MODE_LONG))); unassert((m = NewMachine(s, 0))); m->xedd = &xedd; memset(&xedd, 0, sizeof(xedd)); } void TearDown(void) { FreeMachine(m); } TEST(modrm, testAddressSizeOverride_isNotPresent_keepsWholeExpression) { uint8_t op[] = {0x8d, 0x04, 0x03}; /* lea (%rbx,%rax,1),%eax */ Write64(m->bx, 0x2); Write64(m->ax, 0xffffffff); ASSERT_EQ(0, DecodeInstruction(m->xedd, op, sizeof(op), XED_MODE_LONG)); EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); } TEST(modrm, testAddressSizeOverride_isPresent_modulesWholeExpression) { uint8_t op[] = {0x67, 0x8d, 0x04, 0x03}; /* lea (%ebx,%eax,1),%eax */ Write64(m->bx, 0x2); Write64(m->ax, 0xffffffff); ASSERT_EQ(0, DecodeInstruction(m->xedd, op, sizeof(op), XED_MODE_LONG)); EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); } TEST(modrm, testOverflow_doesntTriggerTooling) { uint8_t op[] = {0x8d, 0x04, 0x03}; /* lea (%rbx,%rax,1),%eax */ Write64(m->bx, 0x0000000000000001); Write64(m->ax, 0x7fffffffffffffff); ASSERT_EQ(0, DecodeInstruction(m->xedd, op, sizeof(op), XED_MODE_LONG)); EXPECT_EQ(0x8000000000000000ull, (uint64_t)ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); } TEST(modrm, testPuttingOnTheRiz) { static uint8_t op[][15] = { {0x8d, 0b00110100, 0b00100110}, // lea (%rsi),%esi {0x67, 0x8d, 0b00110100, 0b11100110}, // lea (%esi,%eiz,8),%esi {103, 141, 180, 229, 55, 19, 3, 0}, // lea 0x31337(%ebp,%eiz,8),%esi {141, 52, 229, 55, 19, 3, 0}, // lea 0x31337,%esi }; Write64(m->si, 0x100000001); Write64(m->bp, 0x200000002); ASSERT_EQ(0, DecodeInstruction(m->xedd, op[0], sizeof(op[0]), XED_MODE_LONG)); EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); ASSERT_EQ(0, DecodeInstruction(m->xedd, op[1], sizeof(op[1]), XED_MODE_LONG)); EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); ASSERT_EQ(0, DecodeInstruction(m->xedd, op[2], sizeof(op[2]), XED_MODE_LONG)); EXPECT_EQ(0x31339, ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); ASSERT_EQ(0, DecodeInstruction(m->xedd, op[3], sizeof(op[3]), XED_MODE_LONG)); EXPECT_EQ(0x31337, ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); } TEST(modrm, testSibIndexOnly) { // lea 0x0(,%rcx,4),%r8 // mod = 0b00 (0) // reg = 0b000 (0) // rm = 0b100 (4) // scale = 0b10 (2) // index = 0b001 (1) // base = 0b101 (5) uint8_t op[] = {0x4c, 0x8d, 0x04, 0x8d, 0, 0, 0, 0}; Write64(m->bp, 0x123); Write64(m->cx, 0x123); ASSERT_EQ(0, DecodeInstruction(m->xedd, op, sizeof(op), XED_MODE_LONG)); EXPECT_TRUE(Rexw(m->xedd->op.rde)); EXPECT_TRUE(Rexr(m->xedd->op.rde)); EXPECT_FALSE(Rexb(m->xedd->op.rde)); EXPECT_EQ(0b000, ModrmReg(m->xedd->op.rde)); EXPECT_EQ(0b100, ModrmRm(m->xedd->op.rde)); EXPECT_EQ(0x123 * 4, (uint64_t)ComputeAddress(m, m->xedd->op.rde, m->xedd->op.disp, m->xedd->op.uimm0)); } ================================================ FILE: test/blink/test.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ PKGS += TEST_BLINK TEST_BLINK_FILES := $(wildcard test/blink/*) TEST_BLINK_SRCS = $(filter %.c,$(TEST_BLINK_FILES)) TEST_BLINK_HDRS = $(filter %.h,$(TEST_BLINK_FILES)) TEST_BLINK_OBJS = $(TEST_BLINK_SRCS:%.c=o/$(MODE)/%.o) # this file takes a minute to compile on raspi using -O2 o/$(MODE)/test/blink/x86_test.o \ o/$(MODE)/i486/test/blink/x86_test.o \ o/$(MODE)/m68k/test/blink/x86_test.o \ o/$(MODE)/x86_64/test/blink/x86_test.o \ o/$(MODE)/x86_64-gcc49/test/blink/x86_test.o \ o/$(MODE)/arm/test/blink/x86_test.o \ o/$(MODE)/aarch64/test/blink/x86_test.o \ o/$(MODE)/riscv64/test/blink/x86_test.o \ o/$(MODE)/mips/test/blink/x86_test.o \ o/$(MODE)/mipsel/test/blink/x86_test.o \ o/$(MODE)/mips64/test/blink/x86_test.o \ o/$(MODE)/mips64el/test/blink/x86_test.o \ o/$(MODE)/s390x/test/blink/x86_test.o \ o/$(MODE)/powerpc/test/blink/x86_test.o \ o/$(MODE)/powerpc64le/test/blink/x86_test.o: \ private CFLAGS += -O0 o/$(MODE)/test/blink/divmul_test.com: o/$(MODE)/test/blink/divmul_test.o o/$(MODE)/blink/blink.a $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/i486/test/blink/divmul_test.com: o/$(MODE)/i486/test/blink/divmul_test.o o/$(MODE)/i486/blink/blink.a o/third_party/gcc/i486/bin/i486-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/m68k/test/blink/divmul_test.com: o/$(MODE)/m68k/test/blink/divmul_test.o o/$(MODE)/m68k/blink/blink.a o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64/test/blink/divmul_test.com: o/$(MODE)/x86_64/test/blink/divmul_test.o o/$(MODE)/x86_64/blink/blink.a o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64-gcc49/test/blink/divmul_test.com: o/$(MODE)/x86_64-gcc49/test/blink/divmul_test.o o/$(MODE)/x86_64-gcc49/blink/blink.a o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/arm/test/blink/divmul_test.com: o/$(MODE)/arm/test/blink/divmul_test.o o/$(MODE)/arm/blink/blink.a o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/aarch64/test/blink/divmul_test.com: o/$(MODE)/aarch64/test/blink/divmul_test.o o/$(MODE)/aarch64/blink/blink.a o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/riscv64/test/blink/divmul_test.com: o/$(MODE)/riscv64/test/blink/divmul_test.o o/$(MODE)/riscv64/blink/blink.a o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips/test/blink/divmul_test.com: o/$(MODE)/mips/test/blink/divmul_test.o o/$(MODE)/mips/blink/blink.a o/third_party/gcc/mips/bin/mips-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mipsel/test/blink/divmul_test.com: o/$(MODE)/mipsel/test/blink/divmul_test.o o/$(MODE)/mipsel/blink/blink.a o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64/test/blink/divmul_test.com: o/$(MODE)/mips64/test/blink/divmul_test.o o/$(MODE)/mips64/blink/blink.a o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64el/test/blink/divmul_test.com: o/$(MODE)/mips64el/test/blink/divmul_test.o o/$(MODE)/mips64el/blink/blink.a o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/s390x/test/blink/divmul_test.com: o/$(MODE)/s390x/test/blink/divmul_test.o o/$(MODE)/s390x/blink/blink.a o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc/test/blink/divmul_test.com: o/$(MODE)/powerpc/test/blink/divmul_test.o o/$(MODE)/powerpc/blink/blink.a o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc64le/test/blink/divmul_test.com: o/$(MODE)/powerpc64le/test/blink/divmul_test.o o/$(MODE)/powerpc64le/blink/blink.a o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/test/blink/modrm_test.com: o/$(MODE)/test/blink/modrm_test.o o/$(MODE)/blink/blink.a $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/i486/test/blink/modrm_test.com: o/$(MODE)/i486/test/blink/modrm_test.o o/$(MODE)/i486/blink/blink.a o/third_party/gcc/i486/bin/i486-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/m68k/test/blink/modrm_test.com: o/$(MODE)/m68k/test/blink/modrm_test.o o/$(MODE)/m68k/blink/blink.a o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64/test/blink/modrm_test.com: o/$(MODE)/x86_64/test/blink/modrm_test.o o/$(MODE)/x86_64/blink/blink.a o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64-gcc49/test/blink/modrm_test.com: o/$(MODE)/x86_64-gcc49/test/blink/modrm_test.o o/$(MODE)/x86_64-gcc49/blink/blink.a o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/arm/test/blink/modrm_test.com: o/$(MODE)/arm/test/blink/modrm_test.o o/$(MODE)/arm/blink/blink.a o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/aarch64/test/blink/modrm_test.com: o/$(MODE)/aarch64/test/blink/modrm_test.o o/$(MODE)/aarch64/blink/blink.a o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/riscv64/test/blink/modrm_test.com: o/$(MODE)/riscv64/test/blink/modrm_test.o o/$(MODE)/riscv64/blink/blink.a o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips/test/blink/modrm_test.com: o/$(MODE)/mips/test/blink/modrm_test.o o/$(MODE)/mips/blink/blink.a o/third_party/gcc/mips/bin/mips-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mipsel/test/blink/modrm_test.com: o/$(MODE)/mipsel/test/blink/modrm_test.o o/$(MODE)/mipsel/blink/blink.a o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64/test/blink/modrm_test.com: o/$(MODE)/mips64/test/blink/modrm_test.o o/$(MODE)/mips64/blink/blink.a o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64el/test/blink/modrm_test.com: o/$(MODE)/mips64el/test/blink/modrm_test.o o/$(MODE)/mips64el/blink/blink.a o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/s390x/test/blink/modrm_test.com: o/$(MODE)/s390x/test/blink/modrm_test.o o/$(MODE)/s390x/blink/blink.a o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc/test/blink/modrm_test.com: o/$(MODE)/powerpc/test/blink/modrm_test.o o/$(MODE)/powerpc/blink/blink.a o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc64le/test/blink/modrm_test.com: o/$(MODE)/powerpc64le/test/blink/modrm_test.o o/$(MODE)/powerpc64le/blink/blink.a o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/test/blink/x86_test.com: o/$(MODE)/test/blink/x86_test.o o/$(MODE)/blink/blink.a $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/i486/test/blink/x86_test.com: o/$(MODE)/i486/test/blink/x86_test.o o/$(MODE)/i486/blink/blink.a o/third_party/gcc/i486/bin/i486-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/m68k/test/blink/x86_test.com: o/$(MODE)/m68k/test/blink/x86_test.o o/$(MODE)/m68k/blink/blink.a o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64/test/blink/x86_test.com: o/$(MODE)/x86_64/test/blink/x86_test.o o/$(MODE)/x86_64/blink/blink.a o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64-gcc49/test/blink/x86_test.com: o/$(MODE)/x86_64-gcc49/test/blink/x86_test.o o/$(MODE)/x86_64-gcc49/blink/blink.a o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/arm/test/blink/x86_test.com: o/$(MODE)/arm/test/blink/x86_test.o o/$(MODE)/arm/blink/blink.a o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/aarch64/test/blink/x86_test.com: o/$(MODE)/aarch64/test/blink/x86_test.o o/$(MODE)/aarch64/blink/blink.a o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/riscv64/test/blink/x86_test.com: o/$(MODE)/riscv64/test/blink/x86_test.o o/$(MODE)/riscv64/blink/blink.a o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips/test/blink/x86_test.com: o/$(MODE)/mips/test/blink/x86_test.o o/$(MODE)/mips/blink/blink.a o/third_party/gcc/mips/bin/mips-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mipsel/test/blink/x86_test.com: o/$(MODE)/mipsel/test/blink/x86_test.o o/$(MODE)/mipsel/blink/blink.a o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64/test/blink/x86_test.com: o/$(MODE)/mips64/test/blink/x86_test.o o/$(MODE)/mips64/blink/blink.a o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64el/test/blink/x86_test.com: o/$(MODE)/mips64el/test/blink/x86_test.o o/$(MODE)/mips64el/blink/blink.a o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/s390x/test/blink/x86_test.com: o/$(MODE)/s390x/test/blink/x86_test.o o/$(MODE)/s390x/blink/blink.a o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc/test/blink/x86_test.com: o/$(MODE)/powerpc/test/blink/x86_test.o o/$(MODE)/powerpc/blink/blink.a o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc64le/test/blink/x86_test.com: o/$(MODE)/powerpc64le/test/blink/x86_test.o o/$(MODE)/powerpc64le/blink/blink.a o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/test/blink/ldbl_test.com: o/$(MODE)/test/blink/ldbl_test.o o/$(MODE)/blink/blink.a $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/i486/test/blink/ldbl_test.com: o/$(MODE)/i486/test/blink/ldbl_test.o o/$(MODE)/i486/blink/blink.a o/third_party/gcc/i486/bin/i486-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/m68k/test/blink/ldbl_test.com: o/$(MODE)/m68k/test/blink/ldbl_test.o o/$(MODE)/m68k/blink/blink.a o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64/test/blink/ldbl_test.com: o/$(MODE)/x86_64/test/blink/ldbl_test.o o/$(MODE)/x86_64/blink/blink.a o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64-gcc49/test/blink/ldbl_test.com: o/$(MODE)/x86_64-gcc49/test/blink/ldbl_test.o o/$(MODE)/x86_64-gcc49/blink/blink.a o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/arm/test/blink/ldbl_test.com: o/$(MODE)/arm/test/blink/ldbl_test.o o/$(MODE)/arm/blink/blink.a o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/aarch64/test/blink/ldbl_test.com: o/$(MODE)/aarch64/test/blink/ldbl_test.o o/$(MODE)/aarch64/blink/blink.a o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/riscv64/test/blink/ldbl_test.com: o/$(MODE)/riscv64/test/blink/ldbl_test.o o/$(MODE)/riscv64/blink/blink.a o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips/test/blink/ldbl_test.com: o/$(MODE)/mips/test/blink/ldbl_test.o o/$(MODE)/mips/blink/blink.a o/third_party/gcc/mips/bin/mips-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mipsel/test/blink/ldbl_test.com: o/$(MODE)/mipsel/test/blink/ldbl_test.o o/$(MODE)/mipsel/blink/blink.a o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64/test/blink/ldbl_test.com: o/$(MODE)/mips64/test/blink/ldbl_test.o o/$(MODE)/mips64/blink/blink.a o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64el/test/blink/ldbl_test.com: o/$(MODE)/mips64el/test/blink/ldbl_test.o o/$(MODE)/mips64el/blink/blink.a o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/s390x/test/blink/ldbl_test.com: o/$(MODE)/s390x/test/blink/ldbl_test.o o/$(MODE)/s390x/blink/blink.a o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc/test/blink/ldbl_test.com: o/$(MODE)/powerpc/test/blink/ldbl_test.o o/$(MODE)/powerpc/blink/blink.a o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc64le/test/blink/ldbl_test.com: o/$(MODE)/powerpc64le/test/blink/ldbl_test.o o/$(MODE)/powerpc64le/blink/blink.a o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/test/blink/disinst_test.com: o/$(MODE)/test/blink/disinst_test.o o/$(MODE)/blink/blink.a $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/i486/test/blink/disinst_test.com: o/$(MODE)/i486/test/blink/disinst_test.o o/$(MODE)/i486/blink/blink.a o/third_party/gcc/i486/bin/i486-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/m68k/test/blink/disinst_test.com: o/$(MODE)/m68k/test/blink/disinst_test.o o/$(MODE)/m68k/blink/blink.a o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64/test/blink/disinst_test.com: o/$(MODE)/x86_64/test/blink/disinst_test.o o/$(MODE)/x86_64/blink/blink.a o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/x86_64-gcc49/test/blink/disinst_test.com: o/$(MODE)/x86_64-gcc49/test/blink/disinst_test.o o/$(MODE)/x86_64-gcc49/blink/blink.a o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/arm/test/blink/disinst_test.com: o/$(MODE)/arm/test/blink/disinst_test.o o/$(MODE)/arm/blink/blink.a o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/aarch64/test/blink/disinst_test.com: o/$(MODE)/aarch64/test/blink/disinst_test.o o/$(MODE)/aarch64/blink/blink.a o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/riscv64/test/blink/disinst_test.com: o/$(MODE)/riscv64/test/blink/disinst_test.o o/$(MODE)/riscv64/blink/blink.a o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips/test/blink/disinst_test.com: o/$(MODE)/mips/test/blink/disinst_test.o o/$(MODE)/mips/blink/blink.a o/third_party/gcc/mips/bin/mips-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mipsel/test/blink/disinst_test.com: o/$(MODE)/mipsel/test/blink/disinst_test.o o/$(MODE)/mipsel/blink/blink.a o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64/test/blink/disinst_test.com: o/$(MODE)/mips64/test/blink/disinst_test.o o/$(MODE)/mips64/blink/blink.a o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/mips64el/test/blink/disinst_test.com: o/$(MODE)/mips64el/test/blink/disinst_test.o o/$(MODE)/mips64el/blink/blink.a o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/s390x/test/blink/disinst_test.com: o/$(MODE)/s390x/test/blink/disinst_test.o o/$(MODE)/s390x/blink/blink.a o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc/test/blink/disinst_test.com: o/$(MODE)/powerpc/test/blink/disinst_test.o o/$(MODE)/powerpc/blink/blink.a o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/powerpc64le/test/blink/disinst_test.com: o/$(MODE)/powerpc64le/test/blink/disinst_test.o o/$(MODE)/powerpc64le/blink/blink.a o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc -static $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@ o/$(MODE)/test/blink: \ $(TEST_BLINK_OBJS) \ o/$(MODE)/test/blink/divmul_test.com.runs \ o/$(MODE)/test/blink/modrm_test.com.runs \ o/$(MODE)/test/blink/x86_test.com.runs \ o/$(MODE)/test/blink/ldbl_test.com.runs \ o/$(MODE)/test/blink/disinst_test.com.runs o/$(MODE)/test/blink/emulates: \ o/$(MODE)/blink/blink \ o/$(MODE)/i486/blink/blink \ o/$(MODE)/m68k/blink/blink \ o/$(MODE)/x86_64/blink/blink \ o/$(MODE)/arm/blink/blink \ o/$(MODE)/aarch64/blink/blink \ o/$(MODE)/riscv64/blink/blink \ o/$(MODE)/mips/blink/blink \ o/$(MODE)/mipsel/blink/blink \ o/$(MODE)/mips64/blink/blink \ o/$(MODE)/mips64el/blink/blink \ o/$(MODE)/s390x/blink/blink \ o/$(MODE)/powerpc/blink/blink \ o/$(MODE)/powerpc64le/blink/blink \ o/$(MODE)/blink/blink \ o/$(MODE)/i486/blink/blink \ o/$(MODE)/m68k/blink/blink \ o/$(MODE)/x86_64/blink/blink \ o/$(MODE)/arm/blink/blink \ o/$(MODE)/aarch64/blink/blink \ o/$(MODE)/riscv64/blink/blink \ o/$(MODE)/mips/blink/blink \ o/$(MODE)/mipsel/blink/blink \ o/$(MODE)/mips64/blink/blink \ o/$(MODE)/mips64el/blink/blink \ o/$(MODE)/s390x/blink/blink \ o/$(MODE)/powerpc/blink/blink \ o/$(MODE)/powerpc64le/blink/blink \ o/$(MODE)/i486/test/blink/divmul_test.com.runs \ o/$(MODE)/m68k/test/blink/divmul_test.com.runs \ o/$(MODE)/x86_64/test/blink/divmul_test.com.runs \ o/$(MODE)/arm/test/blink/divmul_test.com.runs \ o/$(MODE)/aarch64/test/blink/divmul_test.com.runs \ o/$(MODE)/riscv64/test/blink/divmul_test.com.runs \ o/$(MODE)/mips/test/blink/divmul_test.com.runs \ o/$(MODE)/mipsel/test/blink/divmul_test.com.runs \ o/$(MODE)/mips64/test/blink/divmul_test.com.runs \ o/$(MODE)/mips64el/test/blink/divmul_test.com.runs \ o/$(MODE)/s390x/test/blink/divmul_test.com.runs \ o/$(MODE)/powerpc/test/blink/divmul_test.com.runs \ o/$(MODE)/powerpc64le/test/blink/divmul_test.com.runs \ o/$(MODE)/i486/test/blink/modrm_test.com.runs \ o/$(MODE)/m68k/test/blink/modrm_test.com.runs \ o/$(MODE)/x86_64/test/blink/modrm_test.com.runs \ o/$(MODE)/arm/test/blink/modrm_test.com.runs \ o/$(MODE)/aarch64/test/blink/modrm_test.com.runs \ o/$(MODE)/riscv64/test/blink/modrm_test.com.runs \ o/$(MODE)/mips/test/blink/modrm_test.com.runs \ o/$(MODE)/mipsel/test/blink/modrm_test.com.runs \ o/$(MODE)/mips64/test/blink/modrm_test.com.runs \ o/$(MODE)/mips64el/test/blink/modrm_test.com.runs \ o/$(MODE)/s390x/test/blink/modrm_test.com.runs \ o/$(MODE)/powerpc/test/blink/modrm_test.com.runs \ o/$(MODE)/powerpc64le/test/blink/modrm_test.com.runs \ o/$(MODE)/i486/test/blink/x86_test.com.runs \ o/$(MODE)/m68k/test/blink/x86_test.com.runs \ o/$(MODE)/x86_64/test/blink/x86_test.com.runs \ o/$(MODE)/arm/test/blink/x86_test.com.runs \ o/$(MODE)/aarch64/test/blink/x86_test.com.runs \ o/$(MODE)/riscv64/test/blink/x86_test.com.runs \ o/$(MODE)/mips/test/blink/x86_test.com.runs \ o/$(MODE)/mipsel/test/blink/x86_test.com.runs \ o/$(MODE)/mips64/test/blink/x86_test.com.runs \ o/$(MODE)/mips64el/test/blink/x86_test.com.runs \ o/$(MODE)/s390x/test/blink/x86_test.com.runs \ o/$(MODE)/powerpc/test/blink/x86_test.com.runs \ o/$(MODE)/powerpc64le/test/blink/x86_test.com.runs \ o/$(MODE)/i486/test/blink/ldbl_test.com.runs \ o/$(MODE)/m68k/test/blink/ldbl_test.com.runs \ o/$(MODE)/x86_64/test/blink/ldbl_test.com.runs \ o/$(MODE)/arm/test/blink/ldbl_test.com.runs \ o/$(MODE)/aarch64/test/blink/ldbl_test.com.runs \ o/$(MODE)/riscv64/test/blink/ldbl_test.com.runs \ o/$(MODE)/mips/test/blink/ldbl_test.com.runs \ o/$(MODE)/mipsel/test/blink/ldbl_test.com.runs \ o/$(MODE)/mips64/test/blink/ldbl_test.com.runs \ o/$(MODE)/mips64el/test/blink/ldbl_test.com.runs \ o/$(MODE)/s390x/test/blink/ldbl_test.com.runs \ o/$(MODE)/powerpc/test/blink/ldbl_test.com.runs \ o/$(MODE)/powerpc64le/test/blink/ldbl_test.com.runs \ o/$(MODE)/i486/test/blink/disinst_test.com.runs \ o/$(MODE)/m68k/test/blink/disinst_test.com.runs \ o/$(MODE)/x86_64/test/blink/disinst_test.com.runs \ o/$(MODE)/arm/test/blink/disinst_test.com.runs \ o/$(MODE)/aarch64/test/blink/disinst_test.com.runs \ o/$(MODE)/riscv64/test/blink/disinst_test.com.runs \ o/$(MODE)/mips/test/blink/disinst_test.com.runs \ o/$(MODE)/mipsel/test/blink/disinst_test.com.runs \ o/$(MODE)/mips64/test/blink/disinst_test.com.runs \ o/$(MODE)/mips64el/test/blink/disinst_test.com.runs \ o/$(MODE)/s390x/test/blink/disinst_test.com.runs \ o/$(MODE)/powerpc/test/blink/disinst_test.com.runs \ o/$(MODE)/powerpc64le/test/blink/disinst_test.com.runs ================================================ FILE: test/blink/x86_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "blink/modrm.h" #include "blink/x86.h" #include "test/test.h" int error; struct XedDecodedInst xedd; void SetUp(void) { } void TearDown(void) { } TEST(x86, testPopR10) { DecodeInstruction(&xedd, "\115\132\0\0", 4, XED_MODE_LONG); ASSERT_EQ(2, xedd.length); ASSERT_EQ(0132, Opcode(xedd.op.rde)); ASSERT_EQ(0, Osz(xedd.op.rde)); ASSERT_EQ(0, Asz(xedd.op.rde)); ASSERT_EQ(0, Rep(xedd.op.rde)); ASSERT_EQ(1, Rex(xedd.op.rde)); ASSERT_EQ(1, Rexb(xedd.op.rde)); ASSERT_EQ(1, Rexw(xedd.op.rde)); ASSERT_EQ(1, Rexr(xedd.op.rde)); ASSERT_EQ(0, Rexx(xedd.op.rde)); ASSERT_EQ(0, Sego(xedd.op.rde)); ASSERT_EQ(XED_MODE_LONG, Mode(xedd.op.rde)); ASSERT_EQ(XED_MODE_LONG, Eamode(xedd.op.rde)); } TEST(x86, tesRepzCmpsb) { DecodeInstruction(&xedd, "\363\246\0\0", 4, XED_MODE_LONG); ASSERT_EQ(2, xedd.length); ASSERT_EQ(0246, Opcode(xedd.op.rde)); ASSERT_EQ(0, Osz(xedd.op.rde)); ASSERT_EQ(0, Asz(xedd.op.rde)); ASSERT_EQ(3, Rep(xedd.op.rde)); ASSERT_EQ(0, Rex(xedd.op.rde)); ASSERT_EQ(0, Rexb(xedd.op.rde)); ASSERT_EQ(0, Rexw(xedd.op.rde)); ASSERT_EQ(0, Rexr(xedd.op.rde)); ASSERT_EQ(0, Rexx(xedd.op.rde)); ASSERT_EQ(0, Sego(xedd.op.rde)); ASSERT_EQ(XED_MODE_LONG, Mode(xedd.op.rde)); ASSERT_EQ(XED_MODE_LONG, Eamode(xedd.op.rde)); } int ild(const char *p, size_t n) { error = DecodeInstruction(&xedd, p, n, XED_MODE_LONG); return error == XED_ERROR_NONE ? xedd.length : -error; } int ildreal(const char *p, size_t n) { error = DecodeInstruction(&xedd, p, n, XED_MODE_REAL); return error == XED_ERROR_NONE ? xedd.length : -error; } int ildlegacy(const char *p, size_t n) { error = DecodeInstruction(&xedd, p, n, XED_MODE_LEGACY); return error == XED_ERROR_NONE ? xedd.length : -error; } TEST(ild, test86) { EXPECT_EQ(6, ild("\017\202\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\203\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\204\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\205\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\206\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\207\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\210\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\211\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\215\000\000\000\000", 6)); EXPECT_EQ(6, ild("\017\216\000\000\000\000", 6)); EXPECT_EQ(4, ild("@\210k\000", 4)); EXPECT_EQ(4, ild("@\210s\000", 4)); EXPECT_EQ(4, ild("@\210w\000", 4)); EXPECT_EQ(4, ild("@\210{\000", 4)); EXPECT_EQ(3, ild("@\210\305", 3)); EXPECT_EQ(3, ild("@\210\306", 3)); EXPECT_EQ(3, ild("@\210\307", 3)); EXPECT_EQ(3, ild("@\210\316", 3)); EXPECT_EQ(3, ild("@\210\326", 3)); EXPECT_EQ(3, ild("@\210\327", 3)); EXPECT_EQ(3, ild("@\210\350", 3)); EXPECT_EQ(3, ild("@\210\352", 3)); EXPECT_EQ(3, ild("@\210\360", 3)); EXPECT_EQ(3, ild("@\210\361", 3)); EXPECT_EQ(3, ild("@\210\362", 3)); EXPECT_EQ(3, ild("@\210\367", 3)); EXPECT_EQ(3, ild("@\210\371", 3)); EXPECT_EQ(3, ild("@\210\372", 3)); EXPECT_EQ(3, ild("@\2120", 3)); EXPECT_EQ(4, ild("@\212k\000", 4)); EXPECT_EQ(4, ild("@\212p\000", 4)); EXPECT_EQ(4, ild("@\212s\000", 4)); EXPECT_EQ(4, ild("@\212w\000", 4)); EXPECT_EQ(4, ild("@\212{\000", 4)); EXPECT_EQ(4, ild("@\212}\000", 4)); EXPECT_EQ(3, ild("@\266\000", 3)); EXPECT_EQ(2, ild("AT", 2)); EXPECT_EQ(2, ild("AU", 2)); EXPECT_EQ(2, ild("AV", 2)); EXPECT_EQ(2, ild("AW", 2)); EXPECT_EQ(2, ild("AX", 2)); EXPECT_EQ(2, ild("A\134", 2)); EXPECT_EQ(2, ild("A]", 2)); EXPECT_EQ(2, ild("A^", 2)); EXPECT_EQ(2, ild("A_", 2)); EXPECT_EQ(4, ild("A\210P\000", 4)); EXPECT_EQ(3, ild("A\210\300", 3)); EXPECT_EQ(3, ild("A\210\301", 3)); EXPECT_EQ(3, ild("A\210\302", 3)); EXPECT_EQ(3, ild("A\210\303", 3)); EXPECT_EQ(3, ild("A\210\316", 3)); EXPECT_EQ(3, ild("A\210\362", 3)); EXPECT_EQ(7, ild("A\211\210\000\000\000\000", 7)); EXPECT_EQ(3, ild("A\211\300", 3)); EXPECT_EQ(3, ild("A\211\301", 3)); EXPECT_EQ(3, ild("A\211\304", 3)); EXPECT_EQ(3, ild("A\211\305", 3)); EXPECT_EQ(3, ild("A\211\306", 3)); EXPECT_EQ(3, ild("A\211\307", 3)); EXPECT_EQ(3, ild("A\211\310", 3)); EXPECT_EQ(3, ild("A\211\313", 3)); EXPECT_EQ(3, ild("A\211\320", 3)); EXPECT_EQ(3, ild("A\211\323", 3)); EXPECT_EQ(3, ild("A\211\326", 3)); EXPECT_EQ(3, ild("A\211\327", 3)); EXPECT_EQ(3, ild("A\211\334", 3)); EXPECT_EQ(3, ild("A\211\350", 3)); EXPECT_EQ(3, ild("A\211\362", 3)); EXPECT_EQ(3, ild("A\211\364", 3)); EXPECT_EQ(3, ild("A\211\365", 3)); EXPECT_EQ(3, ild("A\211\370", 3)); EXPECT_EQ(3, ild("A\211\373", 3)); EXPECT_EQ(4, ild("A\212\004\000", 4)); EXPECT_EQ(4, ild("A\212\004\004", 4)); EXPECT_EQ(4, ild("A\212\014\024", 4)); EXPECT_EQ(7, ild("A\213\200\000\000\000\000", 7)); EXPECT_EQ(6, ild("A\270\000\000\000\000", 6)); EXPECT_EQ(6, ild("A\271\000\000\000\000", 6)); EXPECT_EQ(6, ild("A\274\000\000\000\000", 6)); EXPECT_EQ(6, ild("A\275\000\000\000\000", 6)); EXPECT_EQ(6, ild("A\276\000\000\000\000", 6)); EXPECT_EQ(6, ild("A\277\000\000\000\000", 6)); EXPECT_EQ(4, ild("A\306\000\000", 4)); EXPECT_EQ(5, ild("A\306\004$\000", 5)); EXPECT_EQ(3, ild("A\323\340", 3)); EXPECT_EQ(4, ild("A\377\024\304", 4)); EXPECT_EQ(4, ild("B\210\004\007", 4)); EXPECT_EQ(4, ild("B\212\004\006", 4)); EXPECT_EQ(4, ild("B\212\024\000", 4)); EXPECT_EQ(8, ild("B\213\024\215\000\000\000\000", 8)); EXPECT_EQ(5, ild("C\306\004\016\000", 5)); EXPECT_EQ(4, ild("D\210@\000", 4)); EXPECT_EQ(4, ild("D\210C\000", 4)); EXPECT_EQ(4, ild("D\210G\000", 4)); EXPECT_EQ(4, ild("D\210K\000", 4)); EXPECT_EQ(4, ild("D\210S\000", 4)); EXPECT_EQ(4, ild("D\210c\000", 4)); EXPECT_EQ(3, ild("D\210\300", 3)); EXPECT_EQ(3, ild("D\210\302", 3)); EXPECT_EQ(3, ild("D\210\305", 3)); EXPECT_EQ(3, ild("D\210\306", 3)); EXPECT_EQ(3, ild("D\210\310", 3)); EXPECT_EQ(3, ild("D\210\311", 3)); EXPECT_EQ(3, ild("D\210\312", 3)); EXPECT_EQ(3, ild("D\210\315", 3)); EXPECT_EQ(3, ild("D\210\316", 3)); EXPECT_EQ(3, ild("D\210\320", 3)); EXPECT_EQ(3, ild("D\210\322", 3)); EXPECT_EQ(3, ild("D\210\331", 3)); EXPECT_EQ(3, ild("D\210\350", 3)); EXPECT_EQ(5, ild("D\211D$\000", 5)); EXPECT_EQ(7, ild("D\211\211\000\000\000\000", 7)); EXPECT_EQ(3, ild("D\211\300", 3)); EXPECT_EQ(3, ild("D\211\301", 3)); EXPECT_EQ(3, ild("D\211\302", 3)); EXPECT_EQ(3, ild("D\211\310", 3)); EXPECT_EQ(3, ild("D\211\316", 3)); EXPECT_EQ(3, ild("D\211\331", 3)); EXPECT_EQ(3, ild("D\211\340", 3)); EXPECT_EQ(3, ild("D\211\341", 3)); EXPECT_EQ(3, ild("D\211\342", 3)); EXPECT_EQ(3, ild("D\211\346", 3)); EXPECT_EQ(3, ild("D\211\347", 3)); EXPECT_EQ(3, ild("D\211\350", 3)); EXPECT_EQ(3, ild("D\211\351", 3)); EXPECT_EQ(3, ild("D\211\352", 3)); EXPECT_EQ(3, ild("D\211\357", 3)); EXPECT_EQ(3, ild("D\211\362", 3)); EXPECT_EQ(3, ild("D\211\367", 3)); EXPECT_EQ(3, ild("D\211\372", 3)); EXPECT_EQ(3, ild("D\211\377", 3)); EXPECT_EQ(3, ild("D\212\001", 3)); EXPECT_EQ(4, ild("D\212C\000", 4)); EXPECT_EQ(4, ild("D\212F\000", 4)); EXPECT_EQ(4, ild("D\212G\000", 4)); EXPECT_EQ(4, ild("D\212N\000", 4)); EXPECT_EQ(4, ild("D\212O\000", 4)); EXPECT_EQ(4, ild("D\212S\000", 4)); EXPECT_EQ(4, ild("D\212W\000", 4)); EXPECT_EQ(4, ild("D\213\004$", 4)); EXPECT_EQ(5, ild("D\213D$\000", 5)); EXPECT_EQ(4, ild("D\213E\000", 4)); EXPECT_EQ(4, ild("D\213G\000", 4)); EXPECT_EQ(4, ild("D\213g\000", 4)); EXPECT_EQ(5, ild("D\213l$\000", 5)); EXPECT_EQ(4, ild("D\213w\000", 4)); EXPECT_EQ(5, ild("D\213|$\000", 5)); EXPECT_EQ(4, ild("D\213}\000", 4)); EXPECT_EQ(7, ild("D\213\201\000\000\000\000", 7)); EXPECT_EQ(4, ild("E\2104$", 4)); EXPECT_EQ(3, ild("E\210\307", 3)); EXPECT_EQ(3, ild("E\210\310", 3)); EXPECT_EQ(3, ild("E\210\321", 3)); EXPECT_EQ(3, ild("E\210\323", 3)); EXPECT_EQ(3, ild("E\210\370", 3)); EXPECT_EQ(3, ild("E\211\301", 3)); EXPECT_EQ(3, ild("E\211\312", 3)); EXPECT_EQ(3, ild("E\211\313", 3)); EXPECT_EQ(3, ild("E\211\330", 3)); EXPECT_EQ(7, ild("E\213\220\000\000\000\000", 7)); EXPECT_EQ(4, ild("G\210,\016", 4)); EXPECT_EQ(3, ild("Hc\022", 3)); EXPECT_EQ(3, ild("Hc\307", 3)); EXPECT_EQ(3, ild("Hc\310", 3)); EXPECT_EQ(3, ild("Hc\311", 3)); EXPECT_EQ(3, ild("Hc\320", 3)); EXPECT_EQ(3, ild("Hc\322", 3)); EXPECT_EQ(3, ild("Hc\366", 3)); EXPECT_EQ(3, ild("Hc\370", 3)); EXPECT_EQ(3, ild("H\211\002", 3)); EXPECT_EQ(3, ild("H\211\003", 3)); EXPECT_EQ(7, ild("H\211\005\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\211\006", 3)); EXPECT_EQ(3, ild("H\211\007", 3)); EXPECT_EQ(7, ild("H\211\015\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\211\020", 3)); EXPECT_EQ(3, ild("H\211\023", 3)); EXPECT_EQ(7, ild("H\211\025\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\211\027", 3)); EXPECT_EQ(4, ild("H\2114$", 4)); EXPECT_EQ(7, ild("H\2115\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\2117", 3)); EXPECT_EQ(7, ild("H\211=\000\000\000\000", 7)); EXPECT_EQ(4, ild("H\211C\000", 4)); EXPECT_EQ(4, ild("H\211G\000", 4)); EXPECT_EQ(4, ild("H\211S\000", 4)); EXPECT_EQ(4, ild("H\211W\000", 4)); EXPECT_EQ(4, ild("H\211w\000", 4)); EXPECT_EQ(3, ild("H\211\301", 3)); EXPECT_EQ(3, ild("H\211\302", 3)); EXPECT_EQ(3, ild("H\211\303", 3)); EXPECT_EQ(3, ild("H\211\305", 3)); EXPECT_EQ(3, ild("H\211\306", 3)); EXPECT_EQ(3, ild("H\211\307", 3)); EXPECT_EQ(3, ild("H\211\310", 3)); EXPECT_EQ(3, ild("H\211\312", 3)); EXPECT_EQ(3, ild("H\211\315", 3)); EXPECT_EQ(3, ild("H\211\316", 3)); EXPECT_EQ(3, ild("H\211\320", 3)); EXPECT_EQ(3, ild("H\211\321", 3)); EXPECT_EQ(3, ild("H\211\323", 3)); EXPECT_EQ(3, ild("H\211\325", 3)); EXPECT_EQ(3, ild("H\211\326", 3)); EXPECT_EQ(3, ild("H\211\327", 3)); EXPECT_EQ(3, ild("H\211\331", 3)); EXPECT_EQ(3, ild("H\211\336", 3)); EXPECT_EQ(3, ild("H\211\337", 3)); EXPECT_EQ(3, ild("H\211\345", 3)); EXPECT_EQ(3, ild("H\211\347", 3)); EXPECT_EQ(3, ild("H\211\351", 3)); EXPECT_EQ(3, ild("H\211\356", 3)); EXPECT_EQ(3, ild("H\211\357", 3)); EXPECT_EQ(3, ild("H\211\360", 3)); EXPECT_EQ(3, ild("H\211\361", 3)); EXPECT_EQ(3, ild("H\211\363", 3)); EXPECT_EQ(3, ild("H\211\365", 3)); EXPECT_EQ(3, ild("H\211\367", 3)); EXPECT_EQ(3, ild("H\211\370", 3)); EXPECT_EQ(3, ild("H\211\372", 3)); EXPECT_EQ(3, ild("H\211\373", 3)); EXPECT_EQ(3, ild("H\211\375", 3)); EXPECT_EQ(3, ild("H\211\376", 3)); EXPECT_EQ(3, ild("H\213\000", 3)); EXPECT_EQ(3, ild("H\213\003", 3)); EXPECT_EQ(8, ild("H\213\004\305\000\000\000\000", 8)); EXPECT_EQ(4, ild("H\213\004\320", 4)); EXPECT_EQ(8, ild("H\213\004\365\000\000\000\000", 8)); EXPECT_EQ(7, ild("H\213\005\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\213\007", 3)); EXPECT_EQ(3, ild("H\213\013", 3)); EXPECT_EQ(7, ild("H\213\015\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\213\022", 3)); EXPECT_EQ(3, ild("H\213\023", 3)); EXPECT_EQ(4, ild("H\213\024\312", 4)); EXPECT_EQ(8, ild("H\213\024\325\000\000\000\000", 8)); EXPECT_EQ(8, ild("H\213\024\335\000\000\000\000", 8)); EXPECT_EQ(3, ild("H\213\027", 3)); EXPECT_EQ(7, ild("H\213\035\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\2133", 3)); EXPECT_EQ(4, ild("H\2134$", 4)); EXPECT_EQ(3, ild("H\2137", 3)); EXPECT_EQ(3, ild("H\213;", 3)); EXPECT_EQ(7, ild("H\213=\000\000\000\000", 7)); EXPECT_EQ(4, ild("H\213A\000", 4)); EXPECT_EQ(4, ild("H\213C\000", 4)); EXPECT_EQ(4, ild("H\213E\000", 4)); EXPECT_EQ(4, ild("H\213G\000", 4)); EXPECT_EQ(4, ild("H\213K\000", 4)); EXPECT_EQ(4, ild("H\213O\000", 4)); EXPECT_EQ(4, ild("H\213R\000", 4)); EXPECT_EQ(4, ild("H\213S\000", 4)); EXPECT_EQ(4, ild("H\213U\000", 4)); EXPECT_EQ(4, ild("H\213W\000", 4)); EXPECT_EQ(4, ild("H\213o\000", 4)); EXPECT_EQ(4, ild("H\213s\000", 4)); EXPECT_EQ(4, ild("H\213w\000", 4)); EXPECT_EQ(4, ild("H\213{\000", 4)); EXPECT_EQ(4, ild("H\213\177\000", 4)); EXPECT_EQ(7, ild("H\213\200\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\213\206\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\213\207\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\213\220\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\213\221\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\213\226\000\000\000\000", 7)); EXPECT_EQ(2, ild("H\230", 2)); EXPECT_EQ(10, ild("H\270\000\000\000\000\000\000\000\000", 10)); EXPECT_EQ(10, ild("H\271\000\000\000\000\000\000\000\000", 10)); EXPECT_EQ(10, ild("H\272\000\000\000\000\000\000\000\000", 10)); EXPECT_EQ(10, ild("H\276\000\000\000\000\000\000\000\000", 10)); EXPECT_EQ(10, ild("H\277\000\000\000\000\000\000\000\000", 10)); EXPECT_EQ(7, ild("H\307\003\000\000\000\000", 7)); EXPECT_EQ(11, ild("H\307\005\000\000\000\000\000\000\000\000", 11)); EXPECT_EQ(7, ild("H\307\007\000\000\000\000", 7)); EXPECT_EQ(8, ild("H\307C\000\000\000\000\000", 8)); EXPECT_EQ(8, ild("H\307G\000\000\000\000\000", 8)); EXPECT_EQ(7, ild("H\307\300\000\000\000\000", 7)); EXPECT_EQ(3, ild("H\323\300", 3)); EXPECT_EQ(3, ild("H\323\340", 3)); EXPECT_EQ(3, ild("H\323\342", 3)); EXPECT_EQ(3, ild("H\323\350", 3)); EXPECT_EQ(3, ild("H\323\352", 3)); EXPECT_EQ(3, ild("Ic\367", 3)); EXPECT_EQ(3, ild("I\211\304", 3)); EXPECT_EQ(3, ild("I\211\305", 3)); EXPECT_EQ(3, ild("I\211\315", 3)); EXPECT_EQ(3, ild("I\211\320", 3)); EXPECT_EQ(3, ild("I\211\325", 3)); EXPECT_EQ(3, ild("I\211\344", 3)); EXPECT_EQ(3, ild("I\211\362", 3)); EXPECT_EQ(3, ild("I\211\364", 3)); EXPECT_EQ(3, ild("I\211\365", 3)); EXPECT_EQ(3, ild("I\211\366", 3)); EXPECT_EQ(3, ild("I\211\374", 3)); EXPECT_EQ(3, ild("I\211\375", 3)); EXPECT_EQ(4, ild("I\213U\000", 4)); EXPECT_EQ(3, ild("I\323\340", 3)); EXPECT_EQ(3, ild("I\323\355", 3)); EXPECT_EQ(8, ild("J\2134\305\000\000\000\000", 8)); EXPECT_EQ(4, ild("L\211c\000", 4)); EXPECT_EQ(4, ild("L\211s\000", 4)); EXPECT_EQ(3, ild("L\211\301", 3)); EXPECT_EQ(3, ild("L\211\306", 3)); EXPECT_EQ(3, ild("L\211\316", 3)); EXPECT_EQ(3, ild("L\211\320", 3)); EXPECT_EQ(3, ild("L\211\346", 3)); EXPECT_EQ(3, ild("L\211\347", 3)); EXPECT_EQ(3, ild("L\211\352", 3)); EXPECT_EQ(3, ild("L\211\356", 3)); EXPECT_EQ(3, ild("L\211\357", 3)); EXPECT_EQ(3, ild("L\211\372", 3)); EXPECT_EQ(7, ild("L\213%\000\000\000\000", 7)); EXPECT_EQ(4, ild("L\213C\000", 4)); EXPECT_EQ(4, ild("L\213G\000", 4)); EXPECT_EQ(4, ild("L\213c\000", 4)); EXPECT_EQ(4, ild("L\213g\000", 4)); EXPECT_EQ(4, ild("L\213m\000", 4)); EXPECT_EQ(4, ild("L\213o\000", 4)); EXPECT_EQ(4, ild("L\213w\000", 4)); EXPECT_EQ(3, ild("Mc\300", 3)); EXPECT_EQ(3, ild("Mc\356", 3)); EXPECT_EQ(3, ild("M\211\303", 3)); EXPECT_EQ(3, ild("M\211\354", 3)); EXPECT_EQ(1, ild("S", 1)); EXPECT_EQ(1, ild("U", 1)); EXPECT_EQ(1, ild("X", 1)); EXPECT_EQ(1, ild("Y", 1)); EXPECT_EQ(1, ild("Z", 1)); EXPECT_EQ(1, ild("[", 1)); EXPECT_EQ(1, ild("]", 1)); EXPECT_EQ(5, ild("fD\213G\000", 5)); EXPECT_EQ(5, ild("fD\213o\000", 5)); EXPECT_EQ(5, ild("fD\213u\000", 5)); EXPECT_EQ(3, ild("f\211\002", 3)); EXPECT_EQ(3, ild("f\211\020", 3)); EXPECT_EQ(4, ild("f\211C\000", 4)); EXPECT_EQ(4, ild("f\211G\000", 4)); EXPECT_EQ(4, ild("f\211K\000", 4)); EXPECT_EQ(4, ild("f\211O\000", 4)); EXPECT_EQ(4, ild("f\211W\000", 4)); EXPECT_EQ(4, ild("f\211s\000", 4)); EXPECT_EQ(4, ild("f\211w\000", 4)); EXPECT_EQ(4, ild("f\211{\000", 4)); EXPECT_EQ(7, ild("f\211\201\000\000\000\000", 7)); EXPECT_EQ(7, ild("f\211\202\000\000\000\000", 7)); EXPECT_EQ(7, ild("f\211\220\000\000\000\000", 7)); EXPECT_EQ(8, ild("f\213\004\205\000\000\000\000", 8)); EXPECT_EQ(8, ild("f\213\024\255\000\000\000\000", 8)); EXPECT_EQ(8, ild("f\213\024\325\000\000\000\000", 8)); EXPECT_EQ(8, ild("f\213\024\355\000\000\000\000", 8)); EXPECT_EQ(4, ild("f\213C\000", 4)); EXPECT_EQ(4, ild("f\213G\000", 4)); EXPECT_EQ(4, ild("f\213K\000", 4)); EXPECT_EQ(4, ild("f\213O\000", 4)); EXPECT_EQ(4, ild("f\213S\000", 4)); EXPECT_EQ(4, ild("f\213W\000", 4)); EXPECT_EQ(4, ild("f\213s\000", 4)); EXPECT_EQ(4, ild("f\213w\000", 4)); EXPECT_EQ(4, ild("f\213{\000", 4)); EXPECT_EQ(7, ild("f\213\200\000\000\000\000", 7)); EXPECT_EQ(8, ild("f\213\204\000\000\000\000\000", 8)); EXPECT_EQ(8, ild("f\213\224\000\000\000\000\000", 8)); EXPECT_EQ(8, ild("f\213\224-\000\000\000\000", 8)); EXPECT_EQ(7, ild("f\213\225\000\000\000\000", 7)); EXPECT_EQ(2, ild("f\220", 2)); EXPECT_EQ(9, ild("f\307\005\000\000\000\000\000\000", 9)); EXPECT_EQ(6, ild("f\307G\000\000\000", 6)); EXPECT_EQ(9, ild("f\307\200\000\000\000\000\000\000", 9)); EXPECT_EQ(9, ild("f\307\202\000\000\000\000\000\000", 9)); EXPECT_EQ(2, ild("r\000", 2)); EXPECT_EQ(2, ild("s\000", 2)); EXPECT_EQ(2, ild("t\000", 2)); EXPECT_EQ(2, ild("u\000", 2)); EXPECT_EQ(2, ild("v\000", 2)); EXPECT_EQ(2, ild("w\000", 2)); EXPECT_EQ(2, ild("x\000", 2)); EXPECT_EQ(2, ild("y\000", 2)); EXPECT_EQ(2, ild("|\000", 2)); EXPECT_EQ(2, ild("}\000", 2)); EXPECT_EQ(2, ild("~\000", 2)); EXPECT_EQ(2, ild("\177\000", 2)); EXPECT_EQ(2, ild("\210\002", 2)); EXPECT_EQ(3, ild("\210\0143", 3)); EXPECT_EQ(2, ild("\210\020", 2)); EXPECT_EQ(3, ild("\210C\000", 3)); EXPECT_EQ(4, ild("\210D\024\000", 4)); EXPECT_EQ(4, ild("\210D$\000", 4)); EXPECT_EQ(3, ild("\210G\000", 3)); EXPECT_EQ(3, ild("\210K\000", 3)); EXPECT_EQ(3, ild("\210O\000", 3)); EXPECT_EQ(3, ild("\210Q\000", 3)); EXPECT_EQ(3, ild("\210S\000", 3)); EXPECT_EQ(4, ild("\210T\003\000", 4)); EXPECT_EQ(4, ild("\210T\007\000", 4)); EXPECT_EQ(3, ild("\210W\000", 3)); EXPECT_EQ(2, ild("\210\301", 2)); EXPECT_EQ(2, ild("\210\302", 2)); EXPECT_EQ(2, ild("\210\310", 2)); EXPECT_EQ(2, ild("\210\312", 2)); EXPECT_EQ(2, ild("\210\320", 2)); EXPECT_EQ(2, ild("\210\321", 2)); EXPECT_EQ(2, ild("\211\002", 2)); EXPECT_EQ(2, ild("\211\003", 2)); EXPECT_EQ(3, ild("\211\004$", 3)); EXPECT_EQ(2, ild("\211\020", 2)); EXPECT_EQ(6, ild("\211\025\000\000\000\000", 6)); EXPECT_EQ(6, ild("\211=\000\000\000\000", 6)); EXPECT_EQ(3, ild("\211B\000", 3)); EXPECT_EQ(3, ild("\211C\000", 3)); EXPECT_EQ(4, ild("\211D$\000", 4)); EXPECT_EQ(3, ild("\211E\000", 3)); EXPECT_EQ(3, ild("\211G\000", 3)); EXPECT_EQ(3, ild("\211K\000", 3)); EXPECT_EQ(4, ild("\211L$\000", 4)); EXPECT_EQ(3, ild("\211O\000", 3)); EXPECT_EQ(3, ild("\211P\000", 3)); EXPECT_EQ(4, ild("\211T$\000", 4)); EXPECT_EQ(3, ild("\211W\000", 3)); EXPECT_EQ(3, ild("\211X\000", 3)); EXPECT_EQ(3, ild("\211Z\000", 3)); EXPECT_EQ(3, ild("\211]\000", 3)); EXPECT_EQ(3, ild("\211j\000", 3)); EXPECT_EQ(3, ild("\211s\000", 3)); EXPECT_EQ(4, ild("\211t$\000", 4)); EXPECT_EQ(3, ild("\211w\000", 3)); EXPECT_EQ(4, ild("\211|$\000", 4)); EXPECT_EQ(6, ild("\211\202\000\000\000\000", 6)); EXPECT_EQ(6, ild("\211\220\000\000\000\000", 6)); EXPECT_EQ(7, ild("\211\224$\000\000\000\000", 7)); EXPECT_EQ(6, ild("\211\232\000\000\000\000", 6)); EXPECT_EQ(6, ild("\211\252\000\000\000\000", 6)); EXPECT_EQ(2, ild("\211\300", 2)); EXPECT_EQ(2, ild("\211\301", 2)); EXPECT_EQ(2, ild("\211\302", 2)); EXPECT_EQ(2, ild("\211\303", 2)); EXPECT_EQ(2, ild("\211\305", 2)); EXPECT_EQ(2, ild("\211\306", 2)); EXPECT_EQ(2, ild("\211\307", 2)); EXPECT_EQ(2, ild("\211\310", 2)); EXPECT_EQ(2, ild("\211\313", 2)); EXPECT_EQ(2, ild("\211\316", 2)); EXPECT_EQ(2, ild("\211\320", 2)); EXPECT_EQ(2, ild("\211\321", 2)); EXPECT_EQ(2, ild("\211\323", 2)); EXPECT_EQ(2, ild("\211\325", 2)); EXPECT_EQ(2, ild("\211\326", 2)); EXPECT_EQ(2, ild("\211\327", 2)); EXPECT_EQ(2, ild("\211\330", 2)); EXPECT_EQ(2, ild("\211\332", 2)); EXPECT_EQ(2, ild("\211\336", 2)); EXPECT_EQ(2, ild("\211\337", 2)); EXPECT_EQ(2, ild("\211\350", 2)); EXPECT_EQ(2, ild("\211\351", 2)); EXPECT_EQ(2, ild("\211\352", 2)); EXPECT_EQ(2, ild("\211\356", 2)); EXPECT_EQ(2, ild("\211\360", 2)); EXPECT_EQ(2, ild("\211\361", 2)); EXPECT_EQ(2, ild("\211\362", 2)); EXPECT_EQ(2, ild("\211\363", 2)); EXPECT_EQ(2, ild("\211\365", 2)); EXPECT_EQ(2, ild("\211\366", 2)); EXPECT_EQ(2, ild("\211\367", 2)); EXPECT_EQ(2, ild("\211\370", 2)); EXPECT_EQ(2, ild("\211\371", 2)); EXPECT_EQ(2, ild("\211\373", 2)); EXPECT_EQ(2, ild("\211\377", 2)); EXPECT_EQ(2, ild("\212\000", 2)); EXPECT_EQ(3, ild("\212\004\001", 3)); EXPECT_EQ(3, ild("\212\004\002", 3)); EXPECT_EQ(3, ild("\212\004\006", 3)); EXPECT_EQ(7, ild("\212\004\225\000\000\000\000", 7)); EXPECT_EQ(7, ild("\212\004\325\000\000\000\000", 7)); EXPECT_EQ(2, ild("\212\006", 2)); EXPECT_EQ(2, ild("\212\010", 2)); EXPECT_EQ(3, ild("\212\014\001", 3)); EXPECT_EQ(3, ild("\212\014\010", 3)); EXPECT_EQ(7, ild("\212\014\325\000\000\000\000", 7)); EXPECT_EQ(2, ild("\212\020", 2)); EXPECT_EQ(3, ild("\212\024\002", 3)); EXPECT_EQ(3, ild("\212\024\012", 3)); EXPECT_EQ(3, ild("\212\024\021", 3)); EXPECT_EQ(7, ild("\212\024\225\000\000\000\000", 7)); EXPECT_EQ(7, ild("\212\024\305\000\000\000\000", 7)); EXPECT_EQ(7, ild("\212\024\325\000\000\000\000", 7)); EXPECT_EQ(7, ild("\212\024\365\000\000\000\000", 7)); EXPECT_EQ(3, ild("\212@\000", 3)); EXPECT_EQ(3, ild("\212C\000", 3)); EXPECT_EQ(3, ild("\212E\000", 3)); EXPECT_EQ(3, ild("\212F\000", 3)); EXPECT_EQ(3, ild("\212G\000", 3)); EXPECT_EQ(3, ild("\212H\000", 3)); EXPECT_EQ(3, ild("\212J\000", 3)); EXPECT_EQ(3, ild("\212K\000", 3)); EXPECT_EQ(3, ild("\212M\000", 3)); EXPECT_EQ(3, ild("\212N\000", 3)); EXPECT_EQ(3, ild("\212O\000", 3)); EXPECT_EQ(3, ild("\212P\000", 3)); EXPECT_EQ(3, ild("\212S\000", 3)); EXPECT_EQ(4, ild("\212T$\000", 4)); EXPECT_EQ(3, ild("\212W\000", 3)); EXPECT_EQ(6, ild("\212\200\000\000\000\000", 6)); EXPECT_EQ(7, ild("\212\204\020\000\000\000\000", 7)); EXPECT_EQ(6, ild("\212\211\000\000\000\000", 6)); EXPECT_EQ(6, ild("\212\220\000\000\000\000", 6)); EXPECT_EQ(6, ild("\212\222\000\000\000\000", 6)); EXPECT_EQ(2, ild("\213\000", 2)); EXPECT_EQ(7, ild("\213\004\205\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\004\225\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\004\265\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\004\275\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\004\305\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\004\325\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\004\375\000\000\000\000", 7)); EXPECT_EQ(2, ild("\213\006", 2)); EXPECT_EQ(2, ild("\213\007", 2)); EXPECT_EQ(7, ild("\213\014\205\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\014\215\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\014\265\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\014\275\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\014\315\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\014\325\000\000\000\000", 7)); EXPECT_EQ(2, ild("\213\020", 2)); EXPECT_EQ(7, ild("\213\024\205\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\024\225\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\024\255\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\024\305\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\024\315\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\024\325\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\024\355\000\000\000\000", 7)); EXPECT_EQ(7, ild("\213\024\365\000\000\000\000", 7)); EXPECT_EQ(6, ild("\213\025\000\000\000\000", 6)); EXPECT_EQ(2, ild("\213\026", 2)); EXPECT_EQ(2, ild("\213\036", 2)); EXPECT_EQ(2, ild("\213(", 2)); EXPECT_EQ(7, ild("\2134\205\000\000\000\000", 7)); EXPECT_EQ(7, ild("\2134\315\000\000\000\000", 7)); EXPECT_EQ(7, ild("\2134\325\000\000\000\000", 7)); EXPECT_EQ(3, ild("\213<$", 3)); EXPECT_EQ(2, ild("\213?", 2)); EXPECT_EQ(3, ild("\213@\000", 3)); EXPECT_EQ(3, ild("\213C\000", 3)); EXPECT_EQ(3, ild("\213E\000", 3)); EXPECT_EQ(3, ild("\213G\000", 3)); EXPECT_EQ(3, ild("\213H\000", 3)); EXPECT_EQ(3, ild("\213K\000", 3)); EXPECT_EQ(4, ild("\213L$\000", 4)); EXPECT_EQ(3, ild("\213O\000", 3)); EXPECT_EQ(3, ild("\213Q\000", 3)); EXPECT_EQ(3, ild("\213S\000", 3)); EXPECT_EQ(4, ild("\213T$\000", 4)); EXPECT_EQ(3, ild("\213W\000", 3)); EXPECT_EQ(3, ild("\213h\000", 3)); EXPECT_EQ(3, ild("\213s\000", 3)); EXPECT_EQ(4, ild("\213t$\000", 4)); EXPECT_EQ(3, ild("\213u\000", 3)); EXPECT_EQ(3, ild("\213w\000", 3)); EXPECT_EQ(3, ild("\213{\000", 3)); EXPECT_EQ(4, ild("\213|$\000", 4)); EXPECT_EQ(3, ild("\213}\000", 3)); EXPECT_EQ(3, ild("\213\177\000", 3)); EXPECT_EQ(6, ild("\213\200\000\000\000\000", 6)); EXPECT_EQ(6, ild("\213\201\000\000\000\000", 6)); EXPECT_EQ(6, ild("\213\222\000\000\000\000", 6)); EXPECT_EQ(6, ild("\213\225\000\000\000\000", 6)); EXPECT_EQ(6, ild("\213\260\000\000\000\000", 6)); EXPECT_EQ(6, ild("\213\262\000\000\000\000", 6)); EXPECT_EQ(6, ild("\213\271\000\000\000\000", 6)); EXPECT_EQ(2, ild("\260\000", 2)); EXPECT_EQ(2, ild("\262\000", 2)); EXPECT_EQ(5, ild("\270\000\000\000\000", 5)); EXPECT_EQ(5, ild("\271\000\000\000\000", 5)); EXPECT_EQ(5, ild("\272\000\000\000\000", 5)); EXPECT_EQ(5, ild("\273\000\000\000\000", 5)); EXPECT_EQ(5, ild("\275\000\000\000\000", 5)); EXPECT_EQ(5, ild("\276\000\000\000\000", 5)); EXPECT_EQ(5, ild("\277\000\000\000\000", 5)); EXPECT_EQ(1, ild("\303", 1)); EXPECT_EQ(3, ild("\306\001\000", 3)); EXPECT_EQ(4, ild("\306\004\003\000", 4)); EXPECT_EQ(7, ild("\306\005\000\000\000\000\000", 7)); EXPECT_EQ(3, ild("\306\006\000", 3)); EXPECT_EQ(3, ild("\306\007\000", 3)); EXPECT_EQ(4, ild("\306@\000\000", 4)); EXPECT_EQ(4, ild("\306B\000\000", 4)); EXPECT_EQ(4, ild("\306C\000\000", 4)); EXPECT_EQ(5, ild("\306D$\000\000", 5)); EXPECT_EQ(4, ild("\306G\000\000", 4)); EXPECT_EQ(8, ild("\306\204\016\000\000\000\000\000", 8)); EXPECT_EQ(7, ild("\307\004\007\000\000\000\000", 7)); EXPECT_EQ(10, ild("\307\005\000\000\000\000\000\000\000\000", 10)); EXPECT_EQ(7, ild("\307@\000\000\000\000\000", 7)); EXPECT_EQ(7, ild("\307B\000\000\000\000\000", 7)); EXPECT_EQ(8, ild("\307D$\000\000\000\000\000", 8)); EXPECT_EQ(10, ild("\307\200\000\000\000\000\000\000\000\000", 10)); EXPECT_EQ(11, ild("\307\204$\000\000\000\000\000\000\000\000", 11)); EXPECT_EQ(2, ild("\322\301", 2)); EXPECT_EQ(2, ild("\323\340", 2)); EXPECT_EQ(2, ild("\323\342", 2)); EXPECT_EQ(2, ild("\323\347", 2)); EXPECT_EQ(2, ild("\340\000", 2)); EXPECT_EQ(2, ild("\342\000", 2)); EXPECT_EQ(5, ild("\350\000\000\000\000", 5)); EXPECT_EQ(5, ildlegacy("\350\000\000\000\000", 5)); #ifndef DISABLE_METAL EXPECT_EQ(3, ildreal("\350\000\000", 3)); #endif EXPECT_EQ(5, ild("\350\000\203\342\000", 5)); EXPECT_EQ(5, ild("\351\000\000\000\000", 5)); EXPECT_EQ(5, ild("\351\000\203\340\000", 5)); EXPECT_EQ(2, ild("\353\000", 2)); EXPECT_EQ(2, ild("\362\256", 2)); EXPECT_EQ(2, ild("\363\244", 2)); EXPECT_EQ(2, ild("\363\303", 2)); EXPECT_EQ(7, ild("\377\024\305\000\000\000\000", 7)); EXPECT_EQ(7, ild("\377$\305\000\000\000\000", 7)); EXPECT_EQ(7, ild("\377$\315\000\000\000\000", 7)); EXPECT_EQ(7, ild("\377$\325\000\000\000\000", 7)); EXPECT_EQ(7, ild("\377$\365\000\000\000\000", 7)); EXPECT_EQ(2, ild("\377\320", 2)); EXPECT_EQ(2, ild("\377\322", 2)); EXPECT_EQ(2, ild("\377\340", 2)); EXPECT_EQ(2, ild("\336\315", 2)); } TEST(ild, test386) { EXPECT_EQ(3, ild("\017\224\300", 3)); EXPECT_EQ(3, ild("\017\224\301", 3)); EXPECT_EQ(3, ild("\017\224\302", 3)); EXPECT_EQ(3, ild("\017\225\300", 3)); EXPECT_EQ(3, ild("\017\225\301", 3)); EXPECT_EQ(3, ild("\017\225\302", 3)); EXPECT_EQ(3, ild("\017\226\300", 3)); EXPECT_EQ(3, ild("\017\226\302", 3)); EXPECT_EQ(3, ild("\017\227\301", 3)); EXPECT_EQ(3, ild("\017\234\301", 3)); EXPECT_EQ(3, ild("\017\243\320", 3)); EXPECT_EQ(3, ild("\017\266\000", 3)); EXPECT_EQ(8, ild("\017\266\004\225\000\000\000\000", 8)); EXPECT_EQ(8, ild("\017\266\004\325\000\000\000\000", 8)); EXPECT_EQ(3, ild("\017\266\007", 3)); EXPECT_EQ(3, ild("\017\266\010", 3)); EXPECT_EQ(4, ild("\017\266\014\010", 4)); EXPECT_EQ(8, ild("\017\266\014\325\000\000\000\000", 8)); EXPECT_EQ(3, ild("\017\266\017", 3)); EXPECT_EQ(3, ild("\017\266\020", 3)); EXPECT_EQ(3, ild("\017\266/", 3)); EXPECT_EQ(3, ild("\017\2660", 3)); EXPECT_EQ(4, ild("\017\26640", 4)); EXPECT_EQ(4, ild("\017\266<\010", 4)); EXPECT_EQ(3, ild("\017\266?", 3)); EXPECT_EQ(4, ild("\017\266@\000", 4)); EXPECT_EQ(4, ild("\017\266A\000", 4)); EXPECT_EQ(4, ild("\017\266C\000", 4)); EXPECT_EQ(5, ild("\017\266D7\000", 5)); EXPECT_EQ(4, ild("\017\266F\000", 4)); EXPECT_EQ(4, ild("\017\266G\000", 4)); EXPECT_EQ(4, ild("\017\266H\000", 4)); EXPECT_EQ(4, ild("\017\266K\000", 4)); EXPECT_EQ(4, ild("\017\266O\000", 4)); EXPECT_EQ(4, ild("\017\266P\000", 4)); EXPECT_EQ(4, ild("\017\266R\000", 4)); EXPECT_EQ(4, ild("\017\266S\000", 4)); EXPECT_EQ(4, ild("\017\266W\000", 4)); EXPECT_EQ(4, ild("\017\266X\000", 4)); EXPECT_EQ(4, ild("\017\266_\000", 4)); EXPECT_EQ(4, ild("\017\266p\000", 4)); EXPECT_EQ(4, ild("\017\266s\000", 4)); EXPECT_EQ(5, ild("\017\266t$\000", 5)); EXPECT_EQ(4, ild("\017\266{\000", 4)); EXPECT_EQ(4, ild("\017\266}\000", 4)); EXPECT_EQ(4, ild("\017\266\177\000", 4)); EXPECT_EQ(7, ild("\017\266\200\000\000\000\000", 7)); EXPECT_EQ(7, ild("\017\266\202\000\000\000\000", 7)); EXPECT_EQ(8, ild("\017\266\204\022\000\000\000\000", 8)); EXPECT_EQ(7, ild("\017\266\207\000\000\000\000", 7)); EXPECT_EQ(8, ild("\017\266\214\020\000\000\000\000", 8)); EXPECT_EQ(8, ild("\017\266\224\021\000\000\000\000", 8)); EXPECT_EQ(8, ild("\017\266\234$\000\000\000\000", 8)); EXPECT_EQ(3, ild("\017\266\300", 3)); EXPECT_EQ(3, ild("\017\266\301", 3)); EXPECT_EQ(3, ild("\017\266\302", 3)); EXPECT_EQ(3, ild("\017\266\310", 3)); EXPECT_EQ(3, ild("\017\266\311", 3)); EXPECT_EQ(3, ild("\017\266\312", 3)); EXPECT_EQ(3, ild("\017\266\320", 3)); EXPECT_EQ(3, ild("\017\266\322", 3)); EXPECT_EQ(3, ild("\017\266\350", 3)); EXPECT_EQ(3, ild("\017\266\360", 3)); EXPECT_EQ(3, ild("\017\266\361", 3)); EXPECT_EQ(3, ild("\017\266\362", 3)); EXPECT_EQ(3, ild("\017\266\371", 3)); EXPECT_EQ(3, ild("\017\267\000", 3)); EXPECT_EQ(3, ild("\017\2679", 3)); EXPECT_EQ(4, ild("\017\267B\000", 4)); EXPECT_EQ(4, ild("\017\267E\000", 4)); EXPECT_EQ(4, ild("\017\267F\000", 4)); EXPECT_EQ(4, ild("\017\267G\000", 4)); EXPECT_EQ(4, ild("\017\267P\000", 4)); EXPECT_EQ(4, ild("\017\267W\000", 4)); EXPECT_EQ(5, ild("\017\267t$\000", 5)); EXPECT_EQ(4, ild("\017\267x\000", 4)); EXPECT_EQ(7, ild("\017\267\200\000\000\000\000", 7)); EXPECT_EQ(8, ild("\017\267\204\000\000\000\000\000", 8)); EXPECT_EQ(3, ild("\017\267\300", 3)); EXPECT_EQ(3, ild("\017\267\307", 3)); EXPECT_EQ(3, ild("\017\267\322", 3)); EXPECT_EQ(3, ild("\017\267\366", 3)); EXPECT_EQ(3, ild("\017\267\372", 3)); EXPECT_EQ(4, ild("\017\272\345\000", 4)); EXPECT_EQ(8, ild("\017\276\004\225\000\000\000\000", 8)); EXPECT_EQ(8, ild("\017\276\004\325\000\000\000\000", 8)); EXPECT_EQ(8, ild("\017\276\014\325\000\000\000\000", 8)); EXPECT_EQ(4, ild("\017\276A\000", 4)); EXPECT_EQ(4, ild("\017\276F\000", 4)); EXPECT_EQ(4, ild("\017\276G\000", 4)); EXPECT_EQ(4, ild("\017\276J\000", 4)); EXPECT_EQ(4, ild("\017\276N\000", 4)); EXPECT_EQ(4, ild("\017\276O\000", 4)); EXPECT_EQ(4, ild("\017\276V\000", 4)); EXPECT_EQ(7, ild("\017\276\200\000\000\000\000", 7)); EXPECT_EQ(7, ild("\017\276\201\000\000\000\000", 7)); EXPECT_EQ(8, ild("\017\276\204\022\000\000\000\000", 8)); EXPECT_EQ(3, ild("\017\276\370", 3)); EXPECT_EQ(3, ild("\017\277\307", 3)); EXPECT_EQ(3, ild("\017\277\370", 3)); EXPECT_EQ(4, ild("@\017\224\306", 4)); EXPECT_EQ(4, ild("@\017\224\307", 4)); EXPECT_EQ(4, ild("@\017\236\305", 4)); EXPECT_EQ(4, ild("@\017\266\305", 4)); EXPECT_EQ(4, ild("@\017\266\307", 4)); EXPECT_EQ(4, ild("@\017\266\315", 4)); EXPECT_EQ(4, ild("@\017\266\316", 4)); EXPECT_EQ(4, ild("@\017\266\325", 4)); EXPECT_EQ(4, ild("@\017\266\366", 4)); EXPECT_EQ(4, ild("@\017\266\377", 4)); EXPECT_EQ(4, ild("@\017\276\307", 4)); EXPECT_EQ(4, ild("A\017\224\300", 4)); EXPECT_EQ(4, ild("A\017\225\304", 4)); EXPECT_EQ(5, ild("A\017\266,\020", 5)); EXPECT_EQ(5, ild("A\017\2664\000", 5)); EXPECT_EQ(6, ild("A\017\266D$\000", 6)); EXPECT_EQ(6, ild("A\017\266|,\000", 6)); EXPECT_EQ(6, ild("A\017\267D$\000", 6)); EXPECT_EQ(4, ild("D\017\266\007", 4)); EXPECT_EQ(4, ild("D\017\266 ", 4)); EXPECT_EQ(5, ild("D\017\266$0", 5)); EXPECT_EQ(4, ild("D\017\266'", 4)); EXPECT_EQ(5, ild("D\017\266,\010", 5)); EXPECT_EQ(4, ild("D\017\266/", 4)); EXPECT_EQ(5, ild("D\017\266G\000", 5)); EXPECT_EQ(5, ild("D\017\266k\000", 5)); EXPECT_EQ(5, ild("D\017\266u\000", 5)); EXPECT_EQ(5, ild("E\017\266\014\000", 5)); EXPECT_EQ(5, ild("E\017\2664$", 5)); EXPECT_EQ(5, ild("E\017\266u\000", 5)); EXPECT_EQ(4, ild("E\017\266\300", 4)); EXPECT_EQ(4, ild("E\017\267\300", 4)); EXPECT_EQ(4, ild("H\017\243\316", 4)); EXPECT_EQ(4, ild("H\017\243\320", 4)); EXPECT_EQ(4, ild("H\017\243\321", 4)); EXPECT_EQ(9, ild("H\017\276\004\325\000\000\000\000", 9)); EXPECT_EQ(4, ild("H\017\276\022", 4)); EXPECT_EQ(4, ild("H\017\276\307", 4)); EXPECT_EQ(4, ild("H\017\276\366", 4)); EXPECT_EQ(4, ild("H\017\277\022", 4)); EXPECT_EQ(4, ild("H\017\277\307", 4)); EXPECT_EQ(4, ild("H\017\277\366", 4)); EXPECT_EQ(5, ild("f@\017\276\307", 5)); EXPECT_EQ(2, ild("\363\253", 2)); } TEST(ild, testBinary) { EXPECT_EQ(2, ild("\000\000", 2)); EXPECT_EQ(6, ild("\000\270\000\000\000\000", 6)); EXPECT_EQ(2, ild("\000\301", 2)); EXPECT_EQ(2, ild("\000\377", 2)); EXPECT_EQ(6, ild("\001\260\000\000\000\000", 6)); EXPECT_EQ(2, ild("\001\300", 2)); EXPECT_EQ(2, ild("\001\301", 2)); EXPECT_EQ(2, ild("\001\302", 2)); EXPECT_EQ(2, ild("\001\305", 2)); EXPECT_EQ(2, ild("\001\310", 2)); EXPECT_EQ(2, ild("\001\311", 2)); EXPECT_EQ(2, ild("\001\320", 2)); EXPECT_EQ(2, ild("\001\322", 2)); EXPECT_EQ(2, ild("\001\326", 2)); EXPECT_EQ(2, ild("\001\360", 2)); EXPECT_EQ(2, ild("\001\376", 2)); EXPECT_EQ(3, ild("\017\257\302", 3)); EXPECT_EQ(2, ild("\031\300", 2)); EXPECT_EQ(2, ild(")\302", 2)); EXPECT_EQ(2, ild(")\303", 2)); EXPECT_EQ(2, ild(")\305", 2)); EXPECT_EQ(2, ild(")\335", 2)); EXPECT_EQ(2, ild(")\350", 2)); EXPECT_EQ(3, ild("8W\000", 3)); EXPECT_EQ(2, ild("9\301", 2)); EXPECT_EQ(2, ild("9\302", 2)); EXPECT_EQ(2, ild("9\303", 2)); EXPECT_EQ(2, ild("9\305", 2)); EXPECT_EQ(2, ild("9\312", 2)); EXPECT_EQ(2, ild("9\320", 2)); EXPECT_EQ(2, ild("9\330", 2)); EXPECT_EQ(2, ild("9\353", 2)); EXPECT_EQ(2, ild("9\360", 2)); EXPECT_EQ(2, ild("9\361", 2)); EXPECT_EQ(2, ild("9\367", 2)); EXPECT_EQ(2, ild("9\371", 2)); EXPECT_EQ(3, ild(":C\000", 3)); EXPECT_EQ(3, ild(":K\000", 3)); EXPECT_EQ(3, ild(":S\000", 3)); EXPECT_EQ(2, ild("<\000", 2)); EXPECT_EQ(5, ild("=\000\000\000\000", 5)); EXPECT_EQ(3, ild("@8\361", 3)); EXPECT_EQ(4, ild("@\200\376\000", 4)); EXPECT_EQ(4, ild("@\200\377\000", 4)); EXPECT_EQ(3, ild("A)\314", 3)); EXPECT_EQ(3, ild("A8\355", 3)); EXPECT_EQ(3, ild("A9\301", 3)); EXPECT_EQ(3, ild("A9\304", 3)); EXPECT_EQ(3, ild("A9\306", 3)); EXPECT_EQ(3, ild("A9\320", 3)); EXPECT_EQ(3, ild("A9\321", 3)); EXPECT_EQ(3, ild("A9\335", 3)); EXPECT_EQ(3, ild("A9\354", 3)); EXPECT_EQ(3, ild("A9\356", 3)); EXPECT_EQ(3, ild("A9\365", 3)); EXPECT_EQ(5, ild("A\200<\000\000", 5)); EXPECT_EQ(6, ild("A\200|$\000\000", 6)); EXPECT_EQ(4, ild("A\200\370\000", 4)); EXPECT_EQ(4, ild("A\200\371\000", 4)); EXPECT_EQ(7, ild("A\201\370\000\000\000\000", 7)); EXPECT_EQ(4, ild("A\203\370\000", 4)); EXPECT_EQ(4, ild("A\203\371\000", 4)); EXPECT_EQ(4, ild("A\203\373\000", 4)); EXPECT_EQ(4, ild("A\203\374\000", 4)); EXPECT_EQ(4, ild("A\203\375\000", 4)); EXPECT_EQ(4, ild("A\203\376\000", 4)); EXPECT_EQ(3, ild("A\377\301", 3)); EXPECT_EQ(3, ild("A\377\302", 3)); EXPECT_EQ(3, ild("A\377\304", 3)); EXPECT_EQ(3, ild("A\377\306", 3)); EXPECT_EQ(3, ild("A\377\307", 3)); EXPECT_EQ(3, ild("A\377\310", 3)); EXPECT_EQ(3, ild("A\377\317", 3)); EXPECT_EQ(3, ild("D\001\310", 3)); EXPECT_EQ(3, ild("D\001\350", 3)); EXPECT_EQ(3, ild("D)\300", 3)); EXPECT_EQ(3, ild("D)\321", 3)); EXPECT_EQ(3, ild("D)\335", 3)); EXPECT_EQ(3, ild("D)\341", 3)); EXPECT_EQ(3, ild("D8\301", 3)); EXPECT_EQ(3, ild("D9\302", 3)); EXPECT_EQ(3, ild("D9\305", 3)); EXPECT_EQ(3, ild("D9\307", 3)); EXPECT_EQ(3, ild("D9\311", 3)); EXPECT_EQ(3, ild("D9\341", 3)); EXPECT_EQ(3, ild("D9\343", 3)); EXPECT_EQ(3, ild("D9\345", 3)); EXPECT_EQ(3, ild("D9\350", 3)); EXPECT_EQ(3, ild("D9\363", 3)); EXPECT_EQ(3, ild("E\001\342", 3)); EXPECT_EQ(3, ild("E\001\344", 3)); EXPECT_EQ(3, ild("E)\304", 3)); EXPECT_EQ(3, ild("E9\356", 3)); EXPECT_EQ(3, ild("E9\357", 3)); EXPECT_EQ(3, ild("E9\364", 3)); EXPECT_EQ(3, ild("E9\376", 3)); EXPECT_EQ(3, ild("H\001\300", 3)); EXPECT_EQ(3, ild("H\001\301", 3)); EXPECT_EQ(3, ild("H\001\302", 3)); EXPECT_EQ(3, ild("H\001\306", 3)); EXPECT_EQ(3, ild("H\001\310", 3)); EXPECT_EQ(3, ild("H\001\312", 3)); EXPECT_EQ(3, ild("H\001\320", 3)); EXPECT_EQ(3, ild("H\001\321", 3)); EXPECT_EQ(3, ild("H\001\322", 3)); EXPECT_EQ(3, ild("H\001\336", 3)); EXPECT_EQ(3, ild("H\001\337", 3)); EXPECT_EQ(3, ild("H\001\357", 3)); EXPECT_EQ(3, ild("H\001\360", 3)); EXPECT_EQ(3, ild("H\001\362", 3)); EXPECT_EQ(3, ild("H\001\370", 3)); EXPECT_EQ(4, ild("H\003G\000", 4)); EXPECT_EQ(4, ild("H\003S\000", 4)); EXPECT_EQ(6, ild("H\005\000\000\000\000", 6)); EXPECT_EQ(4, ild("H\017\257\310", 4)); EXPECT_EQ(4, ild("H\017\257\312", 4)); EXPECT_EQ(4, ild("H\017\257\320", 4)); EXPECT_EQ(3, ild("H)\332", 3)); EXPECT_EQ(6, ild("H-\000\000\000\000", 6)); EXPECT_EQ(3, ild("H9\301", 3)); EXPECT_EQ(3, ild("H9\302", 3)); EXPECT_EQ(3, ild("H9\307", 3)); EXPECT_EQ(3, ild("H9\310", 3)); EXPECT_EQ(3, ild("H9\312", 3)); EXPECT_EQ(3, ild("H9\320", 3)); EXPECT_EQ(3, ild("H9\326", 3)); EXPECT_EQ(3, ild("H9\330", 3)); EXPECT_EQ(3, ild("H9\360", 3)); EXPECT_EQ(3, ild("H9\361", 3)); EXPECT_EQ(3, ild("H9\362", 3)); EXPECT_EQ(3, ild("H9\370", 3)); EXPECT_EQ(6, ild("H=\000\000\000\000", 6)); EXPECT_EQ(7, ild("H\201\304\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\201\353\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\201\354\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\201\356\000\000\000\000", 7)); EXPECT_EQ(7, ild("H\201\377\000\000\000\000", 7)); EXPECT_EQ(5, ild("H\203\177\000\000", 5)); EXPECT_EQ(4, ild("H\203\300\000", 4)); EXPECT_EQ(4, ild("H\203\302\000", 4)); EXPECT_EQ(4, ild("H\203\303\000", 4)); EXPECT_EQ(4, ild("H\203\304\000", 4)); EXPECT_EQ(4, ild("H\203\350\000", 4)); EXPECT_EQ(4, ild("H\203\353\000", 4)); EXPECT_EQ(4, ild("H\203\354\000", 4)); EXPECT_EQ(4, ild("H\203\370\000", 4)); EXPECT_EQ(4, ild("H\203\371\000", 4)); EXPECT_EQ(4, ild("H\203\372\000", 4)); EXPECT_EQ(4, ild("H\203\373\000", 4)); EXPECT_EQ(4, ild("H\203\376\000", 4)); EXPECT_EQ(4, ild("H\203\377\000", 4)); EXPECT_EQ(3, ild("H\367\333", 3)); EXPECT_EQ(3, ild("H\367\361", 3)); EXPECT_EQ(3, ild("H\367\366", 3)); EXPECT_EQ(3, ild("H\367\367", 3)); EXPECT_EQ(3, ild("H\377\300", 3)); EXPECT_EQ(3, ild("H\377\301", 3)); EXPECT_EQ(3, ild("H\377\302", 3)); EXPECT_EQ(3, ild("H\377\305", 3)); EXPECT_EQ(3, ild("H\377\306", 3)); EXPECT_EQ(3, ild("H\377\307", 3)); EXPECT_EQ(3, ild("H\377\310", 3)); EXPECT_EQ(3, ild("H\377\311", 3)); EXPECT_EQ(3, ild("I\001\321", 3)); EXPECT_EQ(3, ild("I)\302", 3)); EXPECT_EQ(3, ild("I\367\334", 3)); EXPECT_EQ(3, ild("I\367\361", 3)); EXPECT_EQ(3, ild("I\377\300", 3)); EXPECT_EQ(3, ild("I\377\305", 3)); EXPECT_EQ(3, ild("L\001\300", 3)); EXPECT_EQ(3, ild("L\001\340", 3)); EXPECT_EQ(3, ild("L\001\350", 3)); EXPECT_EQ(4, ild("L\003O\000", 4)); EXPECT_EQ(3, ild("L)\300", 3)); EXPECT_EQ(3, ild("f9\312", 3)); EXPECT_EQ(3, ild("f9\320", 3)); EXPECT_EQ(4, ild("f=\000\000", 4)); EXPECT_EQ(5, ild("f\201\302\000\000", 5)); EXPECT_EQ(5, ild("f\201\372\000\000", 5)); EXPECT_EQ(5, ild("f\201\375\000\000", 5)); EXPECT_EQ(5, ild("f\203x\000\000", 5)); EXPECT_EQ(4, ild("f\203\370\000", 4)); EXPECT_EQ(4, ild("f\203\371\000", 4)); EXPECT_EQ(4, ild("f\203\372\000", 4)); EXPECT_EQ(3, ild("\2008\000", 3)); EXPECT_EQ(7, ild("\200=\000\000\000\000\000", 7)); EXPECT_EQ(4, ild("\200x\000\000", 4)); EXPECT_EQ(4, ild("\200z\000\000", 4)); EXPECT_EQ(4, ild("\200{\000\000", 4)); EXPECT_EQ(4, ild("\200}\000\000", 4)); EXPECT_EQ(4, ild("\200\177\000\000", 4)); EXPECT_EQ(3, ild("\200\371\000", 3)); EXPECT_EQ(3, ild("\200\372\000", 3)); EXPECT_EQ(6, ild("\201\353\000\000\000\000", 6)); EXPECT_EQ(6, ild("\201\372\000\000\000\000", 6)); EXPECT_EQ(6, ild("\201\377\000\000\000\000", 6)); EXPECT_EQ(4, ild("\203<$\000", 4)); EXPECT_EQ(8, ild("\203<\325\000\000\000\000\000", 8)); EXPECT_EQ(7, ild("\203=\000\000\000\000\000", 7)); EXPECT_EQ(4, ild("\203x\000\000", 4)); EXPECT_EQ(4, ild("\203}\000\000", 4)); EXPECT_EQ(4, ild("\203\177\000\000", 4)); EXPECT_EQ(7, ild("\203\270\000\000\000\000\000", 7)); EXPECT_EQ(3, ild("\203\301\000", 3)); EXPECT_EQ(3, ild("\203\302\000", 3)); EXPECT_EQ(3, ild("\203\307\000", 3)); EXPECT_EQ(3, ild("\203\350\000", 3)); EXPECT_EQ(3, ild("\203\351\000", 3)); EXPECT_EQ(3, ild("\203\352\000", 3)); EXPECT_EQ(3, ild("\203\370\000", 3)); EXPECT_EQ(3, ild("\203\371\000", 3)); EXPECT_EQ(3, ild("\203\372\000", 3)); EXPECT_EQ(3, ild("\203\373\000", 3)); EXPECT_EQ(3, ild("\203\375\000", 3)); EXPECT_EQ(3, ild("\203\376\000", 3)); EXPECT_EQ(3, ild("\203\377\000", 3)); EXPECT_EQ(3, ild("\367u\000", 3)); EXPECT_EQ(2, ild("\367\333", 2)); EXPECT_EQ(3, ild("\376C\000", 3)); EXPECT_EQ(2, ild("\376\310", 2)); EXPECT_EQ(2, ild("\376\311", 2)); EXPECT_EQ(2, ild("\376\312", 2)); EXPECT_EQ(2, ild("\377\300", 2)); EXPECT_EQ(2, ild("\377\301", 2)); EXPECT_EQ(2, ild("\377\302", 2)); EXPECT_EQ(2, ild("\377\303", 2)); EXPECT_EQ(2, ild("\377\305", 2)); EXPECT_EQ(2, ild("\377\306", 2)); EXPECT_EQ(2, ild("\377\310", 2)); EXPECT_EQ(2, ild("\377\312", 2)); EXPECT_EQ(2, ild("\377\316", 2)); } TEST(ild, testWideNops) { EXPECT_EQ(1, ild("\220", 1)); EXPECT_EQ(2, ild("f\220", 2)); EXPECT_EQ(3, ild("\017\037\000", 3)); EXPECT_EQ(4, ild("\017\037@\000", 4)); EXPECT_EQ(5, ild("\017\037D\000\000", 5)); EXPECT_EQ(6, ild("f\017\037D\000\000", 6)); EXPECT_EQ(7, ild("\017\037\200\000\000\000\000", 7)); EXPECT_EQ(8, ild("\017\037\204\000\000\000\000\000", 8)); EXPECT_EQ(9, ild("f\017\037\204\000\000\000\000\000", 9)); } #ifndef DISABLE_BMI2 TEST(ild, mulx) { // mulx %rbx,%rdx,%rcx char code[15] = "\xc4\xe2\xeb\xf6\xcb"; EXPECT_EQ(0, DecodeInstruction(&xedd, code, 15, XED_MODE_LONG)); EXPECT_EQ(5, xedd.length); EXPECT_EQ(2 << 8 | 0xf6, Mopcode(xedd.op.rde)); EXPECT_EQ(3, ModrmMod(xedd.op.rde)); // register operand EXPECT_TRUE(Rexw(xedd.op.rde)); // 64-bit EXPECT_EQ(1, ModrmReg(xedd.op.rde)); // rcx (arg1) EXPECT_EQ(2, Vreg(xedd.op.rde)); // rdx (arg2) EXPECT_EQ(3, ModrmRm(xedd.op.rde)); // rbx (arg3) } TEST(ild, shlx) { // mulx %rbx,%rdx,%rcx char code[15] = "\xc4\xe2\x71\xf7\xd8"; EXPECT_EQ(0, DecodeInstruction(&xedd, code, 15, XED_MODE_LONG)); EXPECT_EQ(5, xedd.length); EXPECT_EQ(2 << 8 | 0xf7, Mopcode(xedd.op.rde)); EXPECT_EQ(3, ModrmMod(xedd.op.rde)); // register operand EXPECT_TRUE(!Rexw(xedd.op.rde)); // 32-bit EXPECT_EQ(3, ModrmReg(xedd.op.rde)); // EXPECT_EQ(1, Vreg(xedd.op.rde)); // EXPECT_EQ(0, ModrmRm(xedd.op.rde)); // EXPECT_TRUE(Osz(xedd.op.rde)); // } #endif /* DISABLE_BMI2 */ ================================================ FILE: test/flat/flat.S ================================================ .globl _start _start: // make -j8 o//blink o//test/flat/flat.bin // o//blink/blink o//test/flat/flat.bin mov $msg.len,%edx # arg 3 = strlen(msg) lea msg(%rip),%rsi # arg 2 = msg mov $1,%edi # arg 1 = 1 mov $1,%eax # __NR_write syscall mov $0,%edi # arg1 = 0 mov $231,%eax # __NR_exit syscall msg: .ascii "hello! i am a flat executable.\n" msg.len = . - msg ================================================ FILE: test/flat/flat.lds ================================================ ENTRY(_start) OUTPUT_FORMAT(binary) SECTIONS { . = 0x400000; .text : { *(.text) *(.rodata .rodata.*) } .bss : { *(.bss) } /DISCARD/ : { *(.*) } } ================================================ FILE: test/flat/flat.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ TEST_FLAT_FILES := $(wildcard test/flat/*) TEST_FLAT_SRCS = $(filter %.S,$(TEST_FLAT_FILES)) TEST_FLAT_OBJS = $(TEST_FLAT_SRCS:%.S=o/$(MODE)/x86_64/%.o) TEST_FLAT_BINS = $(TEST_FLAT_SRCS:%.S=o/$(MODE)/%.bin) TEST_FLAT_CHECKS = $(TEST_FLAT_BINS:%=%.ok) TEST_FLAT_LINK = \ $(VM) \ o/third_party/gcc/x86_64/bin/x86_64-linux-musl-ld.bfd \ -T test/flat/flat.lds \ -static \ $< \ -o $@ .PRECIOUS: o/$(MODE)/test/flat/%.bin o/$(MODE)/test/flat/%.bin: \ o/$(MODE)/x86_64/test/flat/%.o \ o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc \ test/flat/flat.lds \ $(VM) @mkdir -p $(@D) $(TEST_FLAT_LINK) $(TEST_FLAT_OBJS): test/flat/flat.mk # the .com extension is for cosmopolitan/tool/emacs/ integration o/$(MODE)/test/flat/%.com: \ o/$(MODE)/test/flat/%.bin \ o/$(MODE)/blink/blink @echo "#!/bin/sh" >$@ @echo "o/$(MODE)/blink/blink $< || exit" >>$@ @chmod +x $@ o/$(MODE)/test/flat/%.bin.ok: o/$(MODE)/test/flat/%.bin o/$(MODE)/blink/blink @mkdir -p $(@D) o/$(MODE)/blink/blink $< @touch $@ o/$(MODE)/test/flat: \ $(TEST_FLAT_CHECKS) ================================================ FILE: test/func/README.md ================================================ # Blink Functional Tests Blink's "functional tests" are simple `x86_64-linux` programs written in C that are run both under Blink, and under the host `x86_64-linux` system for comparison. These tests are built using a statically compiled musl-cross-make toolchain that the build system downloads automatically. If the host system is not AMD64 Linux, then we fake it using `$(VM)`. Functional tests also useful for testing various flag combinations: - `blink` checks JIT + LINEAR MEMORY works - `blink -j` checks INTERPRETED + LINEAR MEMORY works - `blink -m` checks JIT + VIRTUALIZED MEMORY works - `blink -jm` checks INTERPRETED + VIRTUALIZED MEMORY works - `blink -s` checks system call logging doesn't break things ================================================ FILE: test/func/busted_test.c ================================================ // 1. test SIGBUS is delivered to guest correctly // 2. test `blink -m` can reverse map a host addr // TODO(jart): terminates due to sigbus on cygwin // TODO(jart): why does silicon trap on the int3? #include #include #include #include char *map; void OnBusted(int sig, siginfo_t *si, void *vctx) { if (sig != SIGBUS) _exit(8); if (si->si_signo != SIGBUS) _exit(9); if (si->si_code != BUS_ADRALN) { // TODO(jart): Why do XNU and FreeBSD report BUS_ADRALN? if (si->si_code != BUS_ADRERR) _exit(10); } if (si->si_addr != map + 65536) _exit(11); _exit(0); } int main(int argc, char *argv[]) { char path[] = "/tmp/blink.test.XXXXXX"; if (mkstemp(path) != 3) return 1; if (unlink(path)) return 2; map = (char *)mmap(0, 65536 * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE, 3, 0); if (map == MAP_FAILED) return 5; // ensure first page in file exists if (ftruncate(3, 1)) return 3; map[0] = 1; // trigger page fault that loads the first page into memory map[1] = 2; // modifying memory past file eof is ok if it's within page struct sigaction sa = {.sa_sigaction = OnBusted, .sa_flags = SA_SIGINFO}; if (sigaction(SIGBUS, &sa, 0)) return 4; map[65536] = 1; // trigger page fault to load second page of file asm("int3"); // it triggers SIGBUS immediately instead of this return 7; } ================================================ FILE: test/func/cycle2_test.c ================================================ // checks non-obvious cycle doesn't prevent asynchronous signals #include #include #include void OnSig(int sig) { _exit(0); } int main(int argc, char *argv[]) { ssize_t got; int ws, pid; if (!(pid = fork())) { struct sigaction sa = {.sa_handler = OnSig}; sigaction(SIGUSR1, &sa, 0); asm("\ nop\n\ 1: nop\n\ jmp 2f\n\ 2: nop\n\ jmp 1b"); } sleep(1); kill(pid, SIGUSR1); wait(&ws); return WEXITSTATUS(ws); } ================================================ FILE: test/func/cycle_test.c ================================================ // checks obvious cycle doesn't prevent asynchronous signals #include #include #include void OnSig(int sig) { _exit(0); } int main(int argc, char *argv[]) { ssize_t got; int ws, pid; if (!(pid = fork())) { struct sigaction sa = {.sa_handler = OnSig}; sigaction(SIGUSR1, &sa, 0); for (;;) { } } sleep(1); kill(pid, SIGUSR1); wait(&ws); return WEXITSTATUS(ws); } ================================================ FILE: test/func/eintr_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include // signal delivery causes blocking i/o calls to return EINTR // see also norestart_test.c // see also restart_test.c int fds[2]; volatile int gotsig; void OnSig(int sig, siginfo_t *si, void *ptr) { gotsig = 1; } int main(int argc, char *argv[]) { char b; ssize_t got; int ws, pid; sigaction(SIGUSR1, &(struct sigaction){.sa_sigaction = OnSig}, 0); pipe(fds); if (!(pid = fork())) { close(fds[1]); got = read(fds[0], &b, 1); if (got == -1 && errno == EINTR && gotsig) { _exit(0); } else { _exit(1); } } close(fds[0]); sleep(1); kill(pid, SIGUSR1); wait(&ws); return WEXITSTATUS(ws); } ================================================ FILE: test/func/fstatat_at_empty_path.c ================================================ #define _GNU_SOURCE #include #include #include #include int main(int argc, char *argv[]) { struct stat st; char path[] = "/tmp/blink.test.XXXXXX"; if (mkstemp(path) != 3) return 1; if (unlink(path)) return 2; if (write(3, "hi", 2) != 2) return 3; if (fstatat(3, "", &st, AT_EMPTY_PATH)) return 4; if (st.st_size != 2) return 5; return 0; } ================================================ FILE: test/func/func.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ PKGS += TEST_FUNC TEST_FUNC_FILES := $(wildcard test/func/*) ifeq ($(HOST_SYSTEM), Darwin) TEST_FUNC_FILES := $(filter-out test/func/busted_test.c,$(TEST_FUNC_FILES)) endif ifeq ($(HOST_OS), Cygwin) TEST_FUNC_FILES := $(filter-out test/func/busted_test.c,$(TEST_FUNC_FILES)) endif TEST_FUNC_SRCS = $(filter %.c,$(TEST_FUNC_FILES)) TEST_FUNC_OBJS = $(TEST_FUNC_SRCS:%.c=o/$(MODE)/x86_64/%.o) TEST_FUNC_BINS = $(TEST_FUNC_SRCS:%.c=o/$(MODE)/%.elf) TEST_FUNC_COMS = $(TEST_FUNC_SRCS:%.c=o/$(MODE)/%.com) TEST_FUNC_CHECKS = $(TEST_FUNC_SRCS:%.c=o/$(MODE)/%.com.ok) TEST_FUNC_EMULATES = $(foreach ARCH,$(ARCHITECTURES),$(foreach SRC,$(filter-out $(TEST_FUNC_NOEMU),$(TEST_FUNC_SRCS)),$(SRC:%.c=o/$(MODE)/$(ARCH)/%.elf.emulates))) # qemu static doesn't appear to emulate this correctly TEST_FUNC_NOEMU = test/func/busted_test.c TEST_FUNC_LINK = \ $(VM) \ o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc \ -static \ -Wl,-z,max-page-size=65536 \ -Wl,-z,common-page-size=65536 \ $< \ -o $@ o/$(MODE)/test/func/%.com.ok: \ o/$(MODE)/test/func/%.com \ o/$(MODE)/blink/blink $< @touch $@ $(TEST_FUNC_OBJS): private CFLAGS = -O -g $(TEST_FUNC_OBJS): private CPPFLAGS = -isystem. .PRECIOUS: o/$(MODE)/test/func/%.elf o/$(MODE)/test/func/%.elf: \ o/$(MODE)/x86_64/test/func/%.o \ o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc \ $(VM) @mkdir -p $(@D) $(TEST_FUNC_LINK) $(TEST_FUNC_OBJS): test/func/func.mk .PRECIOUS: o/$(MODE)/test/func/%.com o/$(MODE)/test/func/%.com: \ o/$(MODE)/test/func/%.elf \ o/$(MODE)/blink/blink @mkdir -p $(@D) @echo "#!/bin/sh" >$@ @echo "echo [test] $(VM) $< >&2" >>$@ @echo "$(VM) $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink $< >&2" >>$@ @echo "o/$(MODE)/blink/blink $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink -jm $< >&2" >>$@ @echo "o/$(MODE)/blink/blink -jm $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink -m $< >&2" >>$@ @echo "o/$(MODE)/blink/blink -m $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink -j $< >&2" >>$@ @echo "o/$(MODE)/blink/blink -j $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink -L/dev/null -sss $< >&2" >>$@ @echo "o/$(MODE)/blink/blink -L/dev/null -sss $< || exit" >>$@ @echo "echo [test] o/$(MODE)/blink/blink -L/dev/null -msss $< >&2" >>$@ @echo "o/$(MODE)/blink/blink -L/dev/null -msss $< || exit" >>$@ @chmod +x $@ .PHONY: o/$(MODE)/test/func o/$(MODE)/test/func: \ $(TEST_FUNC_CHECKS) .PHONY: o/$(MODE)/test/func/emulates o/$(MODE)/test/func/emulates: \ $(TEST_FUNC_EMULATES) ================================================ FILE: test/func/futex_multiprocess_test.c ================================================ // test that futexes work across processes // clang-format off #include #include #include #include #include #include int main(int argc, char *argv[]) { int ws; FILE *f; pid_t pid; pthread_condattr_t ca; pthread_mutexattr_t ma; struct Shared { atomic_int state; pthread_cond_t cond; pthread_mutex_t lock; } *s; if (!(f = tmpfile())) return 0; if (ftruncate(fileno(f), 4096)) return 1; if ((s = (struct Shared *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) return 2; if (pthread_condattr_init(&ca)) return 3; if (pthread_mutexattr_init(&ma)) return 4; if (pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED)) return 5; if (pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED)) return 6; if (pthread_cond_init(&s->cond, &ca)) return 7; if (pthread_mutex_init(&s->lock, &ma)) return 8; if (pthread_mutexattr_destroy(&ma)) return 9; if (pthread_condattr_destroy(&ca)) return 10; if ((pid = fork()) == -1) return 11; if (!pid) { alarm(15); if (pthread_mutex_lock(&s->lock)) return 12; s->state = 1; if (pthread_cond_wait(&s->cond, &s->lock)) return 13; if (pthread_mutex_unlock(&s->lock)) return 14; while (s->state != 2); if (pthread_mutex_lock(&s->lock)) return 15; if (pthread_cond_signal(&s->cond)) return 16; if (pthread_mutex_unlock(&s->lock)) return 17; _exit(0); } alarm(15); while (s->state != 1); if (pthread_mutex_lock(&s->lock)) return 18; if (pthread_cond_signal(&s->cond)) return 19; if (pthread_mutex_unlock(&s->lock)) return 20; if (pthread_mutex_lock(&s->lock)) return 21; s->state = 2; if (pthread_cond_wait(&s->cond, &s->lock)) return 22; if (pthread_mutex_unlock(&s->lock)) return 23; if (wait(&ws) != pid) return 24; if (!WIFEXITED(ws)) return 25; if (WEXITSTATUS(ws)) return 26; if (pthread_mutex_destroy(&s->lock)) return 27; if (pthread_cond_destroy(&s->cond)) return 28; return 0; } ================================================ FILE: test/func/getrandom_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include /* * assuming the system is working correctly there's a 1 in * 235716896562095165800448 chance this check should flake */ #define BYTES 9 #define TRIES 16 void TestDataSeemsRandom(void) { ssize_t rc; size_t i, j; int haszero, fails = 0; for (i = 0; i < TRIES; ++i) { unsigned char x[BYTES] = {0}; rc = syscall(SYS_getrandom, x, BYTES, 0); if (rc == -1) exit(1); if (rc != BYTES) exit(2); for (haszero = j = 0; j < BYTES; ++j) { if (!x[j]) haszero = 1; } if (haszero) ++fails; } if (fails >= TRIES) exit(3); } void TestApi(void) { long x; if (syscall(SYS_getrandom, 0, 0, 0) != 0) exit(4); if (syscall(SYS_getrandom, (void *)-1, 1, 0) != -1) exit(5); if (errno != EFAULT) exit(6); if (syscall(SYS_getrandom, &x, sizeof(x), -1) != -1) exit(7); if (errno != EINVAL) exit(8); } int main(int argc, char *argv[]) { TestDataSeemsRandom(); TestApi(); return 0; } ================================================ FILE: test/func/largefile_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "test/test.h" /** * @fileoverview Large File Tests * * This test ensures that the Blink Virtual Machine is able to host, on * 32-bit platforms, x86_64 binaries that perform 64-bit I/O operations */ #define SIZE (5LL * 1024 * 1024 * 1024) void SetUp(void) { } void TearDown(void) { } TEST(largefile, test) { struct stat st; char path[] = "/tmp/blink.test.XXXXXX"; char b3[8], b2[8], b1[8] = {1, 2, 3, 4, 5, 6, 7, 8}; ASSERT_EQ(3, mkstemp(path)); ASSERT_EQ(0, close(3)); EXPECT_EQ(3, open(path, O_RDWR | O_CREAT | O_TRUNC, 0644)); EXPECT_EQ(0, ftruncate(3, SIZE)); EXPECT_EQ(0, fstat(3, &st)); EXPECT_EQ(SIZE, st.st_size); EXPECT_EQ(8, pwrite(3, b1, 8, SIZE - 8)); EXPECT_EQ(8, pread(3, b2, 8, SIZE - 8)); EXPECT_EQ(0, memcmp(b1, b2, 8)); EXPECT_EQ(SIZE - 8, lseek(3, SIZE - 8, SEEK_SET)); EXPECT_EQ(8, read(3, b3, 8)); EXPECT_EQ(0, memcmp(b1, b3, 8)); EXPECT_EQ(0, close(3)); EXPECT_EQ(0, unlink(path)); } ================================================ FILE: test/func/lock_test.c ================================================ #include #include #include #include #include #include #define THREADS 4 #define ITERATIONS 10000 _Alignas(128) static int a; _Alignas(128) static int b; _Alignas(128) static atomic_int lock; static void Lock(void) { int x; for (;;) { x = atomic_exchange_explicit(&lock, 1, memory_order_acquire); if (!x) break; } } static void Unlock(void) { atomic_store_explicit(&lock, 0, memory_order_release); } static void *Worker(void *arg) { int i; for (i = 0; i < ITERATIONS; ++i) { Lock(); assert(b == a * 2); ++a; b = a * 2; Unlock(); } return 0; } int main(int argc, char *argv[]) { int i; pthread_t t[THREADS]; for (i = 0; i < THREADS; ++i) { pthread_create(t + i, 0, Worker, 0); } for (i = 0; i < THREADS; ++i) { pthread_join(t[i], 0); } } ================================================ FILE: test/func/mem64_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "test/test.h" #define WORKERS 4 #define ITERATIONS 100000 void SetUp(void) { } void TearDown(void) { } static atomic_ulong word; //////////////////////////////////////////////////////////////////////////////// static void *AddWorker(void *arg) { int i; unsigned long x; for (i = 0; i < ITERATIONS; ++i) { x = atomic_load_explicit(&word, memory_order_relaxed); ASSERT_EQ(x & 0xffffffff, x >> 32); x += 1ul | 1ul << 32; atomic_store_explicit(&word, x, memory_order_relaxed); } return 0; } TEST(mem64, add) { int i; pthread_t t[WORKERS]; for (i = 0; i < WORKERS; ++i) { ASSERT_EQ(0, pthread_create(t + i, 0, AddWorker, 0)); } for (i = 0; i < WORKERS; ++i) { ASSERT_EQ(0, pthread_join(t[i], 0)); } } //////////////////////////////////////////////////////////////////////////////// static void *XaddWorker(void *arg) { int i; unsigned long x; for (i = 0; i < ITERATIONS; ++i) { x = atomic_fetch_add_explicit(&word, 1ul | 1ul << 32, memory_order_relaxed); ASSERT_EQ(x & 0xffffffff, x >> 32); } return 0; } TEST(mem64, xadd) { int i; pthread_t t[WORKERS]; for (i = 0; i < WORKERS; ++i) { ASSERT_EQ(0, pthread_create(t + i, 0, XaddWorker, 0)); } for (i = 0; i < WORKERS; ++i) { ASSERT_EQ(0, pthread_join(t[i], 0)); } } ================================================ FILE: test/func/mmap_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include "blink/macros.h" #include "test/test.h" #define pagesize 65536 void SetUp(void) { } void TearDown(void) { } TEST(mmap, file_shared) { FILE *f; u8 *a, *b, *p; // we initialize the file to contain this ASSERT_NOTNULL(a = (u8 *)malloc(pagesize * 3)); memset(a, 'a', pagesize * 3); // we're going to change the file to have this ASSERT_NOTNULL(b = (u8 *)malloc(pagesize * 3)); memset(b, 'a', pagesize * 1); memset(b + pagesize, 'b', pagesize * 2); // create the file ASSERT_NOTNULL(f = tmpfile()); ASSERT_EQ(3, fwrite(a, pagesize, 3, f)); // map the file into memory starting at the second page EXPECT_NE((intptr_t)MAP_FAILED, (intptr_t)(p = (u8 *)mmap(0, pagesize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(f), pagesize))); // change the file via the memory mapping memset(p, 'b', pagesize * 2); EXPECT_NE(-1, msync(p, pagesize * 2, MS_SYNC)); // read the file back into memory and verify it's coherent rewind(f); ASSERT_EQ(3, fread(a, pagesize, 3, f)); ASSERT_EQ(0, memcmp(b, a, pagesize)); ASSERT_EQ(0, memcmp(b + pagesize, a + pagesize, pagesize)); ASSERT_EQ(0, memcmp(b + pagesize * 2, a + pagesize * 2, pagesize)); // perform cleanup duties ASSERT_EQ(0, munmap(p, pagesize * 2)); ASSERT_EQ(0, fclose(f)); free(b); free(a); } TEST(mmap, multiprocess_private_vs_shared) { int ws, pid; int stackvar; int *sharedvar; int *privatevar; EXPECT_NE((intptr_t)MAP_FAILED, (intptr_t)(sharedvar = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0))); EXPECT_NE((intptr_t)MAP_FAILED, (intptr_t)(privatevar = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))); stackvar = 1; *sharedvar = 1; *privatevar = 1; EXPECT_NE(-1, (pid = fork())); if (!pid) { ++stackvar; ++*sharedvar; ++*privatevar; msync((void *)ROUNDDOWN((intptr_t)&stackvar, pagesize), pagesize, MS_SYNC); EXPECT_NE(-1, msync(privatevar, pagesize, MS_SYNC)); EXPECT_NE(-1, msync(sharedvar, pagesize, MS_SYNC)); _exit(0); } EXPECT_NE(-1, waitpid(pid, &ws, 0)); EXPECT_EQ(1, stackvar); EXPECT_EQ(2, *sharedvar); EXPECT_EQ(1, *privatevar); EXPECT_NE(-1, munmap(sharedvar, pagesize)); EXPECT_NE(-1, munmap(privatevar, pagesize)); } TEST(mmap, suggestedAddressWithoutMapFixed_isUsedIfAvailable) { void *want, *got1, *got2; want = (void *)(intptr_t)0x300000000000; got1 = mmap(want, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); while (got1 == MAP_FAILED && errno == ENOMEM) { want = (void *)((intptr_t)want >> 1); ASSERT_EQ((intptr_t)want % pagesize, 0); got1 = mmap(want, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } ASSERT_NE((intptr_t)MAP_FAILED, (intptr_t)got1); got2 = mmap(want, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_NE((intptr_t)MAP_FAILED, (intptr_t)got2); ASSERT_NE((intptr_t)got1, (intptr_t)got2); ASSERT_NE((intptr_t)want, (intptr_t)got2); ASSERT_EQ(0, munmap(got1, pagesize)); ASSERT_EQ(0, munmap(got2, pagesize)); } ================================================ FILE: test/func/munmap_test.c ================================================ #include #include #include #include #include #include #include #include #include #define BYTES 10000 #define THREADS 4 #define ITERATIONS 256 _Atomic(void *) buf; void *Worker(void *arg) { void *b; int i, fd; ssize_t rc; if ((fd = open("/dev/zero", O_RDONLY)) == -1) { fprintf(stderr, "open failed: %s", strerror(errno)); _exit(10); } for (i = 0; i < ITERATIONS; ++i) { b = buf; rc = read(fd, b, 10000); if (rc == -1 && errno != EFAULT) _exit(2); } close(fd); return 0; } void *Alloc(void) { return mmap(0, BYTES, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } int main(int argc, char *argv[]) { int i; pthread_t t[THREADS]; buf = Alloc(); for (i = 0; i < THREADS; ++i) { if (pthread_create(t + i, 0, Worker, 0)) _exit(2); } for (i = 0; i < ITERATIONS; ++i) { munmap(atomic_exchange(&buf, Alloc()), BYTES); } for (i = 0; i < THREADS; ++i) { if (pthread_join(t[i], 0)) _exit(3); } if (munmap(buf, BYTES)) _exit(4); return 0; } ================================================ FILE: test/func/noexec2_test.c ================================================ // test mprotect(rw) prevents code from being executed #include #include #include #include typedef int math_f(int, int); const unsigned char kAdd[] = { 0x89, 0xf8, // mov %edi,%eax 0x01, 0xf0, // add %esi,%eax 0xc3, // ret }; void *p; void OnSigSegv(int sig, siginfo_t *si, void *vctx) { if (si->si_addr != p) _exit(6); if (si->si_code != SEGV_ACCERR) _exit(7); _exit(0); } int main(int argc, char *argv[]) { int i; math_f *f; p = mmap(0, 65536, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (p == MAP_FAILED) return 1; f = (math_f *)p; memcpy(p, kAdd, sizeof(kAdd)); if (mprotect(p, 65536, PROT_READ | PROT_EXEC)) return 4; if (f(20, 3) != 23) return 2; if (f(20, 3) != 23) return 2; struct sigaction sa = {.sa_sigaction = OnSigSegv, .sa_flags = SA_SIGINFO}; if (sigaction(SIGSEGV, &sa, 0)) return 3; if (mprotect(p, 65536, PROT_READ | PROT_WRITE)) return 4; f(20, 3); return 5; } ================================================ FILE: test/func/noexec3_test.c ================================================ // test munmap() prevents code from being executed #include #include #include #include typedef int math_f(int, int); const unsigned char kAdd[] = { 0x89, 0xf8, // mov %edi,%eax 0x01, 0xf0, // add %esi,%eax 0xc3, // ret }; void *p; void OnSigSegv(int sig, siginfo_t *si, void *vctx) { if (si->si_addr != p) _exit(8); if (si->si_code != SEGV_MAPERR) _exit(9); _exit(0); } int main(int argc, char *argv[]) { int i; math_f *f; p = mmap(0, 65536, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (p == MAP_FAILED) return 1; f = (math_f *)p; memcpy(p, kAdd, sizeof(kAdd)); if (mprotect(p, 65536, PROT_READ | PROT_EXEC)) return 2; if (f(20, 3) != 23) return 3; if (f(20, 3) != 23) return 4; struct sigaction sa = {.sa_sigaction = OnSigSegv, .sa_flags = SA_SIGINFO}; if (sigaction(SIGSEGV, &sa, 0)) return 5; if (munmap(p, 65536)) return 6; f(20, 3); return 7; } ================================================ FILE: test/func/noexec_test.c ================================================ // tests memory can't be executed without exec permission #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include typedef void func_t(void); const unsigned char kCode[] = { 0xc3, // ret }; void *p; void OnSigSegv(int sig, siginfo_t *si, void *vctx) { if (si->si_addr != p) _exit(5); if (si->si_code != SEGV_ACCERR) _exit(6); if ((void *)((ucontext_t *)vctx)->uc_mcontext.gregs[REG_RIP] != p) _exit(7); _exit(0); } int main(int argc, char *argv[]) { func_t *f; p = mmap(0, 65536, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (p == MAP_FAILED) return 2; f = (func_t *)p; memcpy(f, kCode, sizeof(kCode)); struct sigaction sa = {.sa_sigaction = OnSigSegv, .sa_flags = SA_SIGINFO}; if (sigaction(SIGSEGV, &sa, 0)) return 3; f(); return 4; } ================================================ FILE: test/func/norestart_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include // SA_RESTART doesn't apply to @norestart functions like sigsuspend() // see also restart_test.c // see also eintr_test.c volatile int gotsig; void OnSig(int sig, siginfo_t *si, void *ptr) { gotsig = 1; } int main(int argc, char *argv[]) { sigset_t mask; int rc, ws, pid; sigfillset(&mask); sigprocmask(SIG_BLOCK, &mask, 0); sigaction(SIGUSR1, &(struct sigaction){ .sa_sigaction = OnSig, .sa_flags = SA_RESTART, }, 0); if (!(pid = fork())) { sigemptyset(&mask); rc = sigsuspend(&mask); if (rc == -1 && errno == EINTR && gotsig) { _exit(0); } else { _exit(1); } } kill(pid, SIGUSR1); wait(&ws); return WEXITSTATUS(ws); } ================================================ FILE: test/func/preadv_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "test/test.h" char bb1[5000]; char bb2[5000]; void SetUp(void) { } void TearDown(void) { } TEST(preadv, errors) { signed char b3[8]; ASSERT_EQ(3, open("/tmp", O_RDWR | O_TMPFILE, 0644)); ASSERT_EQ(8, pwritev(3, (struct iovec[]){{b3, 8}}, 1, 0)); ASSERT_EQ(-1, preadv(3, (struct iovec[]){{0, 8}}, 1, 0)); ASSERT_EQ(EFAULT, errno); ASSERT_EQ(0, preadv(3, (struct iovec[]){{b3, 8}}, 0, 0)); ASSERT_EQ(-1, preadv(3, (struct iovec[]){{b3, 8}}, -1, 0)); ASSERT_EQ(EINVAL, errno); ASSERT_EQ(-1, preadv(3, (struct iovec[]){{b3, 8}}, 1, -1)); ASSERT_EQ(EINVAL, errno); ASSERT_EQ(-1, preadv(3, (struct iovec[]){{b3, 8}}, 99999, 0)); ASSERT_EQ(EINVAL, errno); ASSERT_EQ(0, close(3)); } TEST(preadv, test) { signed char b1[8] = {0, 1, 2, 3, 4, 5, 6, 7}; signed char b2[8] = {-1, -2, -3, -4, -5, -6, -7, -8}; signed char b3[8]; ASSERT_EQ(3, open("/tmp", O_RDWR | O_TMPFILE, 0644)); ASSERT_EQ(16, pwritev(3, (struct iovec[]){{b1, 8}, {b2, 8}}, 2, 0)); ASSERT_EQ(8, preadv(3, (struct iovec[]){{b3, 8}}, 1, 8)); ASSERT_EQ(0, memcmp(b3, b2, 8)); ASSERT_EQ(8, preadv(3, (struct iovec[]){{b3, 4}, {b3 + 4, 4}}, 2, 0)); ASSERT_EQ(0, memcmp(b3, b1, 8)); ASSERT_EQ(0, close(3)); } TEST(pwritev, test) { ASSERT_EQ(3, open("/tmp", O_RDWR | O_TMPFILE, 0644)); memset(bb1, 1, 5000); ASSERT_EQ(5000, pwritev(3, (struct iovec[]){ {bb1, 4097}, {bb1 + 4097, 903}, }, 2, 0)); ASSERT_EQ(5000, preadv(3, (struct iovec[]){ {bb2, 4097}, {bb2 + 4097, 903}, }, 2, 0)); ASSERT_EQ(0, memcmp(bb1, bb2, 4000)); ASSERT_EQ(0, close(3)); } ================================================ FILE: test/func/readonly_test.c ================================================ // test read-only memory protection works #include #include #include #include void *p; void OnSigSegv(int sig, siginfo_t *si, void *vctx) { if (si->si_addr != p) _exit(5); if (si->si_code != SEGV_ACCERR) _exit(6); _exit(0); } int main(int argc, char *argv[]) { p = mmap(0, 65536, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (p == MAP_FAILED) return 2; struct sigaction sa = {.sa_sigaction = OnSigSegv, .sa_flags = SA_SIGINFO}; if (sigaction(SIGSEGV, &sa, 0)) return 3; *(int *)p = 1; return 4; } ================================================ FILE: test/func/restart_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include // SA_RESTART inhibits EINTR on blocking calls after signal delivery // see also norestart_test.c // see also eintr_test.c int fds[2]; volatile int gotsig; void OnSig(int sig, siginfo_t *si, void *ptr) { gotsig = 1; } int main(int argc, char *argv[]) { char b; ssize_t got; int ws, pid; sigaction(SIGUSR1, &(struct sigaction){ .sa_sigaction = OnSig, .sa_flags = SA_RESTART, }, 0); pipe(fds); if (!(pid = fork())) { close(fds[1]); got = read(fds[0], &b, 1); if (got == 1 && gotsig) { _exit(0); } else { _exit(1); } } close(fds[0]); sleep(1); kill(pid, SIGUSR1); write(fds[1], &b, 1); wait(&ws); return WEXITSTATUS(ws); } ================================================ FILE: test/func/robust_exit_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include #define PCHECK(x) \ do { \ int rc_ = (x); \ if (rc_) { \ errno = rc_; \ perror(#x); \ exit(1); \ } \ } while (0) static pthread_mutex_t mtx; static void *OriginalOwnerThread(void *ptr) { pthread_mutex_lock(&mtx); pthread_exit(NULL); } static void WaitForOriginalOwnerThreadToDie(pthread_t thr) { int rc; for (;;) { rc = pthread_kill(thr, 0); if (rc == ESRCH) break; assert(!rc); } } int main(int argc, char *argv[]) { int rc; pthread_t thr; pthread_mutexattr_t attr; PCHECK(pthread_mutexattr_init(&attr)); PCHECK(pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST)); PCHECK(pthread_mutex_init(&mtx, &attr)); PCHECK(pthread_mutexattr_destroy(&attr)); PCHECK(pthread_create(&thr, 0, OriginalOwnerThread, 0)); WaitForOriginalOwnerThreadToDie(thr); rc = pthread_mutex_lock(&mtx); if (rc == EOWNERDEAD) { PCHECK(pthread_mutex_consistent(&mtx)); PCHECK(pthread_mutex_unlock(&mtx)); exit(EXIT_SUCCESS); } else if (!rc) { fprintf(stderr, "pthread_mutex_lock() unexpectedly succeeded\n"); exit(EXIT_FAILURE); } else { fprintf(stderr, "pthread_mutex_lock() unexpectedly failed: %s\n", strerror(rc)); exit(1); } } ================================================ FILE: test/func/robust_kill_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include #include #include #include #define SCHECK(x) \ do { \ if ((intptr_t)(x) == -1) { \ perror(#x); \ exit(1); \ } \ } while (0) #define PCHECK(x) \ do { \ int rc_ = (x); \ if (rc_) { \ errno = rc_; \ perror(#x); \ exit(1); \ } \ } while (0) static struct { atomic_int ready; pthread_mutex_t mtx; } * shared; int main(int argc, char *argv[]) { int rc, pid; pthread_mutexattr_t attr; if (1) return 0; // TODO: Figure out how robust list works. SCHECK(shared = mmap(0, 65536, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)); PCHECK(pthread_mutexattr_init(&attr)); PCHECK(pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST)); PCHECK(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)); PCHECK(pthread_mutex_init(&shared->mtx, &attr)); PCHECK(pthread_mutexattr_destroy(&attr)); SCHECK(pid = fork()); if (!pid) { PCHECK(pthread_mutex_lock(&shared->mtx)); shared->ready = 1; for (;;) getppid(); } while (!shared->ready) { } fprintf(stderr, "killing\n"); SCHECK(kill(pid, SIGTERM)); SCHECK(wait(0)); fprintf(stderr, "locking\n"); rc = pthread_mutex_lock(&shared->mtx); fprintf(stderr, "locked\n"); if (rc == EOWNERDEAD) { fprintf(stderr, "good\n"); PCHECK(pthread_mutex_consistent(&shared->mtx)); PCHECK(pthread_mutex_unlock(&shared->mtx)); exit(0); } else if (!rc) { fprintf(stderr, "pthread_mutex_lock() unexpectedly succeeded\n"); exit(1); } else { fprintf(stderr, "pthread_mutex_lock() unexpectedly failed: %s\n", strerror(rc)); exit(1); } } ================================================ FILE: test/func/select_timeout_test.c ================================================ // test kernel sys_select(timeout) is always modified // the linux kernel even appears to modify it on errors like einval! #include #include #include int main(int argc, char *argv[]) { int rc; int pfds[2]; fd_set rfds; struct timeval tv = {0, 10 * 1000}; if (pipe(pfds)) return 1; FD_ZERO(&rfds); FD_SET(pfds[0], &rfds); if (syscall(SYS_select, pfds[0] + 1, &rfds, 0, 0, &tv)) return 2; if (tv.tv_sec) return 3; if (tv.tv_usec) return 4; return 0; } ================================================ FILE: test/func/shared_test.c ================================================ // checks if mmap(MAP_SHARED) works #include #include #include #include #include "config.h" int main(int argc, char *argv[]) { #ifdef HAVE_MAP_SHARED FILE *f; void *map; int ws, *x; pid_t pid, rc; if (!(f = tmpfile())) return 1; if (ftruncate(fileno(f), sizeof(int))) return 2; map = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fileno(f), 0); if (map == MAP_FAILED) return 3; x = (int *)map; pid = fork(); if (pid == -1) return 4; if (!pid) { *x = 42; msync(map, sizeof(int), MS_INVALIDATE); _exit(0); } rc = wait(&ws); if (rc == -1) return 5; if (rc != pid) return 6; if (!WIFEXITED(ws)) return 7; if (WEXITSTATUS(ws)) return 8; if (*x != 42) return 9; return 0; #endif } ================================================ FILE: test/func/sigprocmask_test.c ================================================ #include volatile int gotsigusr1; volatile int gotsigusr2; void OnSigUsr1(int sig) { ++gotsigusr1; } void OnSigUsr2(int sig) { ++gotsigusr2; } int main(int argc, char *argv[]) { sigset_t ss; if (signal(SIGUSR1, OnSigUsr1) == SIG_ERR) return 1; if (signal(SIGUSR2, OnSigUsr2) == SIG_ERR) return 2; if (sigemptyset(&ss)) return 3; if (sigaddset(&ss, SIGUSR1)) return 4; if (sigaddset(&ss, SIGUSR2)) return 5; if (sigprocmask(SIG_BLOCK, &ss, 0)) return 6; // tkill() enqueues masked signals if (raise(SIGUSR1)) return 7; if (raise(SIGUSR1)) return 8; if (raise(SIGUSR2)) return 9; if (raise(SIGUSR2)) return 10; if (gotsigusr1) return 11; if (gotsigusr2) return 12; // sigprocmask() triggers immediate delivery of deliverable signals if (sigprocmask(SIG_UNBLOCK, &ss, 0)) return 13; if (!gotsigusr1) return 14; if (!gotsigusr2) return 15; // a signal enqueued multiple times is only delivered once if (gotsigusr1 != 1) return 16; if (gotsigusr2 != 1) return 17; return 0; } ================================================ FILE: test/func/smc1_test.c ================================================ // tests for class 1 self-modifying code // this is the portable prim/proper kind #include #include const unsigned char kAdd[] = { 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x89, 0xf8, // mov %edi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x01, 0xf0, // add %esi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0xc3, // ret }; const unsigned char kSub[] = { 0x90, // nop 0x90, // nop 0x90, // nop 0x89, 0xf8, // mov %edi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x29, 0xf0, // sub %esi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0xc3, // ret }; typedef int math_f(int, int); int main(int argc, char *argv[]) { void *p; math_f *f; p = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (p == MAP_FAILED) return 1; f = (math_f *)p; memcpy(p, kAdd, sizeof(kAdd)); if (mprotect(p, 4096, PROT_READ | PROT_EXEC)) return 2; if (f(20, 3) != 23) return 3; if (mprotect(p, 4096, PROT_READ | PROT_WRITE)) return 4; memcpy(p, kSub, sizeof(kSub)); if (mprotect(p, 4096, PROT_READ | PROT_EXEC)) return 5; if (f(20, 3) != 17) return 6; if (munmap(p, 4096)) return 7; return 0; } ================================================ FILE: test/func/smc2_test.c ================================================ // tests for class 2 self-modifying code // this is the kind intel's cpus support // namely option 1 from the intel manual // using indirect branches to other page #include #include // To write self-modifying code and ensure that it is compliant with // current and future versions of the IA-32 architectures, use one of // the following coding options: // // (* OPTION 1 *) // Store modified code (as data) into code segment; // Jump to new code or an intermediate location; // Execute new code; // // (* OPTION 2 *) // Store modified code (as data) into code segment; // Execute a serializing instruction; (* For example, CPUID instruction *) // Execute new code; // // ──Intel V.3 §8.1.3 const unsigned char kAdd[] = { 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x89, 0xf8, // mov %edi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x01, 0xf0, // add %esi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0xc3, // ret }; const unsigned char kSub[] = { 0x90, // nop 0x90, // nop 0x90, // nop 0x89, 0xf8, // mov %edi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x29, 0xf0, // sub %esi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0xc3, // ret }; typedef int math_f(int, int); // even though we're copying byte by byte, blink shouldn't segfault on // every byte, and it shouldn't need to clear caches on every byte--at // least not in the canonical jit'ed + linear memory optimization mode // // make -j8 o//blink/blink o//test/func/smc2_test.elf // o//blink/blink -Z o//test/func/smc2_test.elf // void SlowMemCpy(void *dest, const void *src, int size) { int i; volatile char *d = (volatile char *)dest; volatile const char *s = (volatile const char *)src; for (i = 0; i < size; ++i) { d[i] = s[i]; } } int main(int argc, char *argv[]) { int i; void *p; math_f *f; p = mmap(0, 65536, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (p == MAP_FAILED) return 1; f = (math_f *)p; for (i = 0; i < 10; ++i) { SlowMemCpy(p, kAdd, sizeof(kAdd)); if (f(20, 3) != 23) return 2; SlowMemCpy(p, kSub, sizeof(kSub)); if (f(20, 3) != 17) return 3; } if (munmap(p, 65536)) return 4; return 0; } ================================================ FILE: test/func/smc3_test.c ================================================ // tests for class 3 self-modifying code // this is the kind intel's cpus support // namely option 1 from the intel manual // using a near branch to the local page #include #include // To write self-modifying code and ensure that it is compliant with // current and future versions of the IA-32 architectures, use one of // the following coding options: // // (* OPTION 1 *) // Store modified code (as data) into code segment; // Jump to new code or an intermediate location; // Execute new code; // // (* OPTION 2 *) // Store modified code (as data) into code segment; // Execute a serializing instruction; (* For example, CPUID instruction *) // Execute new code; // // ──Intel V.3 §8.1.3 const unsigned char kAdd[] = { 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x89, 0xf8, // mov %edi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x01, 0xf0, // add %esi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0xc3, // ret }; const unsigned char kSub[] = { 0x90, // nop 0x90, // nop 0x90, // nop 0x89, 0xf8, // mov %edi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0x90, // nop 0x29, 0xf0, // sub %esi,%eax 0x90, // nop 0x90, // nop 0x90, // nop 0xc3, // ret }; __attribute__((__noinline__)) static int f(int x, int y) { asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); return 0; } __attribute__((__noinline__)) static int Main(void) { int i, n, prot; prot = PROT_READ | PROT_WRITE | PROT_EXEC; for (n = 65536; n; n -= 4096) { if (!mprotect((void *)((long)f & -65536), n, prot)) { break; } } if (!n) return 2; if (f(20, 3) != 0) return 3; for (i = 0; i < 10; ++i) { memcpy(f, kAdd, sizeof(kAdd)); if (f(20, 3) != 23) return i * 10 + 4; memcpy(f, kSub, sizeof(kSub)); if (f(20, 3) != 17) return i * 10 + 5; } return 0; } int main(int argc, char *argv[]) { return Main(); } ================================================ FILE: test/func/socket_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include "test/test.h" void SetUp(void) { } void TearDown(void) { } TEST(ipv4, test) { int ws, pid; char buf[16] = {0}; uint32_t addrsize = sizeof(struct sockaddr_in); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(0x7f000001), }; ASSERT_EQ(3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); ASSERT_EQ(0, bind(3, (struct sockaddr *)&addr, sizeof(addr))); ASSERT_EQ(0, getsockname(3, (struct sockaddr *)&addr, &addrsize)); ASSERT_EQ(0, listen(3, SOMAXCONN)); ASSERT_NE(-1, (pid = fork())); if (!pid) { ASSERT_EQ(4, accept(3, (struct sockaddr *)&addr, &addrsize)); ASSERT_EQ(5, send(4, "hello", 5, 0)); ASSERT_EQ(0, close(4)); ASSERT_EQ(0, close(3)); _Exit(0); } EXPECT_EQ(0, close(3)); EXPECT_EQ(3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); EXPECT_EQ(0, connect(3, (struct sockaddr *)&addr, sizeof(addr))); EXPECT_EQ(5, read(3, buf, 16)); EXPECT_STREQ("hello", buf); EXPECT_EQ(0, close(3)); EXPECT_NE(-1, wait(&ws)); ASSERT_TRUE(WIFEXITED(ws)); ASSERT_EQ(0, WEXITSTATUS(ws)); } ================================================ FILE: test/func/trap_cpuid_test.c ================================================ // test kernel lets us trap cpuid instruction #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #define ARCH_GET_CPUID_ 0x1011 #define ARCH_SET_CPUID_ 0x1012 static void OnSigSegv(int sig, siginfo_t *si, void *vctx) { ucontext_t *ctx = (ucontext_t *)vctx; const char *code = (const char *)ctx->uc_mcontext.gregs[REG_RIP]; if (code[0] == 0x0F && code[1] == (char)0xA2) { // we successfully trapped the cpuid instruction ctx->uc_mcontext.gregs[REG_RAX] = 0x13370001; ctx->uc_mcontext.gregs[REG_RBX] = 0x13370002; ctx->uc_mcontext.gregs[REG_RCX] = 0x13370003; ctx->uc_mcontext.gregs[REG_RDX] = 0x13370004; ctx->uc_mcontext.gregs[REG_RIP] += 2; } else { _exit(20); } } int main(int argc, char *argv[]) { int ax, bx, cx, dx; ax = cx = 0; asm volatile("cpuid" : "+a"(ax), "=b"(bx), "+c"(cx), "=d"(dx)); if (syscall(SYS_arch_prctl, ARCH_GET_CPUID_) != 1 || syscall(SYS_arch_prctl, ARCH_SET_CPUID_, 0) != 0) { fprintf(stderr, "skipping %s\n", argv[0]); return 0; } if (syscall(SYS_arch_prctl, ARCH_GET_CPUID_) != 0) return 3; struct sigaction sa = {.sa_sigaction = OnSigSegv}; if (sigaction(SIGSEGV, &sa, 0)) return 4; ax = cx = 0; asm volatile("cpuid" : "+a"(ax), "=b"(bx), "+c"(cx), "=d"(dx)); if (ax != 0x13370001) return 5; if (bx != 0x13370002) return 6; if (cx != 0x13370003) return 7; if (dx != 0x13370004) return 8; return 0; } ================================================ FILE: test/func/trap_rdtsc_test.c ================================================ // test kernel lets us trap rdtsc instruction #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #define rdtsc() \ ({ \ uint64_t rax_, rdx_; \ asm volatile("rdtsc" : "=a"(rax_), "=d"(rdx_) : : "memory"); \ rdx_ << 32 | rax_; \ }) static void OnSigSegv(int sig, siginfo_t *si, void *vctx) { ucontext_t *ctx = (ucontext_t *)vctx; const char *code = (const char *)ctx->uc_mcontext.gregs[REG_RIP]; if (code[0] == 0x0f && code[1] == 0x31) { ctx->uc_mcontext.gregs[REG_RDX] = 3; ctx->uc_mcontext.gregs[REG_RAX] = 0x13370000; ctx->uc_mcontext.gregs[REG_RIP] += 2; } else { _exit(20); } } int main(int argc, char *argv[]) { uint64_t x, y; if (prctl(PR_SET_TSC, PR_TSC_ENABLE)) return 1; x = rdtsc(); y = rdtsc(); if (x == y) return 2; if (y < x) return 3; struct sigaction sa = {.sa_sigaction = OnSigSegv}; if (sigaction(SIGSEGV, &sa, 0)) return 4; if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV)) return 5; if (rdtsc() != 0x313370000) return 6; if (rdtsc() != 0x313370000) return 7; return 0; } ================================================ FILE: test/func/trap_test.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include volatile int failed; void OnSig(int sig, siginfo_t *si, void *ptr) { failed = 0; } int main(int argc, char *argv[]) { sigaction(SIGTRAP, &(struct sigaction){.sa_sigaction = OnSig}, 0); failed = 1; asm("int3"); return failed; } ================================================ FILE: test/metal/biosdisk.S ================================================ #include "test/metal/mac.inc" .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/biosdisk.bin // o//blink/blinkenlights -r o//test/metal/biosdisk.bin ljmpw $0,$1f 1: .test "int 0x1E diskette parameter table should contain sane values" lds %cs:(0x1e*4),%bx // %ds:%bx := table pointer mov %ds,%ax // test that pointer is not null or %bx,%ax .ne cmpb $2,3(%bx) // test that diskette I/O is using .e // 512 bytes per sector cmpb $8,4(%bx) // ...& at least 8 sectors per track .nc test %dl,%dl // skip next test in unlikely case jne 2f // this was not booted from floppy // drive A: .test "floppy parameters from int 0x13 should be sane" xor %di,%di // get parameters for A: mov %di,%es mov $8,%ah xor %cx,%cx int $0x13 .nc cmp $8,%cl // test that maximum sector number .nc // per track makes sense cmp $40-1,%ch // test that maximum track number .nc // makes sense test %dl,%dl // test that drive count makes sense .ne mov %es,%ax // test that parameter table pointer or %di,%ax // is not null .ne cmpb $2,%es:3(%di) // test parameter table values for .e // this drive cmpb $8,%es:4(%di) .nc 2: .exit // fabricate a 160 KiB disk image (40 tracks × 1 side × 8 sectors per track) .global _sectors _sectors = 320 .section .pad,"a",@progbits ================================================ FILE: test/metal/biostime.S ================================================ #include "test/metal/mac.inc" .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/biostime.bin // o//blink/blinkenlights -r o//test/metal/biostime.bin ljmpw $0,$1f 1: .test "real time clock should not move much slower than system clock" mov $5,%bp 2: mov $2,%ah // get starting RTC time int $0x1a .nc mov %cl,%dl mov %dx,%si mov $0,%ah // get starting system time int $0x1a push %cx push %dx pop %edi 3: mov $0,%ah // wait until at least 20 system clock int $0x1a // ticks (slightly more than 1s) push %cx // have elapsed push %dx pop %edx cmp $0x1800b0,%edx .c sub %edi,%edx jnc 4f add $0x1800b0,%edx 4: cmp $20,%edx jb 3b cmp $0x1800b0/2,%edx ja 1b // lolwut? mov $2,%ah // get new RTC time int $0x1a .nc mov %cl,%dl cmp %dx,%si // RTC time should have changed by now .nz dec %bp // retry this 5 times jnz 2b .test "system clock should not move much slower than real time clock" 5: mov $2,%ah // wait until RTC time rolls over int $0x1a // to next second .nc mov %cl,%dl mov %dx,%si 6: mov $2,%ah int $0x1a mov %cl,%dl cmp %dx,%si je 6b mov $5,%bp 7: mov $0,%ah // get starting system time int $0x1a push %cx push %dx pop %edi mov $2,%ah // get starting RTC time int $0x1a .nc mov %cl,%dl mov %dx,%si 8: mov $2,%ah // wait until RTC time rolls over int $0x1a // to next second .nc mov %cl,%dl cmp %dx,%si jz 8b mov $0,%ah // system time should have advanced int $0x1a // by at least 16 ticks by now push %cx push %dx pop %edx sub %edi,%edx jnc 9f add $0x1800b0,%edx 9: cmp $16,%edx .nc cmp $0x1800b0/2,%edx ja 5b dec %bp jnz 7b .exit ================================================ FILE: test/metal/enter.S ================================================ #include "test/metal/mac.inc" .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/enter.bin // o//blink/blinkenlights -r o//test/metal/enter.bin .load32 _start32 .section .text,"ax",@progbits .code32 #define MAGIC1 0xacc31274 #define MAGIC2 0xa7fc #define MAGIC3 0x40df #define MAGIC4 0x8c34 _start32: .test "enterl stores frame pointer of size 4" mov $MAGIC1,%ebx lea -4-MAGIC2(%esp),%eax lea -4(%esp),%ecx mov %esp,%edx mov %ebx,%ebp enterl $MAGIC2,$0 cmp %esp,%eax .e cmp %ebp,%ecx .e cmp (%ebp),%ebx .e .test "leavel restores frame pointer of size 4" leavel cmp %edx,%esp .e cmp %ebx,%ebp .e .test "enterw stores frame pointer of size 2" xor %sp,%sp // make sure %sp does not wrap sub $4,%esp // around 64 KiB boundary mov %esp,%ebx mov $MAGIC3,%bx lea -2-MAGIC4(%esp),%eax lea -2(%esp),%ecx mov %esp,%edx mov %ebx,%ebp enterw $MAGIC4,$0 cmp %esp,%eax .e cmp %ebp,%ecx .e cmp (%ebp),%bx .e .test "leavew restores frame pointer of size 2" leavew cmp %edx,%esp .e mov %bx,%dx cmp %edx,%ebp .e "test succeeded": .exit ================================================ FILE: test/metal/gdt-idt-32.S ================================================ .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/gdt-idt-32.bin // o//blink/blinkenlights -r o//test/metal/gdt-idt-32.bin ljmpw $0,$1f 1: mov %cs,%ax cli mov %ax,%ss mov $_start,%sp mov %ax,%ds mov %ax,%es sidt orig_idt // Test that we can load arbitrary values into the GDTR & IDTR, & that // the loaded base addresses are of the correct widths cld mov $actual_out,%di mov $0xf6,%al mov $out_size,%cx rep stosb lgdtw dt1 // load GDTR, operand size 16 bits // => 24-bit base address sgdtw out1a // store GDTR: this will still dump a // 32-bit base address lgdtl dt1 // load GDTR, operand size 32 bits // => 32-bit base address sgdtl out1b // store GDTR again lidtw dt2 // now try messing with the IDTR sidtw out2a lidtl dt2 sidtl out2b // Now load an actual GDT, switch to protected mode, & test that the // LSL instruction reads the correct limits from it // While at it, also check that for the `smsw` instruction (0f 01 /4) // the reg/opcode field (/4) is not misinterpreted as an %sp operand lgdtw good_gdtr mov $-1,%dx smsw %dx // %dx := %cr0[15:0]... cmp $_start,%sp // ...not %sp := %cr0[15:0] ! jnz fail or $1,%dl lmsw %dx jmp 2f 2: mov $GDT_DATA16_32K,%cx lsl %ecx,%eax mov %eax,out3a mov $GDT_DATA16_4G,%cl lsl %ecx,%eax mov %eax,out3b mov $GDT_DATA32_64K,%cl lsl %ecx,%eax mov %eax,out3c mov $GDT_DATA32_384M,%cl lsl %ecx,%eax mov %eax,out3d // Back to real mode mov %cr0,%eax and $~1,%al mov %eax,%cr0 jmp 3f 3: // Compare actual output with expected output mov $expect_out,%si mov $actual_out,%di mov $out_size,%cx repz cmpsb jnz fail // Tests passed! Try to "exit" emulator with success status cli lidt bad_idt xor %edi,%edi mov $231,%eax syscall // this will triple fault on a real PC fail: lidt orig_idt int3 jmp fail .balign 8 dt1: .quad 0x5b1ebd8d858e9801 dt2: .quad 0xc5a9b78fe8a862f1 expect_out: .quad 0xf6f6008d858e9801 // expected result of 1st SGDT .quad 0xf6f6bd8d858e9801 // expected result of 2nd SGDT .quad 0xf6f6008fe8a862f1 // expected result of 1st SIDT .quad 0xf6f6b78fe8a862f1 // expected result of 2nd SIDT .long 0x00007fff // expected result of 1st LSL .long 0xffffffff // expected result of 2nd LSL .long 0x0000ffff // expected result of 3rd LSL .long 0x17ffffff // expected result of 4th LSL out_size = . - expect_out good_gdtr: .short good_gdt_end-good_gdt-1 .long good_gdt good_gdt: .quad 0b0000000000000000000000000000000000000000000000000000000000000000 # 0 .quad 0b0000000000000000100100100000000000000000000000000111111111111111 # 8 .quad 0b0000000010001111100100100000000000000000000000001111111111111111 #16 .quad 0b0000000001000000100100100000000000000000000000001111111111111111 #24 .quad 0b0000000011000001100100100000000000000000000000000111111111111111 #32 good_gdt_end: GDT_DATA16_32K = 8 GDT_DATA16_4G = 16 GDT_DATA32_64K = 24 GDT_DATA32_384M = 32 .balign 8 bad_idt: .quad 0 .bss .balign 8 orig_idt: .skip 8 actual_out: out1a: .skip 8 out1b: .skip 8 out2a: .skip 8 out2b: .skip 8 out3a: .skip 4 out3b: .skip 4 out3c: .skip 4 out3d: .skip 4 ================================================ FILE: test/metal/hello.S ================================================ .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/hello.bin // o//blink/blinkenlights -r o//test/metal/hello.bin ljmpw $0,$1f 1: mov %cs,%ax mov %ax,%ds mov $msg,%si cld 2: lodsb test %al,%al jz 3f mov $0x0e,%ah mov $0x0007,%bx int $0x10 jmp 2b 3: cli lidt bad_idt xor %edi,%edi mov $231,%eax syscall // this will triple fault on a real PC msg: .asciz "Hello world!\r\n" .balign 8 bad_idt: .quad 0 ================================================ FILE: test/metal/int3.S ================================================ #include "test/metal/mac.inc" .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/int3.bin // o//blink/blinkenlights -r o//test/metal/int3.bin ljmpw $0,$1f 1: .test "int3 should not halt execution if guest is hooking it" movw $9f,%cs:(0x03*4) // point int 3 vector at our own code movw %cs,%cs:(0x03*4)+2 int3 // then invoke int 3 2: // if the above happens to fall ud2 // through to the next instruction, hlt // force something really bad (not jmp 2b // an int 3!) to happen 9: // if things go well, execution .exit // should reach here ================================================ FILE: test/metal/iret.S ================================================ .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/iret.bin // o//blink/blinkenlights -r o//test/metal/iret.bin 0: ljmpw $0,$1f RET_TO = 5215 .subsection RET_TO 1: xor %ax,%ax mov %ax,%ss mov $0b,%sp mov $0x414,%ax mov %ax,%ds mov $0b11100011,%ah sahf jns fail jnz fail jp fail jnc fail pushfl lcalll $0x655,$11f-0x6550 .subsection 2480 11: mov $0b01000010,%ah sahf js fail jnz fail jp fail jc fail iretl .subsection RET_TO jns fail jnz fail jp fail jnc fail cmp $0b01000010,%ah jnz fail mov $0b10011111,%ah sahf jns fail jz fail jnp fail jnc fail pushfw lcallw $0x554,$21f-0x5540 .subsection 1555 21: mov $0b00111000,%ah sahf js fail jz fail jp fail jc fail iretw .subsection RET_TO jns fail jz fail jnp fail jnc fail cmp $0b00111000,%ah jnz fail cli xor %edi,%edi mov %di,%ds lidt bad_idt mov $231,%eax syscall // this will triple fault on a real PC fail: int3 hlt jmp fail .balign 8 bad_idt: .quad 0 ================================================ FILE: test/metal/lds-les.S ================================================ .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/lds-les.bin // o//blink/blinkenlights -r o//test/metal/lds-les.bin ljmpw $0,$1f #define SEG1 0x66d #define OFF1 (loc1-0x66d0) #define MAGIC1 0x5bd3610b #define SEG2 0x79e #define OFF2 (loc2-0x79e0) #define MAGIC2 0x358f8b2e #define SEG3 0x541 #define OFF3 (loc3-0x5410) #define MAGIC3 0xca55bb07 #define SEG4 0x29f #define OFF4 (loc4-0x29f0) #define MAGIC4 0xb9fca8dc #define SEG5 0x1c7 #define OFF5A (-0x29ec8d34) #define OFF5B (loc5-0x1c70-OFF5A) #define MAGIC5 0x9c948198 #define SEG6 0x323 #define OFF6A (-0x03748378) #define OFF6B (loc6-0x3230-OFF6A) #define MAGIC6 0x3f2c0b97 #define SEG7 0x41e #define OFF7 (loc7-0x41e0) #define MAGIC7 0xf1cab448 1: or $-1,%ecx mov %ecx,%ebx mov %ecx,%esi mov %ecx,%edi mov %cx,%ds mov %cx,%es lds %cs:fp1,%bx cmp $OFF1,%bx jnz fail mov %ds,%ax cmp $SEG1,%ax jnz fail cmpl $MAGIC1,(%bx) jnz fail les %cs:fp2,%si cmp $OFF2,%si jnz fail mov %es,%ax cmp $SEG2,%ax jnz fail cmpl $MAGIC2,%es:(%si) jnz fail lds %cs:fp3,%edi cmp $OFF3,%edi jnz fail mov %ds,%ax cmp $SEG3,%ax jnz fail cmpl $MAGIC3,(%edi) jnz fail les %cs:fp4,%ebp cmp $OFF4,%ebp jnz fail mov %es,%ax cmp $SEG4,%ax jnz fail cmpl $MAGIC4,%es:(%ebp) jnz fail lfs %cs:fp5,%eax cmp $OFF5A,%eax jnz fail mov %fs,%bx cmp $SEG5,%bx jnz fail cmpl $MAGIC5,%fs:OFF5B(%eax) jnz fail lgs %cs:fp6,%ecx cmp $OFF6B,%ecx jnz fail mov %gs,%dx cmp $SEG6,%dx jnz fail cli mov $OFF6A,%esp cmpl $MAGIC6,%gs:(%esp,%ecx) jnz fail mov $_start-SEG7*0x10,%esp lss %cs:fp7,%si mov %ss,%bp cmp $SEG7,%bp jnz fail sti cmp $OFF7,%si jnz fail cmpl $MAGIC7,%ss:(%si) jnz fail // Tests passed! Try to "exit" emulator with success status cli lidt bad_idt xor %edi,%edi mov $231,%eax syscall // this will triple fault on a real PC fail: int3 jmp fail .balign 2 fp1: .hword OFF1,SEG1 fp2: .hword OFF2,SEG2 fp3: .long OFF3 .hword SEG3 fp4: .long OFF4 .hword SEG4 fp5: .long OFF5A .hword SEG5 fp6: .long OFF6B .hword SEG6 fp7: .hword OFF7,SEG7 loc1: .long MAGIC1 loc2: .long MAGIC2 loc3: .long MAGIC3 loc4: .long MAGIC4 loc5: .long MAGIC5 loc6: .long MAGIC6 loc7: .long MAGIC7 .balign 8 bad_idt: .quad 0 ================================================ FILE: test/metal/ljmp-lcall.S ================================================ .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/ljmp-lcall.bin // o//blink/blinkenlights -r o//test/metal/ljmp-lcall.bin 0: ljmpw $0,$1f 1: xor %ax,%ax mov %ax,%ss mov $0b,%sp ljmpw *%cs:21f .subsection 1027 21: .hword 11f-0x6aa0,0x6aa RET_TO = 4703 .subsection RET_TO 11: mov $0x30e,%ax mov %ax,%ds mov $0xa9e,%bx lcalll *22f-0xa9e-0x30e0(%bx) .subsection 2822 22: .long 12f-0x26b0 .hword 0x26b .subsection 2997 12: add $0x35fc-0x30e,%ax lretl .subsection RET_TO cmp $0x35fc,%ax jnz fail movl $-0xafa8b409,%ecx ljmpl *23f+0xafa8b409-0x30e0(%ecx) .subsection 367 23: .long 13f-0x6480 .hword 0x648 RET_TO = 8148 .subsection RET_TO 13: mov $0x2ab,%ax mov %ax,%es movl $-0x8f45a4df,%ebp lcallw *%es:24f+0x8f45a4df-0x2ab0(%ebp) .subsection 7391 24: .hword 14f-0x6820,0x682 .subsection 141 14: xor %ebp,%ecx lretw .subsection RET_TO cmp $(-0xafa8b409)^(-0x8f45a4df),%ecx jnz fail cli xor %edi,%edi mov %di,%ds lidt bad_idt mov $231,%eax syscall // this will triple fault on a real PC fail: int3 hlt jmp fail .balign 8 bad_idt: .quad 0 ================================================ FILE: test/metal/mac.inc ================================================ // -*- mode: unix-assembly; indent-tabs-mode: t; tab-width: 8; coding: utf-8 -*- .macro .load16 ljmp $0,$101f 101: xor %ax,%ax mov %ax,%ds mov %ax,%es mov %ax,%ss mov $_start,%sp int $0x13 // reset boot device (%ah = 0) mov $0x0200+_sectors-1,%ax // read remaining sectors of this mov $_start+512,%bx // test case mov $0x0002,%cx mov $0,%dh int $0x13 jc 101b .endm .macro .load32 entry:req .load16 cli // switch to protected mode lgdtl 103f mov %cr0,%eax or $1,%al mov %eax,%cr0 jmp 102f 102: mov $16,%ax mov %ax,%ds mov %ax,%es mov %ax,%ss movzwl 0x0413,%esp // start stack at base memory top shll $10,%esp ljmpl $8,$(\entry) // really transition to 32-bit mode .balign 8 103: .short 105f-104f-1 .long 104f .balign 8 104: .quad 0b0000000000000000000000000000000000000000000000000000000000000000 # 0 .quad 0b0000000011001111100110100000000000000000000000001111111111111111 # 8 .quad 0b0000000011001111100100100000000000000000000000001111111111111111 #16 105: .endm .macro .exit cli lidtl %cs:106f xor %edi,%edi xor %eax,%eax mov $231,%al syscall .balign 8 106: .quad 0 .endm .macro .test name:req prologue\@: jmp 101f 100: int3 hlt jmp 100b 101: nop "\name": .endm .macro .c jnc 100b .endm .macro .nc jc 100b .endm .macro .e jne 100b .endm .macro .ne je 100b .endm .macro .z jnz 100b .endm .macro .nz jz 100b .endm .macro .s jns 100b .endm .macro .ns js 100b .endm .macro .o jno 100b .endm .macro .no jo 100b .endm .macro .p jnp 100b .endm .macro .np jp 100b .endm .macro .sop .nz .s .nc .o .p .endm ================================================ FILE: test/metal/metal.lds ================================================ ENTRY(_start) OUTPUT_FORMAT(binary) SECTIONS { . = 0x7c00; .head : { _base = .; *(.head) /* * Fabricate a degenerate "hard disk partition table" that covers at * least this bare metal program. Fill up 1 partition table entry. */ . = 0x1be; BYTE(0x80) /* 0=non-boot / 0x80=active */ BYTE(0) /* start head */ BYTE(1) /* start sector[5:0], cylinder[9:8] */ BYTE(0) /* start cylinder[7:0] */ BYTE(0x7f) /* filesystem type */ BYTE(0xff) /* end head */ BYTE(0xff) /* end sector[5:0], cylinder[9:8] */ BYTE(0xff) /* end cylinder[7:0] */ LONG(0) /* c₀*Cₙ + h₀*Hₙ + s₀*Sₙ */ LONG(0xffffffff) /* sector count */ /* Add the boot record signature. */ . = 0x1fe; SHORT(0xaa55); } = 0 .text : { *(.text .text.*) . = ALIGN(0x10); *(.rodata .rodata.*) . = ALIGN(0x10); *(.data .data.*) _edata = .; } PROVIDE(_sectors = ALIGN(_edata - _base, 512) / 512); .bss : { *(.bss .bss.*) *(COMMON) } .pad : { /* * If the program defines both a _sectors value & a .pad section, then * pad the image up to the requested sector count. This allows us to * fabricate disk images that follow particular disk geometries. */ . = MAX(., _base + _sectors * 512 - SIZEOF(.pad)); *(.pad .pad.*) } = 0xF6 /DISCARD/ : { *(.*) } } ================================================ FILE: test/metal/metal.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ TEST_METAL_FILES := $(wildcard test/metal/*) TEST_METAL_SRCS = $(filter %.S,$(TEST_METAL_FILES)) TEST_METAL_OBJS = $(TEST_METAL_SRCS:%.S=o/$(MODE)/x86_64-gcc49/%.o) TEST_METAL_BINS = $(TEST_METAL_SRCS:%.S=o/$(MODE)/%.bin) TEST_METAL_CHECKS = $(TEST_METAL_BINS:%=%.ok) TEST_METAL_LINK = \ $(VM) \ o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-ld.bfd \ -T test/metal/metal.lds \ -static \ $< \ -o $@ .PRECIOUS: o/$(MODE)/test/metal/%.bin o/$(MODE)/test/metal/%.bin: \ o/$(MODE)/x86_64-gcc49/test/metal/%.o \ o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc \ test/metal/metal.lds \ $(VM) @mkdir -p $(@D) $(TEST_METAL_LINK) $(TEST_METAL_OBJS): test/metal/metal.mk test/metal/mac.inc o/$(MODE)/test/metal/%.bin.ok: \ o/$(MODE)/test/metal/%.bin \ o/$(MODE)/blink/blinkenlights @mkdir -p $(@D) o/$(MODE)/blink/blinkenlights -r -t $< @touch $@ o/$(MODE)/test/metal: \ $(TEST_METAL_CHECKS) ================================================ FILE: test/metal/pusha-popa.S ================================================ .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/pusha-popa.bin // o//blink/blinkenlights -r o//test/metal/pusha-popa.bin 0: ljmpw $0,$1f 1: xor %ax,%ax mov %ax,%ds mov %ax,%es mov %ax,%ss /* longword with high half being z & low half being w */ #define SMUSH(z, w) ((((z) & 0xffff) << 16) | ((w) & 0xffff)) #define MAGIC0 0x84de #define INI_SP 0x7c00 #define INI_ESP SMUSH(MAGIC0, INI_SP) mov $INI_ESP,%esp int $0x13 // reset boot device (%ah = 0) mov $0x0200+_sectors-1,%ax // read remaining sectors of this mov $0b+512,%bx // test case mov $0x0002,%cx mov $0,%dh int $0x13 jc 1b #define MAGIC1 0x6f692002 #define MAGIC2 0x8556ab1b #define MAGIC3 0x1bc6f7f7 #define MAGIC4 0x60540962 #define MAGIC5 0xf2b8c5fd #define MAGIC6 0x705a9a7f #define MAGIC7 0x08500349 #define MAGIC8 0xdf7601c3 mov $MAGIC1,%eax mov $MAGIC2,%ecx mov $MAGIC3,%edx mov $MAGIC4,%ebx mov $MAGIC5,%ebp mov $MAGIC6,%esi mov $MAGIC7,%edi pushal /* * now %sp INI_SP * ↓ +4 +8 +12 +16 +20 +24 +28 ↓ * ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐ * │MAGIC7 │MAGIC6 │MAGIC5 │INI_ESP│MAGIC4 │MAGIC3 │MAGIC2 │MAGIC1 │ * └───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘ * %edi %esi %ebp initial %edx %ecx %ebx %eax * %esp */ cmp $INI_ESP-32,%esp jnz fail mov $MAGIC8,%ebp mov %sp,%bp cmpl $MAGIC1,28(%bp) jnz fail cmpl $MAGIC2,24(%bp) jnz fail cmpl $MAGIC3,20(%bp) jnz fail cmpl $MAGIC4,16(%bp) jnz fail cmpl $INI_ESP,12(%bp) jnz fail cmpl $MAGIC5,8(%bp) jnz fail cmpl $MAGIC6,4(%bp) jnz fail cmpl $MAGIC7,(%bp) jnz fail #define MAGIC9 0x63b5007e mov $MAGIC9,%edi addr32 popaw // the `addr32' (0x67) prefix should have no effect! /* * now %sp INI_SP * ↓ ↓ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───────┬───────┬───────┬───────┐ * │MAGIC7 │MAGIC6 │MAGIC5 │INI_ESP│MAGIC4 │MAGIC3 │MAGIC2 │MAGIC1 │ * └───┴───┴───┴───┴───┴───┴───┴───┴───────┴───────┴───────┴───────┘ * %di %si %bp %bx %dx %cx %ax */ /* high half of x combined with low half of y */ #define HL(x, y) (((x) & ~0xffff) | ((y) & 0xffff)) cmp $HL(MAGIC1, MAGIC0),%eax jnz fail cmp $HL(MAGIC2, INI_ESP),%ecx jnz fail cmp $HL(MAGIC3, MAGIC5 >> 16),%edx jnz fail cmp $HL(MAGIC4, MAGIC5),%ebx jnz fail cmp $INI_ESP-16,%esp jnz fail cmp $HL(MAGIC8, MAGIC6),%ebp jnz fail cmp $HL(MAGIC6, MAGIC7 >> 16),%esi jnz fail cmp $HL(MAGIC9, MAGIC7),%edi jnz fail #define MAGIC10 0x35ff #define MAGIC11 0x45de #define MAGIC12 0xe0e4 #define MAGIC13 0x43ab #define MAGIC14 0x44819457 #define MAGIC15 0x92d11944 #define MAGIC16 0xf5136466 mov $MAGIC10,%ax mov $MAGIC11,%cx mov $MAGIC12,%dx mov $MAGIC13,%bx mov $MAGIC14,%ebp mov $MAGIC15,%esi mov $MAGIC16,%edi addr32 pushaw // `addr32' (0x67) should be ignored /* * now %sp sp₂ INI_SP * ↓ +4 +8 +12 ↓ ↓ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───────┬───────┬───────┬───────┐ * │M₁₆│M₁₅│M₁₄│sp₂│M₁₃│M₁₂│M₁₁│M₁₀│MAGIC4 │MAGIC3 │MAGIC2 │MAGIC1 │ * └───┴───┴───┴───┴───┴───┴───┴───┴───────┴───────┴───────┴───────┘ * %di %si %bp %bx %dx %cx %ax */ mov %sp,%bp cmpl $SMUSH(MAGIC10, MAGIC11),12(%bp) jnz fail popal /* * sp₂ %sp = INI_SP * ↓ ↓ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───────┬───────┬───────┬───────┐ * │M₁₆│M₁₅│M₁₄│sp₂│M₁₃│M₁₂│M₁₁│M₁₀│MAGIC4 │MAGIC3 │MAGIC2 │MAGIC1 │ * └───┴───┴───┴───┴───┴───┴───┴───┴───────┴───────┴───────┴───────┘ * └─────┘ └─────┘ └─────┘ %ebx %edx %ecx %eax * %edi %esi %ebp */ cmp $MAGIC1,%eax jnz fail cmp $MAGIC2,%ecx jnz fail cmp $MAGIC3,%edx jnz fail cmp $MAGIC4,%ebx jnz fail cmp $INI_ESP,%esp jnz fail cmp $SMUSH(MAGIC12, MAGIC13),%ebp jnz fail cmp $SMUSH(INI_SP - 16, MAGIC14),%esi jnz fail cmp $SMUSH(MAGIC15, MAGIC16),%edi jnz fail #define GDT_LEGACY_CODE 8 #define GDT_LEGACY_DATA 16 cli lgdtl good_gdtr mov %cr0,%eax or $1,%al mov %eax,%cr0 ljmpw $GDT_LEGACY_CODE,$2f fail: int3 hlt jmp fail .balign 8 bad_idt: .quad 0 .section .text,"ax",@progbits .code32 #define PM_ESP 0x00020004 // in 32-bit mode, try starting with // a value of %esp that will force // a carry/borrow in the high half // when we push or pop stuff 2: mov $GDT_LEGACY_DATA,%ax mov %ax,%ds mov %ax,%es mov %ax,%ss mov $PM_ESP,%esp #define MAGIC17 0xcd2814e8 #define MAGIC18 0xb7912036 #define MAGIC19 0xf98a2750 #define MAGIC20 0x1f6574af #define MAGIC21 0xbb4a9d2a #define MAGIC22 0x9a86ec5a #define MAGIC23 0x33662e67 mov $MAGIC17,%eax mov $MAGIC18,%ecx mov $MAGIC19,%edx mov $MAGIC20,%ebx mov $MAGIC21,%ebp mov $MAGIC22,%esi mov $MAGIC23,%edi pushal cmp $PM_ESP-32,%esp jnz fail #define MAGIC24 0xad707a8a mov $MAGIC24,%edi addr16 popaw // `addr16' (0x67) should be ignored /* * now %esp PM_ESP * ↓ ↓ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───────┬───────┬───────┬───────┐ * │MAGIC23│MAGIC22│MAGIC21│PM_ESP │MAGIC20│MAGIC19│MAGIC18│MAGIC17│ * └───┴───┴───┴───┴───┴───┴───┴───┴───────┴───────┴───────┴───────┘ * %di %si %bp %bx %dx %cx %ax */ cmpw $(MAGIC22 >> 16),-10(%esp) jnz fail cmp $HL(MAGIC17, PM_ESP >> 16),%eax jnz fail cmp $HL(MAGIC18, PM_ESP),%ecx jnz fail cmp $HL(MAGIC19, MAGIC21 >> 16),%edx jnz fail cmp $HL(MAGIC20, MAGIC21),%ebx jnz fail cmp $PM_ESP-16,%esp jnz fail cmp $HL(MAGIC21, MAGIC22),%ebp jnz fail cmp $HL(MAGIC22, MAGIC23 >> 16),%esi jnz fail cmp $HL(MAGIC24, MAGIC23),%edi jnz fail #define MAGIC25 0x205de5bd mov $MAGIC25,%eax popaw /* * now %esp = * PM_ESP * ↓ * ┌───────┬───────┬───────┬───────┬───┬───┬───┬───┬───┬───┬───┬───┐ * │MAGIC23│MAGIC22│MAGIC21│PM_ESP │MAGIC20│MAGIC19│MAGIC18│MAGIC17│ * └───────┴───────┴───────┴───────┴───┴───┴───┴───┴───┴───┴───┴───┘ * %di %si %bp %bx %dx %cx %ax */ cmpw $(MAGIC19 >> 16),-10(%esp) jnz fail cmp $HL(MAGIC25, MAGIC17 >> 16),%eax jnz fail cmp $HL(MAGIC18, MAGIC17),%ecx jnz fail cmp $HL(MAGIC19, MAGIC18 >> 16),%edx jnz fail cmp $HL(MAGIC20, MAGIC18),%ebx jnz fail cmp $PM_ESP,%esp jnz fail cmp $HL(MAGIC21, MAGIC19),%ebp jnz fail cmp $HL(MAGIC22, MAGIC20 >> 16),%esi jnz fail cmp $HL(MAGIC24, MAGIC20),%edi jnz fail cli // tests passed xor %edi,%edi lidt bad_idt mov $231,%eax syscall // this will triple fault on a real PC .section .rodata,"a",@progbits good_gdtr: .short good_gdt_end-good_gdt-1 .long good_gdt .balign 8 good_gdt: .quad 0b0000000000000000000000000000000000000000000000000000000000000000 # 0 .quad 0b0000000011001111100110100000000000000000000000001111111111111111 # 8 .quad 0b0000000011001111100100100000000000000000000000001111111111111111 #16 good_gdt_end: ================================================ FILE: test/metal/ssemov.S ================================================ #include "config.h" #include "test/metal/mac.inc" .section .head,"ax",@progbits .code16 .globl _start _start: // sse moves in bare metal mode // make -j8 o//blink o//test/metal/ssemov.bin // o//blink/blinkenlights -r o//test/metal/ssemov.bin #define CR0_MP (1<<1) #define CR0_EM (1<<2) #define CR4_OSFXSR (1<<9) #define CR4_OSXMMEXCPT (1<<10) .load16 .test "enable sse2" xor %eax,%eax inc %ax cpuid test $1<<26,%edx // test for sse2 capability .ne mov %cr0,%eax // enable sse and $~CR0_EM,%al or $CR0_MP,%al mov %eax,%cr0 mov %cr4,%eax or $CR4_OSFXSR|CR4_OSXMMEXCPT,%ax mov %eax,%cr4 .test "sse mov unaligned" and $-16,%sp sub $17,%sp movdqu onetwo,%xmm0 movdqu %xmm0,%xmm0 movdqu %xmm0,(%esp) mov (%esp),%eax mov 4(%esp),%esi mov 8(%esp),%edx mov 12(%esp),%edi mov $0x11111111,%ecx cmp %ecx,%eax .e cmp %ecx,%esi .e mov $0x22222222,%ecx cmp %ecx,%edx .e cmp %ecx,%edi .e .test "sse mov aligned" and $-16,%sp sub $16,%sp movdqa onetwo,%xmm7 movdqa %xmm7,%xmm6 movdqa %xmm6,(%esp) mov (%esp),%eax mov 4(%esp),%esi mov 8(%esp),%edx mov 12(%esp),%edi mov $0x11111111,%ecx cmp %ecx,%eax .e cmp %ecx,%esi .e mov $0x22222222,%ecx cmp %ecx,%edx .e cmp %ecx,%edi .e .test "sse mov unaligned #2" and $-16,%sp sub $16,%sp movups onetwo,%xmm7 movups %xmm7,%xmm6 movups %xmm6,(%esp) mov (%esp),%eax mov 4(%esp),%esi mov 8(%esp),%edx mov 12(%esp),%edi mov $0x11111111,%ecx cmp %ecx,%eax .e cmp %ecx,%esi .e mov $0x22222222,%ecx cmp %ecx,%edx .e cmp %ecx,%edi .e jmp 2f .section .text,"ax",@progbits 2: #ifndef DISABLE_ROM .test "sse mov unaligned into ROM area" mov $0xf000,%ax mov %ax,%es mov $0xfff0-1,%bx movdqu %es:(%bx),%xmm3 movdqu %xmm3,saverom mov %es:16(%bx),%al mov %al,saverom+16 movdqu onetwo,%xmm1 movdqu %xmm1,%xmm2 movdqu %xmm2,%es:(%bx) movdqu %es:(%bx),%xmm4 pcmpeqb %xmm4,%xmm1 pmovmskb %xmm1,%eax inc %ax .ne movdqu %es:(%bx),%xmm5 pcmpeqb %xmm3,%xmm5 pmovmskb %xmm5,%eax inc %ax .e mov %es:(%bx),%eax cmp saverom,%eax .e mov %es:4(%bx),%eax cmp saverom+4,%eax .e mov %es:8(%bx),%eax cmp saverom+8,%eax .e mov %es:12(%bx),%eax cmp saverom+12,%eax .e .test "sse mov aligned into ROM area" inc %bx movdqa onetwo,%xmm1 movdqa %xmm1,%xmm2 movdqa %xmm2,%es:(%bx) pcmpeqb %es:(%bx),%xmm1 pmovmskb %xmm1,%eax inc %ax .ne movdqu saverom+1,%xmm6 pcmpeqb %es:(%bx),%xmm6 pmovmskb %xmm6,%eax inc %ax .e mov %es:(%bx),%eax cmp saverom+1,%eax .e mov %es:4(%bx),%eax cmp saverom+1+4,%eax .e mov %es:8(%bx),%eax cmp saverom+1+8,%eax .e mov %es:12(%bx),%eax cmp saverom+1+12,%eax .e #endif /* !DISABLE_ROM */ "test succeeded": .exit .align 16 onetwo: .quad 0x1111111111111111,0x2222222222222222 .lcomm saverom,17 ================================================ FILE: test/metal/string.S ================================================ #include "config.h" .section .head,"ax",@progbits .code16 .globl _start _start: // make -j8 o//blink o//test/metal/string.bin // o//blink/blinkenlights -r o//test/metal/string.bin 0: ljmpw $0,$1f ehead = 0b+0x200 1: xor %ax,%ax mov %ax,%ss mov $ehead+0x1000,%sp orl $-1,%ss:ehead // place something that is not the // same as our first instruction just // after our loaded boot sector mov $0x41a0/0x10,%ax mov %ax,%ds sub $0x200/0x10,%ax mov %ax,%es mov $ehead-1-0x41a0,%si // try to make 9 copies of our own mov %si,%di // code, by copying backwards mov $9*0x200,%cx // starting from 0x7c00+0x200-1 std rep movsb mov $0x1250/0x10,%ax // check there are now exactly 10 mov %ax,%ds // copies of the same boot code mov $0x27e0/0x10,%ax mov %ax,%es mov $-1,%cx mov $0b-0x1250-9*0x200,%si mov $0b-0x27e0-8*0x200,%di cld repe cmpsw je fail cmp $-2-9*0x200/2,%cx jne fail #ifndef DISABLE_ROM mov $0x3370/0x10,%ax mov %ax,%ds mov $0xf000+0xe920/0x10,%ax mov %ax,%es mov $0xfff0-0xe920,%di mov %es:(%di),%eax // make a copy of the CPU "power on mov %eax,good_poweron-0x3370 // restart" ROM code at 0xf000:0xfff0 mov %es:4(%di),%eax mov %eax,good_poweron+4-0x3370 mov %es:8(%di),%eax mov %eax,good_poweron+8-0x3370 mov %es:12(%di),%eax mov %eax,good_poweron+12-0x3370 mov $16,%cx // try to overwrite 0xf000:0xfff0 mov $bad_poweron-0x3370,%si cld rep movsb mov $0xf000+0xaa30/0x10,%ax // check that the ROM is unchanged mov %ax,%ds mov $0x7340/0x10,%ax mov %ax,%es mov $0xfff0-0xaa30,%si mov $good_poweron-0x7340,%di mov $4,%cl repe cmpsl jne fail dec %si // also check that the ROM does not dec %si // match the bad "power on" code we mov $8,%cl // tried to fill it with mov $bad_poweron+(16-2)-0x7340,%di std cmp %ax,%ax // force ZF = 1 here as an extra test repe cmpsw je fail mov $0x06e0/0x10,%ax // try to overwrite 0xf000:0xfff0, mov %ax,%ds // but backwards, shortword-wise, mov $0xf000+0xe470/0x10,%ax // & unaligned mov %ax,%es mov $0xfffd-0xe470,%di mov $bad_poweron+14-0x06e0,%si mov $7,%cx std rep movsw mov $0xf000+0xb400/0x10,%ax // check again that the ROM is mov %ax,%ds // unchanged mov $0x1c90/0x10,%ax mov %ax,%es mov %es:good_poweron-0x1c90,%eax cmp 0xfff0-0xb400,%eax jnz fail mov %es:good_poweron+4-0x1c90,%eax cmp 0xfff4-0xb400,%eax jnz fail mov %es:good_poweron+8-0x1c90,%eax cmp 0xfff8-0xb400,%eax jnz fail mov %es:good_poweron+12-0x1c90,%eax cmp 0xfffc-0xb400,%eax jnz fail #endif /* !DISABLE_ROM */ cli // test succeeded xor %edi,%edi mov %di,%ds lidt bad_idt mov $231,%eax syscall // this will triple fault on a real PC fail: ud2 hlt jmp fail .balign 8 bad_idt: .quad 0 bad_poweron: .quad 0x31bc50ea79cfccb5,0x11ade0c823d42d59 good_poweron: .skip 16 ================================================ FILE: test/metalrom/hello.S ================================================ #include "blink/biosrom.h" .macro hvcall callno:req .if (\callno) == 0 .byte 0x0F .byte 0xFF .byte 0077 .else .if (\callno) >= -0x80 && (\callno) <= 0x7f .byte 0x0F .byte 0xFF .byte 0177 .byte (\callno) .else addr16 .byte 0x0F .byte 0xFF .byte 0277 .short (\callno) .endif .endif .endm .section .text,"ax",@progbits .code16 // make -j8 o//blink o//test/metalrom/hello.bin // o//blink/blinkenlights -r -B o//test/metalrom/hello.bin \ // third_party/sectorlisp/sectorlisp-friendly.bin _start_1: mov %cs,%ax mov %ax,%ds cmp $kBiosSeg,%ax // test that %cs is sane jnz fail cmp $-4,%sp // test that the stack pointer is sane ja fail call 1f // test that %ip is sane 1: pop %ax cmp $1b,%ax jnz fail pop %ax // test that we arrived here from pop %dx // the call near linear address 0xFFFF0 movzwl %ax,%eax // (per visible value of caller %cs) movzwl %dx,%edx shl $4,%edx add %edx,%eax cmp $kBiosBase+9f,%eax jnz fail mov $0x40000000,%eax // test that we are running under a cltd // Blink VM xor %ebx,%ebx xor %ecx,%ecx cpuid xor $0x322809ae,%ebx cmp $('G' | 'e' << 8 | 'n' << 16 | 'u' << 24) ^ 0x322809ae,%ebx jnz fail xor $0xd1b18562,%ecx cmp $('i' | 'n' << 8 | 'e' << 16 | 'B' << 24) ^ 0xd1b18562,%ecx jnz fail xor $0x7421628a,%edx cmp $('l' | 'i' << 8 | 'n' << 16 | 'k' << 24) ^ 0x7421628a,%edx jnz fail mov $hello,%si // say hello cld 2: lodsb test %al,%al jz 3f out %al,$0xE9 mov $0x0e,%ah mov $0x0007,%bx hvcall 0x10 jmp 2b 3: cli // report success lidtw %cs:bad_idtr xor %edi,%edi mov $231,%eax syscall // this will triple fault on a real PC fail: cli hlt jmp fail .section .rodata,"a",@progbits .balign 8 bad_idtr: .quad 0 hello: .asciz "Hello world!\r\n" .section .fixedaddr.0xfff0,"ax",@progbits .globl _start _start: cli xor %esp,%esp mov %sp,%ss lcallw $kBiosSeg,$_start_1 9: ================================================ FILE: test/metalrom/metalrom.lds ================================================ ENTRY(_start) OUTPUT_FORMAT(binary) SECTIONS { .text (0xfff0 - ALIGN(_edata - _base, 0x10)) : { _base = .; *(.text .text.*) . = ALIGN(0x10); *(.rodata .rodata.*) . = ALIGN(0x10); *(.data .data.*) _edata = .; } .fixedaddr.0xfff0 0xfff0 : { *(.fixedaddr.0xfff0 .fixedaddr.0xfff0.*) } .fixedaddr.0xffff 0xffff : { BYTE(0) } /DISCARD/ : { *(.*) } } ================================================ FILE: test/metalrom/metalrom.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ TEST_METALROM_FILES := $(wildcard test/metalrom/*) TEST_METALROM_SRCS = $(filter %.S,$(TEST_METALROM_FILES)) TEST_METALROM_HDRS = $(filter %.h,$(TEST_METALROM_FILES)) TEST_METALROM_OBJS = $(TEST_METALROM_SRCS:%.S=o/$(MODE)/x86_64-gcc49/%.o) TEST_METALROM_BINS = $(TEST_METALROM_SRCS:%.S=o/$(MODE)/%.bin) TEST_METALROM_CHECKS = $(TEST_METALROM_BINS:%=%.ok) TEST_METALROM_LINK = \ $(VM) \ o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-ld.bfd \ -T test/metalrom/metalrom.lds \ -static \ $< \ -o $@ .PRECIOUS: o/$(MODE)/test/metalrom/%.bin o/$(MODE)/test/metalrom/%.bin: \ o/$(MODE)/x86_64-gcc49/test/metalrom/%.o \ o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc \ test/metalrom/metalrom.lds \ $(VM) @mkdir -p $(@D) $(TEST_METALROM_LINK) $(TEST_METALROM_OBJS): \ test/metalrom/metalrom.mk \ $(TEST_METALROM_HDRS) \ $(BLINK_HDRS) o/$(MODE)/test/metalrom/%.bin.ok: \ o/$(MODE)/test/metalrom/%.bin \ o/$(MODE)/blink/blinkenlights \ third_party/sectorlisp/sectorlisp-friendly.bin @mkdir -p $(@D) o/$(MODE)/blink/blinkenlights \ -r \ -t \ -B $< \ third_party/sectorlisp/sectorlisp-friendly.bin @touch $@ o/$(MODE)/test/metalrom: \ $(TEST_METALROM_CHECKS) ================================================ FILE: test/test.h ================================================ #ifndef TEST_TEST_H_ #define TEST_TEST_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include "blink/machine.h" #define TEST(GROUP, NAME) \ void GROUP##_##NAME(void); \ __attribute__((__constructor__)) void GROUP##_##NAME##_init(void) { \ static struct Test test; \ test.func = GROUP##_##NAME; \ test.next = g_testing.tests; \ g_testing.tests = &test; \ } \ void GROUP##_##NAME(void) #define ASSERT_EQ(WANT, GOT, ...) \ AssertionInt64(AssertEq, true, "ASSERT_EQ", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define EXPECT_EQ(WANT, GOT, ...) \ AssertionInt64(AssertEq, false, "EXPECT_EQ", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define ASSERT_NE(WANT, GOT, ...) \ AssertionInt64(AssertNe, true, "ASSERT_NE", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define EXPECT_NE(WANT, GOT, ...) \ AssertionInt64(AssertNe, false, "EXPECT_NE", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define ASSERT_LE(WANT, GOT, ...) \ AssertionInt64(AssertLe, true, "ASSERT_LE", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define EXPECT_LE(WANT, GOT, ...) \ AssertionInt64(AssertLe, false, "EXPECT_LE", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define ASSERT_GE(WANT, GOT, ...) \ AssertionInt64(AssertGe, true, "ASSERT_GE", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define EXPECT_GE(WANT, GOT, ...) \ AssertionInt64(AssertGe, false, "EXPECT_GE", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define ASSERT_LT(WANT, GOT, ...) \ AssertionInt64(AssertLt, true, "ASSERT_LT", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define EXPECT_LT(WANT, GOT, ...) \ AssertionInt64(AssertLt, false, "EXPECT_LT", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define ASSERT_GT(WANT, GOT, ...) \ AssertionInt64(AssertGt, true, "ASSERT_GT", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define EXPECT_GT(WANT, GOT, ...) \ AssertionInt64(AssertGt, false, "EXPECT_GT", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define ASSERT_STREQ(WANT, GOT, ...) \ AssertionStr(AssertStreq, true, "ASSERT_STREQ", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define EXPECT_STREQ(WANT, GOT, ...) \ AssertionStr(AssertStreq, false, "EXPECT_STREQ", __FILE__, __LINE__, \ __FUNCTION__, WANT, #WANT, GOT, #GOT, " " __VA_ARGS__) #define ASSERT_NOTNULL(GOT, ...) \ AssertionInt64(AssertNe, true, "ASSERT_NOTNULL", __FILE__, __LINE__, \ __FUNCTION__, 0, "NULL", (i64)(intptr_t)(GOT), #GOT, \ " " __VA_ARGS__) #define EXPECT_NOTNULL(GOT, ...) \ AssertionInt64(AssertNe, false, "EXPECT_NOTNULL", __FILE__, __LINE__, \ __FUNCTION__, 0, "NULL", (i64)(intptr_t)(GOT), #GOT, \ " " __VA_ARGS__) #define ASSERT_TRUE(GOT, ...) \ AssertionBool(true, true, __FILE__, __LINE__, __FUNCTION__, GOT, #GOT, \ " " __VA_ARGS__) #define EXPECT_TRUE(GOT, ...) \ AssertionBool(true, false, __FILE__, __LINE__, __FUNCTION__, GOT, #GOT, \ " " __VA_ARGS__) #define ASSERT_FALSE(GOT, ...) \ AssertionBool(false, true, __FILE__, __LINE__, __FUNCTION__, GOT, #GOT, \ " " __VA_ARGS__) #define EXPECT_FALSE(GOT, ...) \ AssertionBool(false, false, __FILE__, __LINE__, __FUNCTION__, GOT, #GOT, \ " " __VA_ARGS__) #define ASSERT_LDBL_EQ(WANT, GOT, ...) \ do { \ long double Got, Want; \ Got = GOT; \ Want = WANT; \ if (isnan(Got) || isnan(Want) || fabsl(Got - Want) > 0.00000001) { \ fprintf(stderr, "error:%s:%d: %s() ASSERT_LDBL_EQ failed:", __FILE__, \ __LINE__, __FUNCTION__); \ fprintf(stderr, " " __VA_ARGS__); \ fprintf(stderr, \ "\n\twant %Lg (%s)\n" \ "\tgot %Lg (%s)\n", \ Want, #WANT, Got, #GOT); \ exit(1); \ } \ } while (0) #define SPAWN(METHOD) \ { \ int child, _failed = g_testing.fails; \ ASSERT_NE(-1, (child = METHOD())); \ if (!child) { #define EXITS(CODE) \ PARENT() \ WAIT(Exit, CODE) #define TERMS(SIG) \ PARENT() \ WAIT(Term, SIG) #define PARENT() \ _Exit(MAX(0, MIN(255, g_testing.fails - _failed))); \ } #define WAIT(KIND, CODE) \ WaitFor##KIND(__FILE__, __LINE__, #CODE, CODE, child); \ } struct Test { struct Test *next; void (*func)(void); }; struct Tests { int fails; struct Test *tests; } g_testing; struct Garbage { struct Garbage *next; void *ptr; } * g_garbage; void SetUp(void); void TearDown(void); void *Gc(void *ptr) { struct Garbage *g; g = (struct Garbage *)malloc(sizeof(struct Garbage)); g->ptr = ptr; g->next = g_garbage; g_garbage = g; return ptr; } void Collect(struct Garbage *g) { if (!g) return; Collect(g->next); free(g->ptr); free(g); } char *Format(const char *Format, ...) { char *s; va_list va; s = (char *)Gc(malloc(64)); va_start(va, Format); vsnprintf(s, 64, Format, va); va_end(va); return s; } static void AssertionInt64(bool pred(int64_t, int64_t), bool isfatal, const char *test, const char *file, int line, const char *func, int64_t want, const char *wantstr, int64_t got, const char *gotstr, const char *fmt, ...) { va_list va; if (!pred(want, got)) { int err = errno; fprintf(stderr, "error:%s:%d: %s() %s failed:", file, line, func, test); va_start(va, fmt); vfprintf(stderr, fmt, va); va_end(va); fprintf(stderr, "\n\twant %" PRId64 " (%#" PRIx64 ") %s\n" "\tgot %" PRId64 " (%#" PRIx64 ") %s\n" "\terrno = %d (%s)\n", want, want, wantstr, got, got, gotstr, err, strerror(err)); if (isfatal) { exit(1); } else { ++g_testing.fails; } } } static void AssertionStr(bool pred(const char *, const char *), bool isfatal, const char *test, const char *file, int line, const char *func, const char *want, const char *wantstr, const char *got, const char *gotstr, const char *fmt, ...) { va_list va; char *gotcopy; char *wantcopy; if (!pred(want, got)) { fprintf(stderr, "error:%s:%d: %s() %s failed:", file, line, func, test); va_start(va, fmt); vfprintf(stderr, fmt, va); va_end(va); // we should ideally display an escaped version, but this should be // sufficient to not lose one's mind, when the strings are the same // but one of them contains invisible ansi escape sequences. gotcopy = strdup(got); wantcopy = strdup(want); for (long i = 0; gotcopy[i]; ++i) { if (!isprint(gotcopy[i])) { gotcopy[i] = '?'; } } for (long i = 0; wantcopy[i]; ++i) { if (!isprint(wantcopy[i])) { wantcopy[i] = '?'; } } fprintf(stderr, "\n" "\twant %s (%s)\n" "\tgot %s (%s)\n", wantcopy, wantstr, gotcopy, gotstr); free(gotcopy); free(wantcopy); if (isfatal) { exit(1); } else { ++g_testing.fails; } } } static void AssertionBool(bool need, bool isfatal, const char *file, int line, const char *func, bool got, const char *gotstr, const char *fmt, ...) { va_list va; if (got != need) { fprintf(stderr, "error:%s:%d: %s() ASSERT_%s failed:", file, line, func, need ? "TRUE" : "FALSE"); va_start(va, fmt); vfprintf(stderr, fmt, va); va_end(va); fprintf(stderr, "\n\t%s\n", gotstr); if (isfatal) { exit(1); } else { ++g_testing.fails; } } } static bool AssertStreq(const char *want, const char *got) { return !strcmp(want, got); } static bool AssertEq(int64_t want, int64_t got) { return want == got; } static bool AssertNe(int64_t want, int64_t got) { return want != got; } static bool AssertLe(int64_t want, int64_t got) { return want <= got; } static bool AssertGe(int64_t want, int64_t got) { return want >= got; } static bool AssertLt(int64_t want, int64_t got) { return want < got; } static bool AssertGt(int64_t want, int64_t got) { return want > got; } static void WaitForExit(const char *file, int line, const char *code, int rc, int pid) { int ws; char host[64]; ASSERT_NE(-1, wait(&ws)); if (WIFEXITED(ws)) { if (WEXITSTATUS(ws) == rc) { return; } fprintf(stderr, "%s:%d: test failed\n" "\tEXITS(%s)\n" "\t want WEXITSTATUS(%d)\n" "\t got WEXITSTATUS(%d)\n", file, line, code, rc, WEXITSTATUS(ws)); } else if (WIFSIGNALED(ws)) { fprintf(stderr, "%s:%d: test failed\n" "\tEXITS(%s)\n" "\t want _Exit(%d)\n" "\t got WTERMSIG(%s)\n", file, line, code, rc, strsignal(WTERMSIG(ws))); } else if (WIFSTOPPED(ws)) { fprintf(stderr, "%s:%d: test failed\n" "\tEXITS(%s)\n" "\t want _Exit(%d)\n" "\t got WSTOPSIG(%s)\n", file, line, code, rc, strsignal(WSTOPSIG(ws))); } else { fprintf(stderr, "%s:%d: test failed\n" "\tEXITS(%s)\n" "\t want _Exit(%d)\n" "\t got ws=%#x\n", file, line, code, rc, ws); } if (gethostname(host, sizeof(host))) { strcpy(host, "unknown"); } fprintf(stderr, "\t%s\n", host); exit(1); } static void WaitForTerm(const char *file, int line, const char *code, int sig, int pid) { int ws; char host[64]; ASSERT_NE(-1, waitpid(pid, &ws, 0)); if (WIFSIGNALED(ws)) { if (WTERMSIG(ws) == sig) { return; } fprintf(stderr, "%s:%d: test failed\n" "\tTERMS(%s)\n" "\t want WTERMSIG(%s)\n" "\t got WTERMSIG(%s)\n", file, line, code, strsignal(sig), strsignal(WTERMSIG(ws))); } else if (WIFEXITED(ws)) { fprintf(stderr, "%s:%d: test failed\n" "\tTERMS(%s)\n" "\t want WTERMSIG(%s)\n" "\t got _Exit(%d)\n", file, line, code, strsignal(sig), WEXITSTATUS(ws)); } else if (WIFSTOPPED(ws)) { fprintf(stderr, "%s:%d: test failed\n" "\tTERMS(%s)\n" "\t want WTERMSIG(%s)\n" "\t got WSTOPSIG(%s)\n", file, line, code, strsignal(sig), strsignal(WSTOPSIG(ws))); } else { fprintf(stderr, "%s:%d: test failed\n" "\tTERMS(%s)\n" "\t want WTERMSIG(%s)\n" "\t got ws=%#x\n", file, line, code, strsignal(sig), ws); } if (gethostname(host, sizeof(host))) { strcpy(host, "unknown"); } fprintf(stderr, "\t%s\n", host); exit(1); } _Noreturn void TerminateSignal(struct Machine *m, int sig) { abort(); } int main(int argc, char *argv[]) { struct Test *test; for (test = g_testing.tests; test; test = test->next) { SetUp(); test->func(); TearDown(); Collect(g_garbage); } return g_testing.fails; } #endif /* TEST_TEST_H_ */ ================================================ FILE: test/test.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ emulates = o/$(MODE)/$1.ok $(foreach ARCH,$(ARCHITECTURES),o/$(MODE)/$(ARCH)/$1.emulates) # make -j8 o//test/alu # very time consuming tests of our core arithmetic ops # https://github.com/jart/cosmopolitan/blob/master/test/tool/build/lib/optest.c # https://github.com/jart/cosmopolitan/blob/master/test/tool/build/lib/alu_test.c # https://github.com/jart/cosmopolitan/blob/master/test/tool/build/lib/bsu_test.c o/$(MODE)/test/alu: \ $(call emulates,third_party/cosmo/2/alu_test.com) \ $(call emulates,third_party/cosmo/2/bsu_test.com) @mkdir -p $(@D) @touch $@ # make -j8 o//test/sse # fast and fairly comprehensive tests for our simd instructions # https://github.com/jart/cosmopolitan/blob/master/test/libc/intrin/intrin_test.c o/$(MODE)/test/sse: \ $(call emulates,third_party/cosmo/8/intrin_test.com) \ $(call emulates,third_party/cosmo/2/popcnt_test.com) \ $(call emulates,third_party/cosmo/2/pshuf_test.com) \ $(call emulates,third_party/cosmo/2/pmulhrsw_test.com) \ $(call emulates,third_party/cosmo/2/divmul_test.com) \ $(call emulates,third_party/cosmo/2/palignr_test.com) @mkdir -p $(@D) @touch $@ # make -j8 o//test/lib # test some c libraries o/$(MODE)/test/lib: \ $(call emulates,third_party/cosmo/2/atoi_test.com) \ $(call emulates,third_party/cosmo/2/qsort_test.com) \ $(call emulates,third_party/cosmo/2/kprintf_test.com) @mkdir -p $(@D) @touch $@ # make -j8 o//test/sys # test linux system call emulation o/$(MODE)/test/sys: \ $(call emulates,third_party/cosmo/2/renameat_test.com) \ $(call emulates,third_party/cosmo/2/clock_gettime_test.com) \ $(call emulates,third_party/cosmo/2/clock_getres_test.com) \ $(call emulates,third_party/cosmo/2/clock_nanosleep_test.com) \ $(call emulates,third_party/cosmo/2/access_test.com) \ $(call emulates,third_party/cosmo/2/chdir_test.com) \ $(call emulates,third_party/cosmo/2/closefrom_test.com) \ $(call emulates,third_party/cosmo/2/commandv_test.com) \ $(call emulates,third_party/cosmo/2/dirstream_test.com) \ $(call emulates,third_party/cosmo/2/dirname_test.com) \ $(call emulates,third_party/cosmo/2/clone_test.com) \ $(call emulates,third_party/cosmo/2/fileexists_test.com) \ $(call emulates,third_party/cosmo/2/getcwd_test.com) \ $(call emulates,third_party/cosmo/2/lseek_test.com) \ $(call emulates,third_party/cosmo/2/mkdir_test.com) \ $(call emulates,third_party/cosmo/2/makedirs_test.com) \ $(call emulates,third_party/cosmo/2/nanosleep_test.com) \ $(call emulates,third_party/cosmo/2/readlinkat_test.com) \ $(call emulates,third_party/cosmo/2/symlinkat_test.com) \ $(call emulates,third_party/cosmo/2/tls_test.com) \ $(call emulates,third_party/cosmo/2/tmpfile_test.com) \ $(call emulates,third_party/cosmo/2/xslurp_test.com) @mkdir -p $(@D) @touch $@ o/$(MODE)/%.runs: o/$(MODE)/% $< @touch $@ o/$(MODE)/i486/%.runs: o/$(MODE)/i486/% o/third_party/qemu/4/qemu-i386 $(VM) $(VM) o/third_party/qemu/4/qemu-i386 $< @touch $@ o/$(MODE)/m68k/%.runs: o/$(MODE)/m68k/% o/third_party/qemu/4/qemu-m68k $(VM) $(VM) o/third_party/qemu/4/qemu-m68k $< @touch $@ o/$(MODE)/x86_64/%.runs: o/$(MODE)/x86_64/% o/third_party/qemu/4/qemu-x86_64 $(VM) $(VM) o/third_party/qemu/4/qemu-x86_64 -cpu core2duo $< @touch $@ o/$(MODE)/x86_64-gcc49/%.runs: o/$(MODE)/x86_64-gcc49/% o/third_party/qemu/4/qemu-x86_64 $(VM) $(VM) o/third_party/qemu/4/qemu-x86_64 -cpu core2duo $< @touch $@ o/$(MODE)/arm/%.runs: o/$(MODE)/arm/% o/third_party/qemu/4/qemu-arm $(VM) $(VM) o/third_party/qemu/4/qemu-arm $< @touch $@ o/$(MODE)/aarch64/%.runs: o/$(MODE)/aarch64/% o/third_party/qemu/4/qemu-aarch64 $(VM) $(VM) o/third_party/qemu/4/qemu-aarch64 $< @touch $@ o/$(MODE)/riscv64/%.runs: o/$(MODE)/riscv64/% o/third_party/qemu/4/qemu-riscv64 $(VM) $(VM) o/third_party/qemu/4/qemu-riscv64 $< @touch $@ o/$(MODE)/mips/%.runs: o/$(MODE)/mips/% o/third_party/qemu/4/qemu-mips $(VM) $(VM) o/third_party/qemu/4/qemu-mips $< @touch $@ o/$(MODE)/mipsel/%.runs: o/$(MODE)/mipsel/% o/third_party/qemu/4/qemu-mipsel $(VM) $(VM) o/third_party/qemu/4/qemu-mipsel $< @touch $@ o/$(MODE)/mips64/%.runs: o/$(MODE)/mips64/% o/third_party/qemu/4/qemu-mips64 $(VM) $(VM) o/third_party/qemu/4/qemu-mips64 $< @touch $@ o/$(MODE)/mips64el/%.runs: o/$(MODE)/mips64el/% o/third_party/qemu/4/qemu-mips64el $(VM) $(VM) o/third_party/qemu/4/qemu-mips64el $< @touch $@ o/$(MODE)/s390x/%.runs: o/$(MODE)/s390x/% o/third_party/qemu/4/qemu-s390x $(VM) $(VM) o/third_party/qemu/4/qemu-s390x $< @touch $@ o/$(MODE)/microblaze/%.runs: o/$(MODE)/microblaze/% o/third_party/qemu/4/qemu-microblaze $(VM) $(VM) o/third_party/qemu/4/qemu-microblaze $< @touch $@ o/$(MODE)/powerpc/%.runs: o/$(MODE)/powerpc/% o/third_party/qemu/4/qemu-ppc $(VM) $(VM) o/third_party/qemu/4/qemu-ppc $< @touch $@ o/$(MODE)/powerpc64le/%.runs: o/$(MODE)/powerpc64le/% o/third_party/qemu/4/qemu-ppc64le $(VM) $(VM) o/third_party/qemu/4/qemu-ppc64le $< @touch $@ o/$(MODE)/i486/%.emulates: % o/$(MODE)/i486/blink/blink o/third_party/qemu/4/qemu-i386 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-i386 o/$(MODE)/i486/blink/blink $< @touch $@ o/$(MODE)/m68k/%.emulates: % o/$(MODE)/m68k/blink/blink o/third_party/qemu/4/qemu-m68k $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-m68k o/$(MODE)/m68k/blink/blink $< @touch $@ o/$(MODE)/x86_64/%.emulates: % o/$(MODE)/x86_64/blink/blink o/third_party/qemu/4/qemu-x86_64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-x86_64 -cpu core2duo o/$(MODE)/x86_64/blink/blink $< @touch $@ o/$(MODE)/x86_64-gcc49/%.emulates: % o/$(MODE)/x86_64-gcc49/blink/blink o/third_party/qemu/4/qemu-x86_64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-x86_64 -cpu core2duo o/$(MODE)/x86_64-gcc49/blink/blink $< @touch $@ o/$(MODE)/arm/%.emulates: % o/$(MODE)/arm/blink/blink o/third_party/qemu/4/qemu-arm $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-arm o/$(MODE)/arm/blink/blink $< @touch $@ o/$(MODE)/aarch64/%.emulates: % o/$(MODE)/aarch64/blink/blink o/third_party/qemu/4/qemu-aarch64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-aarch64 o/$(MODE)/aarch64/blink/blink $< @touch $@ o/$(MODE)/riscv64/%.emulates: % o/$(MODE)/riscv64/blink/blink o/third_party/qemu/4/qemu-riscv64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-riscv64 o/$(MODE)/riscv64/blink/blink $< @touch $@ o/$(MODE)/mips/%.emulates: % o/$(MODE)/mips/blink/blink o/third_party/qemu/4/qemu-mips $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mips o/$(MODE)/mips/blink/blink $< @touch $@ o/$(MODE)/mipsel/%.emulates: % o/$(MODE)/mipsel/blink/blink o/third_party/qemu/4/qemu-mipsel $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mipsel o/$(MODE)/mipsel/blink/blink $< @touch $@ o/$(MODE)/mips64/%.emulates: % o/$(MODE)/mips64/blink/blink o/third_party/qemu/4/qemu-mips64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mips64 o/$(MODE)/mips64/blink/blink $< @touch $@ o/$(MODE)/mips64el/%.emulates: % o/$(MODE)/mips64el/blink/blink o/third_party/qemu/4/qemu-mips64el $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mips64el o/$(MODE)/mips64el/blink/blink $< @touch $@ o/$(MODE)/s390x/%.emulates: % o/$(MODE)/s390x/blink/blink o/third_party/qemu/4/qemu-s390x $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-s390x o/$(MODE)/s390x/blink/blink $< @touch $@ o/$(MODE)/microblaze/%.emulates: % o/$(MODE)/microblaze/blink/blink o/third_party/qemu/4/qemu-microblaze $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-microblaze o/$(MODE)/microblaze/blink/blink $< @touch $@ o/$(MODE)/powerpc/%.emulates: % o/$(MODE)/powerpc/blink/blink o/third_party/qemu/4/qemu-ppc $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-ppc o/$(MODE)/powerpc/blink/blink $< @touch $@ o/$(MODE)/powerpc64le/%.emulates: % o/$(MODE)/powerpc64le/blink/blink o/third_party/qemu/4/qemu-ppc64le $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-ppc64le o/$(MODE)/powerpc64le/blink/blink $< @touch $@ o/$(MODE)/i486/%.emulates: o/$(MODE)/% o/$(MODE)/i486/blink/blink o/third_party/qemu/4/qemu-i386 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-i386 o/$(MODE)/i486/blink/blink $< @touch $@ o/$(MODE)/m68k/%.emulates: o/$(MODE)/% o/$(MODE)/m68k/blink/blink o/third_party/qemu/4/qemu-m68k $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-m68k o/$(MODE)/m68k/blink/blink $< @touch $@ o/$(MODE)/x86_64/%.emulates: o/$(MODE)/% o/$(MODE)/x86_64/blink/blink o/third_party/qemu/4/qemu-x86_64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-x86_64 -cpu core2duo o/$(MODE)/x86_64/blink/blink $< @touch $@ o/$(MODE)/x86_64-gcc49/%.emulates: o/$(MODE)/% o/$(MODE)/x86_64-gcc49/blink/blink o/third_party/qemu/4/qemu-x86_64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-x86_64 -cpu core2duo o/$(MODE)/x86_64-gcc49/blink/blink $< @touch $@ o/$(MODE)/arm/%.emulates: o/$(MODE)/% o/$(MODE)/arm/blink/blink o/third_party/qemu/4/qemu-arm $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-arm o/$(MODE)/arm/blink/blink $< @touch $@ o/$(MODE)/aarch64/%.emulates: o/$(MODE)/% o/$(MODE)/aarch64/blink/blink o/third_party/qemu/4/qemu-aarch64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-aarch64 o/$(MODE)/aarch64/blink/blink $< @touch $@ o/$(MODE)/riscv64/%.emulates: o/$(MODE)/% o/$(MODE)/riscv64/blink/blink o/third_party/qemu/4/qemu-riscv64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-riscv64 o/$(MODE)/riscv64/blink/blink $< @touch $@ o/$(MODE)/mips/%.emulates: o/$(MODE)/% o/$(MODE)/mips/blink/blink o/third_party/qemu/4/qemu-mips $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mips o/$(MODE)/mips/blink/blink $< @touch $@ o/$(MODE)/mipsel/%.emulates: o/$(MODE)/% o/$(MODE)/mipsel/blink/blink o/third_party/qemu/4/qemu-mipsel $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mipsel o/$(MODE)/mipsel/blink/blink $< @touch $@ o/$(MODE)/mips64/%.emulates: o/$(MODE)/% o/$(MODE)/mips64/blink/blink o/third_party/qemu/4/qemu-mips64 $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mips64 o/$(MODE)/mips64/blink/blink $< @touch $@ o/$(MODE)/mips64el/%.emulates: o/$(MODE)/% o/$(MODE)/mips64el/blink/blink o/third_party/qemu/4/qemu-mips64el $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-mips64el o/$(MODE)/mips64el/blink/blink $< @touch $@ o/$(MODE)/s390x/%.emulates: o/$(MODE)/% o/$(MODE)/s390x/blink/blink o/third_party/qemu/4/qemu-s390x $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-s390x o/$(MODE)/s390x/blink/blink $< @touch $@ o/$(MODE)/microblaze/%.emulates: o/$(MODE)/% o/$(MODE)/microblaze/blink/blink o/third_party/qemu/4/qemu-microblaze $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-microblaze o/$(MODE)/microblaze/blink/blink $< @touch $@ o/$(MODE)/powerpc/%.emulates: o/$(MODE)/% o/$(MODE)/powerpc/blink/blink o/third_party/qemu/4/qemu-ppc $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-ppc o/$(MODE)/powerpc/blink/blink $< @touch $@ o/$(MODE)/powerpc64le/%.emulates: o/$(MODE)/% o/$(MODE)/powerpc64le/blink/blink o/third_party/qemu/4/qemu-ppc64le $(VM) @mkdir -p $(@D) $(VM) o/third_party/qemu/4/qemu-ppc64le o/$(MODE)/powerpc64le/blink/blink $< @touch $@ o/$(MODE)/test: \ o/$(MODE)/test/blink o/$(MODE)/test/emulates: \ o/$(MODE)/test/blink/emulates ================================================ FILE: third_party/.clang-format ================================================ DisableFormat: true SortIncludes: Never ================================================ FILE: third_party/coi-serviceworker/LICENSE ================================================ MIT License Copyright (c) 2021 Guido Zuidhof Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/coi-serviceworker/README.md ================================================ # coi-serviceworker ![npm](https://img.shields.io/npm/v/coi-serviceworker) ![size](https://img.shields.io/github/size/gzuidhof/coi-serviceworker/coi-serviceworker.min.js) Cross-origin isolation ([COOP and COEP](https://web.dev/coop-coep/)) through a service worker for situations in which you can't control the headers (e.g. GH pages). ## Usage 1. Download `coi-serviceworker.js` (or `coi-serviceworker.min.js`). 2. Put it next to your index file (or in any folder above it) 3. Add to your HTML file: ```html ``` This script will reload the page on the user's first load to magically add the required COOP and COEP headers in a service worker. **Rules**: * It must be in a separate file, you can't bundle it along with your app. * It can't be loaded from a CDN: it must be served from your own origin. * Your page will still need to be either served from HTTPS, or served from localhost. ### Extra credits: download from NPM You can install this package from npm: ``` npm i --save coi-serviceworker ``` You will still have to tell your bundler to put the file alongside your bundle. Something like this will do the trick: ```shell cp node_modules/coi-serviceworker/coi-serviceworker.js dist/ ``` ## Customization You can customize the behavior by defining a variable `coi` in the global scope (i.e. on the `window` object): ```javascript window.coi = { // // A function that is run to decide whether to register the SW or not. // You could for instance make this return a value based on whether you actually need to be cross origin isolated or not. shouldRegister: () => true, // If this function returns true, any existing service worker will be deregistered (and nothing else will happen). shouldDeregister: () => false, // A function that is run to decide whether to use "Cross-Origin-Embedder-Policy: credentialless" or not. // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy#browser_compatibility coepCredentialless: () => !(navigator.userAgent.indexOf("CriOS") > -1 || !window.chrome), // Override this if you want to prompt the user and do reload at your own leisure. Maybe show the user a message saying: // "Click OK to refresh the page to enable <...>" doReload: () => window.location.reload(), // Set to true if you don't want coi to log anything to the console. quiet: false } ``` Library and idea based on @stefnotch's [blog post](https://dev.to/stefnotch/enabling-coop-coep-without-touching-the-server-2d3n). ## License MIT ![Carp or Koi Artwork](https://i.imgur.com/HVyWe6T.jpeg) > Carp or Koi (1926) by Ohara Koson. Original from the Los Angeles County Museum of Art. Public Domain CC0 image. ================================================ FILE: third_party/coi-serviceworker/coi-serviceworker.js ================================================ /*! coi-serviceworker v0.1.6 - Guido Zuidhof, licensed under MIT */ let coepCredentialless = false; if (typeof window === 'undefined') { self.addEventListener("install", () => self.skipWaiting()); self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim())); self.addEventListener("message", (ev) => { if (!ev.data) { return; } else if (ev.data.type === "deregister") { self.registration .unregister() .then(() => { return self.clients.matchAll(); }) .then(clients => { clients.forEach((client) => client.navigate(client.url)); }); } else if (ev.data.type === "coepCredentialless") { coepCredentialless = ev.data.value; } }); self.addEventListener("fetch", function (event) { const r = event.request; if (r.cache === "only-if-cached" && r.mode !== "same-origin") { return; } const request = (coepCredentialless && r.mode === "no-cors") ? new Request(r, { credentials: "omit", }) : r; event.respondWith( fetch(request) .then((response) => { if (response.status === 0) { return response; } const newHeaders = new Headers(response.headers); newHeaders.set("Cross-Origin-Embedder-Policy", coepCredentialless ? "credentialless" : "require-corp" ); newHeaders.set("Cross-Origin-Opener-Policy", "same-origin"); return new Response(response.body, { status: response.status, statusText: response.statusText, headers: newHeaders, }); }) .catch((e) => console.error(e)) ); }); } else { (() => { // You can customize the behavior of this script through a global `coi` variable. const coi = { shouldRegister: () => true, shouldDeregister: () => false, coepCredentialless: () => false, doReload: () => window.location.reload(), quiet: false, ...window.coi }; const n = navigator; if (n.serviceWorker && n.serviceWorker.controller) { n.serviceWorker.controller.postMessage({ type: "coepCredentialless", value: coi.coepCredentialless(), }); if (coi.shouldDeregister()) { n.serviceWorker.controller.postMessage({ type: "deregister" }); } } // If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are // already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here. if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return; if (!window.isSecureContext) { !coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required."); return; } // In some environments (e.g. Chrome incognito mode) this won't be available if (n.serviceWorker) { n.serviceWorker.register(window.document.currentScript.src).then( (registration) => { !coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope); registration.addEventListener("updatefound", () => { !coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker."); coi.doReload(); }); // If the registration is active, but it's not controlling the page if (registration.active && !n.serviceWorker.controller) { !coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker."); coi.doReload(); } }, (err) => { !coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err); } ); } })(); } ================================================ FILE: third_party/cosmo/2/_timespec_test.com.dbg.gz.sha256 ================================================ fa12339aded86054bf0302eb4b046b16efd98b09262143058754516545bd0850 *third_party/cosmo/2/_timespec_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/_timespec_test.com.gz.sha256 ================================================ c3b7a7ba984ce739aa18162e22278a9c09c83a8e8f5f8efc83ae1998b9bbf157 *third_party/cosmo/2/_timespec_test.com.gz ================================================ FILE: third_party/cosmo/2/a64l_test.com.dbg.gz.sha256 ================================================ 982088e75a02f0a4a232f58787dbf903c9beb4974b0cf104109e5c44ca05cf78 *third_party/cosmo/2/a64l_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/a64l_test.com.gz.sha256 ================================================ 357d44b371c926ffe75f13d0032d631f4c6fed7c7c0c2db435b8df0e9f2d65ba *third_party/cosmo/2/a64l_test.com.gz ================================================ FILE: third_party/cosmo/2/abort_test.com.dbg.gz.sha256 ================================================ 34ad05dd7a1bb1dae333eb71abf331deabb4241ad45365bcfcbf483c4f52407d *third_party/cosmo/2/abort_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/abort_test.com.gz.sha256 ================================================ 22e4212e190a087649fa492a7b657627e45522c2cb4385f446313374af039cae *third_party/cosmo/2/abort_test.com.gz ================================================ FILE: third_party/cosmo/2/access_test.com.dbg.gz.sha256 ================================================ 068d2f7f40f0342735165150619758d562a67646c3ef1174adb474aa559d9a8b *third_party/cosmo/2/access_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/access_test.com.gz.sha256 ================================================ 8b8e02bcb2d33347352fa1938af581bc44875736985cc5db388b9aa225fcba54 *third_party/cosmo/2/access_test.com.gz ================================================ FILE: third_party/cosmo/2/acos_test.com.dbg.gz.sha256 ================================================ eafa0f999536532a267e1bce8167ea68dd4b8ac458520900605c2cebf3e86212 *third_party/cosmo/2/acos_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/acos_test.com.gz.sha256 ================================================ 7a16aef2623076ed9b044e818cd5747a513ae2696def6be7ae9acd55b4c56967 *third_party/cosmo/2/acos_test.com.gz ================================================ FILE: third_party/cosmo/2/acosh_test.com.dbg.gz.sha256 ================================================ 9d61ccb14173e9d8260a681891e4d071a20fca8eed10fdb073648a40e067bffb *third_party/cosmo/2/acosh_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/acosh_test.com.gz.sha256 ================================================ 7014d4a2ccc0309b460ba104d16363be3b4407d4c68463b080a0be924a223069 *third_party/cosmo/2/acosh_test.com.gz ================================================ FILE: third_party/cosmo/2/alaw_test.com.dbg.gz.sha256 ================================================ 72bc44ff7ac030961463e7754b9401c796fc7cb2785cf5364b55a556ea82116f *third_party/cosmo/2/alaw_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/alaw_test.com.gz.sha256 ================================================ dd24f1f8b0ce26c9c2220d5d656dfee04cb0e2603186b377f468d84dd65f676f *third_party/cosmo/2/alaw_test.com.gz ================================================ FILE: third_party/cosmo/2/alu_test.com.dbg.gz.sha256 ================================================ 63dcd6c6319ecf0c435f625a81916dfe300ba5d2cc04f5e4a22aece0a3d0d79e *third_party/cosmo/2/alu_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/alu_test.com.gz.sha256 ================================================ 3c0ff6cfea18e9a090b9daf53565060ca17c11b2fc51eda22d880a3664c70969 *third_party/cosmo/2/alu_test.com.gz ================================================ FILE: third_party/cosmo/2/appendresourcereport_test.com.dbg.gz.sha256 ================================================ 25532fa6b62bef9b6bcf1c659c54de8aefeace6fec037453bd543369ddc7222b *third_party/cosmo/2/appendresourcereport_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/appendresourcereport_test.com.gz.sha256 ================================================ 78ffae83701234644a838a5b113bf13b6afbe21eb676a3f4edb66f3621d2477f *third_party/cosmo/2/appendresourcereport_test.com.gz ================================================ FILE: third_party/cosmo/2/arch_prctl_test.com.dbg.gz.sha256 ================================================ e9c76b6970e1683170ea6b578a2d784e8071248ac0ee0ec22c8f0a5e4b2ed1f3 *third_party/cosmo/2/arch_prctl_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/arch_prctl_test.com.gz.sha256 ================================================ a5962f5fb4f7bfa873f3462c2cf79de7afed0b337b9a05ddc4b501280746c66c *third_party/cosmo/2/arch_prctl_test.com.gz ================================================ FILE: third_party/cosmo/2/arena_test.com.dbg.gz.sha256 ================================================ 5ff1492cb39bcf225832c23d57c442caa43b98f19e7a5dd16011fc07f082f156 *third_party/cosmo/2/arena_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/arena_test.com.gz.sha256 ================================================ 453e4581f27ad4126c2d41a0161dea5266d7dd4d52fea4c89850c12e3e90918f *third_party/cosmo/2/arena_test.com.gz ================================================ FILE: third_party/cosmo/2/argon2_test.com.dbg.gz.sha256 ================================================ 595e206c54898dc9aec0a2d53c0430df2922e297284ba00b3b918628e30eb130 *third_party/cosmo/2/argon2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/argon2_test.com.gz.sha256 ================================================ a841ae0fedb12e241f0705abd40acae0289f42ddd652685681ba1d883f7c3d72 *third_party/cosmo/2/argon2_test.com.gz ================================================ FILE: third_party/cosmo/2/args_test.com.dbg.gz.sha256 ================================================ 6373d461ea37dc728ec3009727615f0b60b00c7977a7152b6def3171b018ffd2 *third_party/cosmo/2/args_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/args_test.com.gz.sha256 ================================================ 28635607ed1d0acdfc3f60ec4d6eb8aaa93e841efc7a565701617e15b8ebcae0 *third_party/cosmo/2/args_test.com.gz ================================================ FILE: third_party/cosmo/2/arraylist_test.com.dbg.gz.sha256 ================================================ 80fbbf4a9fa6e0fc12b74d537ec59157cd78d3c52977bdfda2008861d0c4ddf5 *third_party/cosmo/2/arraylist_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/arraylist_test.com.gz.sha256 ================================================ 1f2c82e6cbaaf1a4c2689a5ef80d540fafdb92df39bb7f67d336e2432168bbc7 *third_party/cosmo/2/arraylist_test.com.gz ================================================ FILE: third_party/cosmo/2/asan_test.com.dbg.gz.sha256 ================================================ 5b2988255729a6ad830332ab1638943e406bce1a788f307905cea705401bb2d9 *third_party/cosmo/2/asan_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/asan_test.com.gz.sha256 ================================================ 32839f149c14c03462f0b0e20e058ee84537878ba63d219b89e18404be5c3997 *third_party/cosmo/2/asan_test.com.gz ================================================ FILE: third_party/cosmo/2/asin_test.com.dbg.gz.sha256 ================================================ 35b0623096815acbb7368e6601c3332986846701986978ea3ea536edf405807e *third_party/cosmo/2/asin_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/asin_test.com.gz.sha256 ================================================ a04c4c425038603ab019eb204a3a93c016389be4124cbefb9c9328a165e5afe2 *third_party/cosmo/2/asin_test.com.gz ================================================ FILE: third_party/cosmo/2/asinh_test.com.dbg.gz.sha256 ================================================ 95bee87bfc7d8e711cea21ad4c6266c4309e2db29db6d4bc57a3f844dff862d0 *third_party/cosmo/2/asinh_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/asinh_test.com.gz.sha256 ================================================ 04c8ca48a79725053ce4d1e2c6d1e780eaa2a000670d5755e769447cc5664ef8 *third_party/cosmo/2/asinh_test.com.gz ================================================ FILE: third_party/cosmo/2/asmdown_test.com.dbg.gz.sha256 ================================================ e747fae8e36d2ce3949e185eb6bda987354b69fe3ed74165e1d611356f1b5bd2 *third_party/cosmo/2/asmdown_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/asmdown_test.com.gz.sha256 ================================================ 64723fde003e6181edcec818d29bd3f12b7b48e30e290ff228ea3c9c419f6836 *third_party/cosmo/2/asmdown_test.com.gz ================================================ FILE: third_party/cosmo/2/atan2_test.com.dbg.gz.sha256 ================================================ ced5aea2869020e039ab537177c22d92dfeb0d379dbc06838203c09893327b68 *third_party/cosmo/2/atan2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/atan2_test.com.gz.sha256 ================================================ e7bd88efe2006b4da980aa62610da79f5fc9960f76aed122e9ee3bb43b877085 *third_party/cosmo/2/atan2_test.com.gz ================================================ FILE: third_party/cosmo/2/atan2l_test.com.dbg.gz.sha256 ================================================ 3622689fe93671bdf6f658a5cd59b0e7f02b70e414b64582b664add3188f3f1d *third_party/cosmo/2/atan2l_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/atan2l_test.com.gz.sha256 ================================================ 40f8cef79643346a68694036a44c357c887a514df98ab69d84b0fe0f03741e6a *third_party/cosmo/2/atan2l_test.com.gz ================================================ FILE: third_party/cosmo/2/atan_test.com.dbg.gz.sha256 ================================================ 3ea187c5bb2f7426e5a12ce10c6632abaf33c8c8d70fc85b4972104f5669eb10 *third_party/cosmo/2/atan_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/atan_test.com.gz.sha256 ================================================ ad9cce522b51d0ca2260e44c9eb1f54d9af5e072d6886e80ceed6ceb8462c191 *third_party/cosmo/2/atan_test.com.gz ================================================ FILE: third_party/cosmo/2/atanh_test.com.dbg.gz.sha256 ================================================ 62302916e428e3fea613839a175958a8113fa271ed097625360ab5fa1c5609d4 *third_party/cosmo/2/atanh_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/atanh_test.com.gz.sha256 ================================================ c139ad097ba3f49b6b3a73423e30300439010723fd5e3e4e95b2e7eecd0bf1f6 *third_party/cosmo/2/atanh_test.com.gz ================================================ FILE: third_party/cosmo/2/atanl_test.com.dbg.gz.sha256 ================================================ 2a75bda2e3b24d048f912404a03b8cc39a5362978b945f481f4fcaeede71a44d *third_party/cosmo/2/atanl_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/atanl_test.com.gz.sha256 ================================================ 0f325b80be7495b275ab7434266156620f352ddc95cd00244550e4481b4b5899 *third_party/cosmo/2/atanl_test.com.gz ================================================ FILE: third_party/cosmo/2/atoi_test.com.dbg.gz.sha256 ================================================ e004edefa7a8d663dfe11c4b0b83db50d8a82f60d5d27a88148ab342118c7bd9 *third_party/cosmo/2/atoi_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/atoi_test.com.gz.sha256 ================================================ 4fe27818721ae622163deda1807de2c7e9518509fe34fecedea864e071387a19 *third_party/cosmo/2/atoi_test.com.gz ================================================ FILE: third_party/cosmo/2/backtrace_test.com.dbg.gz.sha256 ================================================ 7e813c31dd843dfac077b060ce2dac58bd202050d786c1110bfa2d371f567a0a *third_party/cosmo/2/backtrace_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/backtrace_test.com.gz.sha256 ================================================ 7765421e7a4482987987395fbf9b4100481e24000873861ec4cc9392f68c54ea *third_party/cosmo/2/backtrace_test.com.gz ================================================ FILE: third_party/cosmo/2/basename_test.com.dbg.gz.sha256 ================================================ eb43fd8323e71358b51d181040d72b7436ed800185e288455da42c0ee94dc66e *third_party/cosmo/2/basename_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/basename_test.com.gz.sha256 ================================================ 622bb8e8c63813a7e35d6b6936ea18175db51d5acd1b30f3625dc58a27367058 *third_party/cosmo/2/basename_test.com.gz ================================================ FILE: third_party/cosmo/2/bextra_test.com.dbg.gz.sha256 ================================================ 55bb4effc5aaadd8894d87071d1cb8ef2b3750dd0b25255caa893c759281cd92 *third_party/cosmo/2/bextra_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bextra_test.com.gz.sha256 ================================================ f119bfaa8656abd4910116c2cc848f9f9b8f744bc7925539029c6655558629fb *third_party/cosmo/2/bextra_test.com.gz ================================================ FILE: third_party/cosmo/2/bilinearscale_test.com.dbg.gz.sha256 ================================================ 266470a52146d2f4f826b1dce97c30e595733db8193283c27e405d474bec9820 *third_party/cosmo/2/bilinearscale_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bilinearscale_test.com.gz.sha256 ================================================ 7f2a3fb0c2e0e5c044098a4f70ed22297be58e7a9016e03120b060ce32f4feb2 *third_party/cosmo/2/bilinearscale_test.com.gz ================================================ FILE: third_party/cosmo/2/bisectcarleft_test.com.dbg.gz.sha256 ================================================ 778c6447439d6a4fede508caec4efd1ef5a884583ac53ad0eef7b41f86b4388f *third_party/cosmo/2/bisectcarleft_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bisectcarleft_test.com.gz.sha256 ================================================ 3f6a472986af28c2843ca136b81c5b8f2076d1c8e3589ebe73a316bc3813ddd6 *third_party/cosmo/2/bisectcarleft_test.com.gz ================================================ FILE: third_party/cosmo/2/bitreverse_test.com.dbg.gz.sha256 ================================================ 44a3a0d9d8e178d2051320f5f788ec92727bfd901e96dd63bd52855a75756c45 *third_party/cosmo/2/bitreverse_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bitreverse_test.com.gz.sha256 ================================================ 8a29e1489a7eea7cde052ff365d1d3cc4007931650aded9fa1e45cd4f7ddbb78 *third_party/cosmo/2/bitreverse_test.com.gz ================================================ FILE: third_party/cosmo/2/bitscan_test.com.dbg.gz.sha256 ================================================ f22d82cb3b4f093350f970c0a93466054310536ffa3736ca5f7537ae6b1e0777 *third_party/cosmo/2/bitscan_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bitscan_test.com.gz.sha256 ================================================ ff47676e77c86e30dd2a494a147a03480cfd6972d62297d8820c7bd815d91bdb *third_party/cosmo/2/bitscan_test.com.gz ================================================ FILE: third_party/cosmo/2/blake2_test.com.dbg.gz.sha256 ================================================ ab740fa25d488c61f8d3c97d85a6d7ed245eda7db46c021e504a5d7dd67dd52b *third_party/cosmo/2/blake2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/blake2_test.com.gz.sha256 ================================================ ba75e9c763e6b9e04d27eac3d19756d2042665a35ebe660ba53755ce9930159a *third_party/cosmo/2/blake2_test.com.gz ================================================ FILE: third_party/cosmo/2/brk_test.com.dbg.gz.sha256 ================================================ ffa8c9b9e3ee55f6ff070188a61cc4867629494b3e3c92ca6f39eb6723fc9d06 *third_party/cosmo/2/brk_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/brk_test.com.gz.sha256 ================================================ 5d8096d29734b06a5a89090a4777f4d0d327cf40e8d7ea531bf23ca096c0cf06 *third_party/cosmo/2/brk_test.com.gz ================================================ FILE: third_party/cosmo/2/bsr_test.com.dbg.gz.sha256 ================================================ 9692fbb184a838e114a91f7fae1a7372bd282b15066528d438ad8d2392de949a *third_party/cosmo/2/bsr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bsr_test.com.gz.sha256 ================================================ 2bfba82ff99edd0016c4653fd45695659246c8d767d67365c185d7625801fc4b *third_party/cosmo/2/bsr_test.com.gz ================================================ FILE: third_party/cosmo/2/bsu_test.com.dbg.gz.sha256 ================================================ 11ec6f7ca41a0b8a0ffb75c91c9c0c9c447ef07c5ccb5301037602071b401640 *third_party/cosmo/2/bsu_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bsu_test.com.gz.sha256 ================================================ 60560521f307362fea76aadd318e54722b410938913e451277c07dc589eb2d01 *third_party/cosmo/2/bsu_test.com.gz ================================================ FILE: third_party/cosmo/2/bzero_test.com.dbg.gz.sha256 ================================================ 935e583ffb6cde1456d4cd8168f0cf784cdb835e3fec6505caa0712032504d57 *third_party/cosmo/2/bzero_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/bzero_test.com.gz.sha256 ================================================ ce50b8bfe5c17c672b582c0f64fb04e33f92b05abed6140ea25b95f42f803ea7 *third_party/cosmo/2/bzero_test.com.gz ================================================ FILE: third_party/cosmo/2/cas_test.com.dbg.gz.sha256 ================================================ c74e74ccd83fd5d1b2f3c2130c4fe1f8ec5751811aaf212c06d3daa085a4370b *third_party/cosmo/2/cas_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/cas_test.com.gz.sha256 ================================================ a06f56d1130decbede78e016c12b3ad0e0009d5d71c7cfda3fb0e7a543f4aaf5 *third_party/cosmo/2/cas_test.com.gz ================================================ FILE: third_party/cosmo/2/cbrt_test.com.dbg.gz.sha256 ================================================ e2c0da571c8caf7107cacb81b3ee5527ecc74f39f3d1069dd411e0516b18edbd *third_party/cosmo/2/cbrt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/cbrt_test.com.gz.sha256 ================================================ bb32cefe57adf35db078b350e088d05377a83a0925de3cc2b50c76eaba8b5334 *third_party/cosmo/2/cbrt_test.com.gz ================================================ FILE: third_party/cosmo/2/ceil_test.com.dbg.gz.sha256 ================================================ 80a722ccb8fb04e804a41a01cd0316897bedace988e0f9b05c4ed62f4bc78c32 *third_party/cosmo/2/ceil_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ceil_test.com.gz.sha256 ================================================ b50e1b1a43ddd8c87625315947970ad2830403b8579d9489f449af2a76d40503 *third_party/cosmo/2/ceil_test.com.gz ================================================ FILE: third_party/cosmo/2/cescapec_test.com.dbg.gz.sha256 ================================================ a9cf870b8e7b27ed36e654af59985e9081988ce53b0410d9e0d88e1192834e50 *third_party/cosmo/2/cescapec_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/cescapec_test.com.gz.sha256 ================================================ 8b924769300d339d075b770c7f624f198ce0dc6bd6591745ca8a1e5f4197abc5 *third_party/cosmo/2/cescapec_test.com.gz ================================================ FILE: third_party/cosmo/2/chdir_test.com.dbg.gz.sha256 ================================================ e19cf73faa244759f6e82faff92838e266534b827917e8c1d340ea04560a7b5b *third_party/cosmo/2/chdir_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/chdir_test.com.gz.sha256 ================================================ 69c4bf086b8634f0d8180f137074082aa34b60207d3d3874645cc21ca4f1f961 *third_party/cosmo/2/chdir_test.com.gz ================================================ FILE: third_party/cosmo/2/classifypath_test.com.dbg.gz.sha256 ================================================ e775f5a676ea102c6b19625ccd64f4832c1dbe4ecb6df23bcc79c13fd99ec463 *third_party/cosmo/2/classifypath_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/classifypath_test.com.gz.sha256 ================================================ dd5004f6767fa4133e48a35b63de4225755be4f9e726aef1b6ce00e360d8f8d3 *third_party/cosmo/2/classifypath_test.com.gz ================================================ FILE: third_party/cosmo/2/clock_getres_test.com.dbg.gz.sha256 ================================================ d08518297f0755c34e23efa6104fb95e46aabaf87eef18ecae0d3a18c2bbc5c7 *third_party/cosmo/2/clock_getres_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/clock_getres_test.com.gz.sha256 ================================================ d02ec8db1289abe22801fba032c5e34dce679757de6af32cbe0bc54d404df102 *third_party/cosmo/2/clock_getres_test.com.gz ================================================ FILE: third_party/cosmo/2/clock_gettime_test.com.dbg.gz.sha256 ================================================ eb4ede5bd65e9baeb0e291b5d4cb05b038336e8725c89f4479a2ed8931b5bc58 *third_party/cosmo/2/clock_gettime_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/clock_gettime_test.com.gz.sha256 ================================================ 8ef8e429de8463e7996a78f521694ac603ba6e6f04d5d309c1a0f962aded8fe4 *third_party/cosmo/2/clock_gettime_test.com.gz ================================================ FILE: third_party/cosmo/2/clock_nanosleep_test.com.dbg.gz.sha256 ================================================ 2d7fb960fdb5a237a3124e4f7690f25182419813d72780ed85c9cbb12320204d *third_party/cosmo/2/clock_nanosleep_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/clock_nanosleep_test.com.gz.sha256 ================================================ 18229e4793a4b2259d9cbee49f35cddaf584895aacf5da8fb602535c7c49dba1 *third_party/cosmo/2/clock_nanosleep_test.com.gz ================================================ FILE: third_party/cosmo/2/clone_test.com.dbg.gz.sha256 ================================================ 5b668bc58fcb5487005ca4955ad231cc9b752248236b7ca353a9760b6beccb25 *third_party/cosmo/2/clone_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/clone_test.com.gz.sha256 ================================================ 5a0bd0b24e59a5455c5215ee1c1b3a9f0b541583e619c04eee7373d76e4dcb46 *third_party/cosmo/2/clone_test.com.gz ================================================ FILE: third_party/cosmo/2/closefrom_test.com.dbg.gz.sha256 ================================================ 8669576e16e5b4c679a00adfc90f5fbc36a7bb6cd403bcbd3ecef7c15d1e4b55 *third_party/cosmo/2/closefrom_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/closefrom_test.com.gz.sha256 ================================================ b1c921218bcff2800994f5ac456d103245f3b69a33e8d5793a68ab785e1c5d05 *third_party/cosmo/2/closefrom_test.com.gz ================================================ FILE: third_party/cosmo/2/commandv_test.com.dbg.gz.sha256 ================================================ a222485868f7657545a8d80220963600682f9c8e5bb440d6dadc7f41b2942140 *third_party/cosmo/2/commandv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/commandv_test.com.gz.sha256 ================================================ 20471cadc2c36cbe2873b41a1afd0cf458f95c196b4f2b3886e4bff1cc0658d5 *third_party/cosmo/2/commandv_test.com.gz ================================================ FILE: third_party/cosmo/2/comparednsnames_test.com.dbg.gz.sha256 ================================================ defa40e435c97f32eddbd0847e698646a77f90dea62368f90df0791d3ea26d38 *third_party/cosmo/2/comparednsnames_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/comparednsnames_test.com.gz.sha256 ================================================ d075469b2674731ee551f782de44e5878a7a6ef4c0d3adb9a95f220762abeeaf *third_party/cosmo/2/comparednsnames_test.com.gz ================================================ FILE: third_party/cosmo/2/complex_test.com.dbg.gz.sha256 ================================================ 0fb2476848c1cc9415ac8d69a33f9fda8d74321a85a96943795d1ae1dc7b6587 *third_party/cosmo/2/complex_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/complex_test.com.gz.sha256 ================================================ 83ff8d48e8eedccf1bee680d01fff3305201254db5ce7be6cde39976afbb8d7c *third_party/cosmo/2/complex_test.com.gz ================================================ FILE: third_party/cosmo/2/convoindex_test.com.dbg.gz.sha256 ================================================ f0e6852e77edf7da16d61603a500dca2aaa21302bc5c414a734df950a00be3eb *third_party/cosmo/2/convoindex_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/convoindex_test.com.gz.sha256 ================================================ bcbaf8f248b9a8063208aee1c71ce578abf4e56eeabc7c4230485a0f3e6f148c *third_party/cosmo/2/convoindex_test.com.gz ================================================ FILE: third_party/cosmo/2/copy_file_range_test.com.dbg.gz.sha256 ================================================ 0a1951ec14ece54f79cbae0e1f0118e11960fd7c6a510796076ea648f8c760fd *third_party/cosmo/2/copy_file_range_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/copy_file_range_test.com.gz.sha256 ================================================ a3aa9d2a395a995ff807fc65e2762486c558c00869e908217688aed335c21c25 *third_party/cosmo/2/copy_file_range_test.com.gz ================================================ FILE: third_party/cosmo/2/copysign_test.com.dbg.gz.sha256 ================================================ 9c6d84ac6cf730341ec3c265a7627ba80e17f5fd6b63885f42dc835ab3ba2a13 *third_party/cosmo/2/copysign_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/copysign_test.com.gz.sha256 ================================================ c4ef5a596afa9edce6060bb1cf33e212adc584aa79597306f78a6bb77b8dd4d3 *third_party/cosmo/2/copysign_test.com.gz ================================================ FILE: third_party/cosmo/2/cos_test.com.dbg.gz.sha256 ================================================ 9b996a21d476ef36f5a2b3e68ade6b28c992b289d80cbd75dc7549b12037d9dd *third_party/cosmo/2/cos_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/cos_test.com.gz.sha256 ================================================ 74d5707fc9278a021fe0595c7cfa8dced23d01b67c8491b5f0d038ba7911a0d1 *third_party/cosmo/2/cos_test.com.gz ================================================ FILE: third_party/cosmo/2/cosh_test.com.dbg.gz.sha256 ================================================ 5fa9426db3cc97cac4b453b14344d229011a3df35a3ea081bc59961ab2673cca *third_party/cosmo/2/cosh_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/cosh_test.com.gz.sha256 ================================================ 06ad8a6b949342f9a49654eee1f8d821ced16fdc30883b9c3ed7b0ff658e2d41 *third_party/cosmo/2/cosh_test.com.gz ================================================ FILE: third_party/cosmo/2/countbits_test.com.dbg.gz.sha256 ================================================ 0931c8b1a95b31ba79fb997e46de24e0f4ba0f5abd8631f929845ee26e7e2d24 *third_party/cosmo/2/countbits_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/countbits_test.com.gz.sha256 ================================================ 679ddd4a5d9ad974c9b5fd9cea5aec0f53c93f61f393c531e374c911e0d3f236 *third_party/cosmo/2/countbits_test.com.gz ================================================ FILE: third_party/cosmo/2/counter_test.com.dbg.gz.sha256 ================================================ acf36a0f239a1655989d75ab9e21ed72a1ac5101870b0b9d5efeacf5dda01156 *third_party/cosmo/2/counter_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/counter_test.com.gz.sha256 ================================================ 4f2d8195128711bd57a89f607463e19b79e0b63c5dedc1c644060e36add16fde *third_party/cosmo/2/counter_test.com.gz ================================================ FILE: third_party/cosmo/2/crc32_test.com.dbg.gz.sha256 ================================================ 1f65c501bde8591d68ffda8ebdad543183c554ed2eb75c6ee9150fe131192ea2 *third_party/cosmo/2/crc32_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/crc32_test.com.gz.sha256 ================================================ 45cbe576a8422d9e7c833a58be5e2927654d41f4278a1e6d9b083253bdcf5715 *third_party/cosmo/2/crc32_test.com.gz ================================================ FILE: third_party/cosmo/2/crc32c_test.com.dbg.gz.sha256 ================================================ 528ca4850bf85e04d6928afb9f411ec21172b1686c41fd7a1ee55d2731ec81ac *third_party/cosmo/2/crc32c_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/crc32c_test.com.gz.sha256 ================================================ a610fa92c4ad20c0f75b0bda95a7fb6385ba51f27aed39904b2eb52a79928466 *third_party/cosmo/2/crc32c_test.com.gz ================================================ FILE: third_party/cosmo/2/crc32z_test.com.dbg.gz.sha256 ================================================ bf105b965394764931e561f66b1c97fee88943df713b7e73a08007333378b578 *third_party/cosmo/2/crc32z_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/crc32z_test.com.gz.sha256 ================================================ 7b06b218d2ddc84b81cf94f8bdedb9521d40e994a1bdef218b943cbc9c1b989e *third_party/cosmo/2/crc32z_test.com.gz ================================================ FILE: third_party/cosmo/2/critbit0_test.com.dbg.gz.sha256 ================================================ d535510105431718ab02cd5c0b26b5a187fec048cf474074b2363b2547736dd9 *third_party/cosmo/2/critbit0_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/critbit0_test.com.gz.sha256 ================================================ a6925bc7aa799ec4d7e3139c41d937a6e8313150919c1a9c9d8e9b2a1a727354 *third_party/cosmo/2/critbit0_test.com.gz ================================================ FILE: third_party/cosmo/2/crypt_test.com.dbg.gz.sha256 ================================================ 8a7ee78079812b8eec204e9aa2d42e70bb3c5d43644591ca6b2f4cd26e04ba09 *third_party/cosmo/2/crypt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/crypt_test.com.gz.sha256 ================================================ f3051bdd8a372fc268d1ed6feaf63cf4892118c3d5e6219d7ac3965dae7f465f *third_party/cosmo/2/crypt_test.com.gz ================================================ FILE: third_party/cosmo/2/csqrt_test.com.dbg.gz.sha256 ================================================ 9514c56a10dd4ec4d12d0c3fa617e0ba63a0b4188379e1e6860c6e80f08edb0a *third_party/cosmo/2/csqrt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/csqrt_test.com.gz.sha256 ================================================ db746edc802a206f4492e36cb77ef7e114a5f68375589ac67e024f0c23331bfd *third_party/cosmo/2/csqrt_test.com.gz ================================================ FILE: third_party/cosmo/2/cv_test.com.dbg.gz.sha256 ================================================ 73a267229f3e57bb3055b503359bd45d13f746638359d17521cd1b0c2b93332d *third_party/cosmo/2/cv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/cv_test.com.gz.sha256 ================================================ 818ca4be3091b383d30fc59ea1e6856920587598a8b316df2b32574a52dbbf85 *third_party/cosmo/2/cv_test.com.gz ================================================ FILE: third_party/cosmo/2/cv_wait_example_test.com.dbg.gz.sha256 ================================================ fcd5aa3f02b389419ffe3ce5e353a92f7a05ac7b1fc07d7d40d2dda25ac651de *third_party/cosmo/2/cv_wait_example_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/cv_wait_example_test.com.gz.sha256 ================================================ 21552614d568300e2c5a640ce5d09dc6da91f88ef34b559f4dd5eed019039cb6 *third_party/cosmo/2/cv_wait_example_test.com.gz ================================================ FILE: third_party/cosmo/2/daemon_test.com.dbg.gz.sha256 ================================================ b9e101f31abe01184a7ddc287a867f8674b03660b580a7839618e4ff11173a61 *third_party/cosmo/2/daemon_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/daemon_test.com.gz.sha256 ================================================ 3d1da0d45a074c3e7954b6d8dd48f1d1d7e609578dc2f36caff17d9240c824c5 *third_party/cosmo/2/daemon_test.com.gz ================================================ FILE: third_party/cosmo/2/decodebase64_test.com.dbg.gz.sha256 ================================================ 42d8322b6f51ac749016618494b7d2e52c6cceb106cda4c946082594a4366efb *third_party/cosmo/2/decodebase64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/decodebase64_test.com.gz.sha256 ================================================ 0ee7056a28076683ceea639b95c59994c61982bb9d8fdc7a1022eee051a0d78c *third_party/cosmo/2/decodebase64_test.com.gz ================================================ FILE: third_party/cosmo/2/decodelatin1_test.com.dbg.gz.sha256 ================================================ be27123830ccd54d7f7a51aa86b30ecd2873dd12a1320145c9ae53e460f95ba1 *third_party/cosmo/2/decodelatin1_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/decodelatin1_test.com.gz.sha256 ================================================ dff25ab23e92efd335424d58a8babb47b748b09ccaeac3dda5d24c4ed30ed937 *third_party/cosmo/2/decodelatin1_test.com.gz ================================================ FILE: third_party/cosmo/2/describeflags_test.com.dbg.gz.sha256 ================================================ a449017ae2da3a6c0cef1fe95dcb778003fc82db75c7557be8e54f613e786c19 *third_party/cosmo/2/describeflags_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/describeflags_test.com.gz.sha256 ================================================ 66dc906949cedc1a3b72095818ad11a5cad340aab42d153a9fcb6b7fd1e25822 *third_party/cosmo/2/describeflags_test.com.gz ================================================ FILE: third_party/cosmo/2/describegidlist_test.com.dbg.gz.sha256 ================================================ aaa18bf8477f97e2ce1e2feef90ff9315ac1a82bc4649abcf7fc66cbdf5d9b82 *third_party/cosmo/2/describegidlist_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/describegidlist_test.com.gz.sha256 ================================================ 6dd8ed2169b520ecec44ef0ed705f10fc161edd1382740ec25b899bdb3c9bf01 *third_party/cosmo/2/describegidlist_test.com.gz ================================================ FILE: third_party/cosmo/2/describesigset_test.com.dbg.gz.sha256 ================================================ 1aaa624108c672ca33d3d1773b638bcf24d32b1398c0437a3f1ed76940f55c1a *third_party/cosmo/2/describesigset_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/describesigset_test.com.gz.sha256 ================================================ 529a2b88b10c6ce65e0b5edca4797a70aaa9dd91bbe895959e426ba85a648ad2 *third_party/cosmo/2/describesigset_test.com.gz ================================================ FILE: third_party/cosmo/2/describesyn_test.com.dbg.gz.sha256 ================================================ 3a377832ba050acb012d7986521fbdda771274d3210a65699b9d110e066c8584 *third_party/cosmo/2/describesyn_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/describesyn_test.com.gz.sha256 ================================================ 622c1b5f0e4b38cb30ed850bf1d9f410b1ea2be03383804230ad2b8ca586c458 *third_party/cosmo/2/describesyn_test.com.gz ================================================ FILE: third_party/cosmo/2/devrand_test.com.dbg.gz.sha256 ================================================ c030012c9a7df15f8ab143fea81adb0489fe5bd96d60585395957411ec49e6d4 *third_party/cosmo/2/devrand_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/devrand_test.com.gz.sha256 ================================================ 3acf250ccd56a6c6dacac55033ee3836ed1ebe8150cac496bb1b34608bcb6d8a *third_party/cosmo/2/devrand_test.com.gz ================================================ FILE: third_party/cosmo/2/diagnose_syscall_test.com.dbg.gz.sha256 ================================================ b8b03d62918e2a43bdf2a81bce59ce1bf1ce4bd356d0a9bd529a798d17040041 *third_party/cosmo/2/diagnose_syscall_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/diagnose_syscall_test.com.gz.sha256 ================================================ ed7e6b06d90ea153db108e32f64b2df2712ca7ed0519a399c149ce38a5758f9d *third_party/cosmo/2/diagnose_syscall_test.com.gz ================================================ FILE: third_party/cosmo/2/dirname_test.com.dbg.gz.sha256 ================================================ ce20bb2bbfdb12bbc74afe2a15b92f8e9e94735c578e9c9541dd859a056ce08a *third_party/cosmo/2/dirname_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dirname_test.com.gz.sha256 ================================================ 139f1c57f929ef75b6ed31c5c2edeee4a81f9eca6af5d6bc83d4fe9407984930 *third_party/cosmo/2/dirname_test.com.gz ================================================ FILE: third_party/cosmo/2/dirstream_test.com.dbg.gz.sha256 ================================================ de9110cd7753c8012c1f62a0f3d1726859a1977c87ab2ff79178b67847941508 *third_party/cosmo/2/dirstream_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dirstream_test.com.gz.sha256 ================================================ bcf18629d26fc7325ee8b9e386add3d21b4b89e0e97ff0d4196ea710d4d5df0a *third_party/cosmo/2/dirstream_test.com.gz ================================================ FILE: third_party/cosmo/2/disinst_test.com.dbg.gz.sha256 ================================================ 3b3e1fb6d5a8c24c331403bb39c0e4ee1b7ba72d11c35658a4f0c3a046197570 *third_party/cosmo/2/disinst_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/disinst_test.com.gz.sha256 ================================================ b0a85a2d21ed7c75ef892eee82d3d421fbb8ba746a182f899b223b423895e81d *third_party/cosmo/2/disinst_test.com.gz ================================================ FILE: third_party/cosmo/2/division_test.com.dbg.gz.sha256 ================================================ 888c5a8a6e9a21a9e0600e2e419c428f36d47277906827fe227b48d3645ffe64 *third_party/cosmo/2/division_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/division_test.com.gz.sha256 ================================================ f84e51b76b4b42682f9c4551527e342ea7163e492ce5f7bb2bc1f45eae64f91f *third_party/cosmo/2/division_test.com.gz ================================================ FILE: third_party/cosmo/2/divmul_test.com.dbg.gz.sha256 ================================================ 1e453a5a1912ca926aa9f58cb9809e1a97b75363f7c7a91fa65e20ae72bde60d *third_party/cosmo/2/divmul_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/divmul_test.com.gz.sha256 ================================================ 2352657fda319cc4ce8be01a27bd4d6c473c6f475baccc66bc7c8ccbf0bbcf25 *third_party/cosmo/2/divmul_test.com.gz ================================================ FILE: third_party/cosmo/2/djbsort_test.com.dbg.gz.sha256 ================================================ 1e9be639a6b9a77043bfa68428537123d94ba60742c3be09f44be1fa8e3de5ba *third_party/cosmo/2/djbsort_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/djbsort_test.com.gz.sha256 ================================================ 8bef821608dd4c02ab6c72736636f94966506d901a9cf6c31ae7968230361c66 *third_party/cosmo/2/djbsort_test.com.gz ================================================ FILE: third_party/cosmo/2/dll_test.com.dbg.gz.sha256 ================================================ d5981e86b6f0842e74e229178c78b656dcbfe9fd64eada1d698f0f42710c24d8 *third_party/cosmo/2/dll_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dll_test.com.gz.sha256 ================================================ 8b971b96037f68138eb651b605044de5f3a07805d6f39531b0e813f5e29e692e *third_party/cosmo/2/dll_test.com.gz ================================================ FILE: third_party/cosmo/2/dnsheader_test.com.dbg.gz.sha256 ================================================ e954742debdb2da636d48319eaffcbea71dac84056d83e4022c103bde201aa93 *third_party/cosmo/2/dnsheader_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dnsheader_test.com.gz.sha256 ================================================ b69f392f4ec8a42035c58319fa477f46ae1a3319b1a1b437283536fcccad60f0 *third_party/cosmo/2/dnsheader_test.com.gz ================================================ FILE: third_party/cosmo/2/dnsquestion_test.com.dbg.gz.sha256 ================================================ dde4c771d0115fd1ffbcf42aba0fb2796b75c91af0a9d9bdfe2f624311faee52 *third_party/cosmo/2/dnsquestion_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dnsquestion_test.com.gz.sha256 ================================================ 32c75cb6321e18255fa30c60d5f1e1ca2f309b27c721210bcee9f2fa0cb21cd9 *third_party/cosmo/2/dnsquestion_test.com.gz ================================================ FILE: third_party/cosmo/2/dos2errno_test.com.dbg.gz.sha256 ================================================ 821580e904b1e1e829566069bb63d69d8089b9f92c1f3c485f5438bca04ff1f2 *third_party/cosmo/2/dos2errno_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dos2errno_test.com.gz.sha256 ================================================ ad7b70df8bfe3cd4e9e093593e91f389ba6c538f2b6ee299e9c7795a5dba013f *third_party/cosmo/2/dos2errno_test.com.gz ================================================ FILE: third_party/cosmo/2/dumphexc_test.com.dbg.gz.sha256 ================================================ b9c950d5caf173849cef0d06b4876edf215b44fc610d3862471ef8c67d193082 *third_party/cosmo/2/dumphexc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dumphexc_test.com.gz.sha256 ================================================ 1c751e48e19db7d30ba11cb1b3c4d640dfd3803a23f5131f49ac0c75251a1748 *third_party/cosmo/2/dumphexc_test.com.gz ================================================ FILE: third_party/cosmo/2/dup_test.com.dbg.gz.sha256 ================================================ 8c55589404c53b9c2256c8457a6eca35fd474e087bc82833b4152013d4ce3ada *third_party/cosmo/2/dup_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/dup_test.com.gz.sha256 ================================================ b0d44d5e2742631d92190d1c254fb0a7112f45eaef8f5089e673e3297a0616c7 *third_party/cosmo/2/dup_test.com.gz ================================================ FILE: third_party/cosmo/2/ecvt_test.com.dbg.gz.sha256 ================================================ eb0d1f0035c5cfada08d16c7248d170a8f3063cb61f0aa42ec62b2b558044218 *third_party/cosmo/2/ecvt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ecvt_test.com.gz.sha256 ================================================ 62aca7a59cc63ab8c1e4983617d732c563fb44b2c46359151d62a09fb206b688 *third_party/cosmo/2/ecvt_test.com.gz ================================================ FILE: third_party/cosmo/2/encodebase64_test.com.dbg.gz.sha256 ================================================ 3c2e0556b7a50d22e9bd7ab7efabca281742b87df1ac52aca9a653f042efb1d5 *third_party/cosmo/2/encodebase64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/encodebase64_test.com.gz.sha256 ================================================ 96220cf7c44bcbd52bea0a98c60c7ae69b035c0cfba33a0181f31c510c2748b9 *third_party/cosmo/2/encodebase64_test.com.gz ================================================ FILE: third_party/cosmo/2/encodehttpheadervalue_test.com.dbg.gz.sha256 ================================================ 3dbbd0449e9d181bfea6e9f09e79c1e8137bc1b2bd68d639b3f1bef75d9dca57 *third_party/cosmo/2/encodehttpheadervalue_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/encodehttpheadervalue_test.com.gz.sha256 ================================================ 4ced361c21efa3244bde457395eec7fba600da4d11b5c8332874323050c296a7 *third_party/cosmo/2/encodehttpheadervalue_test.com.gz ================================================ FILE: third_party/cosmo/2/encodenf32_test.com.dbg.gz.sha256 ================================================ 28dce62f74c28836fb40d80df468cd10e5928100c10795224b2b3cd39bb9a43c *third_party/cosmo/2/encodenf32_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/encodenf32_test.com.gz.sha256 ================================================ 183684169b5f21491589670ea1f11cfdc9269c156a7790f50b4521836857bd44 *third_party/cosmo/2/encodenf32_test.com.gz ================================================ FILE: third_party/cosmo/2/erf_test.com.dbg.gz.sha256 ================================================ f929bf2a5c1c08ca0114ab2c8df813da8e27238c9b28193eab3712238c35fc02 *third_party/cosmo/2/erf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/erf_test.com.gz.sha256 ================================================ 024874ac43d8a823728526211ba3c632f8146c19c62a3de8ae141812f56a70d3 *third_party/cosmo/2/erf_test.com.gz ================================================ FILE: third_party/cosmo/2/escapehtml_test.com.dbg.gz.sha256 ================================================ 39359020db51ece1afb66674d29ac2ccc0664e09b757eb7ce38876dd811a75be *third_party/cosmo/2/escapehtml_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/escapehtml_test.com.gz.sha256 ================================================ 2b050bec54886e0015fa8285725db7899433e83d713f7cfc232454e7805043e9 *third_party/cosmo/2/escapehtml_test.com.gz ================================================ FILE: third_party/cosmo/2/escapejsstringliteral_test.com.dbg.gz.sha256 ================================================ ba7de5afcdd0b60e242c8ca5fd26d1c879c7e57265f4b47167b933bb23647f5a *third_party/cosmo/2/escapejsstringliteral_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/escapejsstringliteral_test.com.gz.sha256 ================================================ ff19036f39314b79ba763e9d2b8efd1a028363d85d7eb1d045a2e77c47f92246 *third_party/cosmo/2/escapejsstringliteral_test.com.gz ================================================ FILE: third_party/cosmo/2/escapeurlparam_test.com.dbg.gz.sha256 ================================================ d40a3fce01402e5067a8f100ec365b29185643c7e22e3ba92cf54800028d6525 *third_party/cosmo/2/escapeurlparam_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/escapeurlparam_test.com.gz.sha256 ================================================ beb4ebb9980cdf184b8faff23fb205fed61f3b5d51d65895be49b2cea9e86201 *third_party/cosmo/2/escapeurlparam_test.com.gz ================================================ FILE: third_party/cosmo/2/everest_test.com.dbg.gz.sha256 ================================================ fcd3538c65fdf79298926bf60db8e192036aef20a023b8343a84e2d659118a70 *third_party/cosmo/2/everest_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/everest_test.com.gz.sha256 ================================================ 8fcd80bb2a6a387fca28e88194c7aed817df0ac8196c1a944ab4978c41df0f45 *third_party/cosmo/2/everest_test.com.gz ================================================ FILE: third_party/cosmo/2/execve_test.com.dbg.gz.sha256 ================================================ f7fba42eda2fd4e5c3d82c26d5859aeb730fd8db12383d5562ce795d774359ec *third_party/cosmo/2/execve_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/execve_test.com.gz.sha256 ================================================ f2ba06720974702f0839595c48f6e133831fc57983c6b66bf4efe4e927d164d5 *third_party/cosmo/2/execve_test.com.gz ================================================ FILE: third_party/cosmo/2/exit_test.com.dbg.gz.sha256 ================================================ 9e6d84cd03dfecc50353bbbb57b7f98a83842b019c20d22c6e2886728ae50b2b *third_party/cosmo/2/exit_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/exit_test.com.gz.sha256 ================================================ 08fe11832da07b07b93ffdeb3866833c0f387ac4fd202d5bba18758bbdf229ea *third_party/cosmo/2/exit_test.com.gz ================================================ FILE: third_party/cosmo/2/exp10_test.com.dbg.gz.sha256 ================================================ 5a499407f67e49f8802055ad5ab2dd0b57155b8e3792eea7b152954341412d9f *third_party/cosmo/2/exp10_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/exp10_test.com.gz.sha256 ================================================ 419dfbcd489da36820a0b7ab5ef5763c79adc247a780454b3ef55ddb34a0a738 *third_party/cosmo/2/exp10_test.com.gz ================================================ FILE: third_party/cosmo/2/exp2_test.com.dbg.gz.sha256 ================================================ 57581f377e8367350a78d5a6df055ff5f49d54adc275bb3a1aa384a158229438 *third_party/cosmo/2/exp2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/exp2_test.com.gz.sha256 ================================================ 3df7b8f4f1b55df55675c9ece30796d06f28962324dd02e3ea914d95e567fe5a *third_party/cosmo/2/exp2_test.com.gz ================================================ FILE: third_party/cosmo/2/exp2l_test.com.dbg.gz.sha256 ================================================ a56b8b2a4d836a07357aa1a153ee6c1b008dd109e9fd44983e4917ced66283a7 *third_party/cosmo/2/exp2l_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/exp2l_test.com.gz.sha256 ================================================ ec97de1b2f0ce4dd01c1a38fadf29b3e8fcb8b7d34411eec3d2bc6a178f1f9d1 *third_party/cosmo/2/exp2l_test.com.gz ================================================ FILE: third_party/cosmo/2/exp_test.com.dbg.gz.sha256 ================================================ 5b921c57f4500d272471972ce7ba39ca8852245f7903f36b5a920fd2bac145ff *third_party/cosmo/2/exp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/exp_test.com.gz.sha256 ================================================ 1aaa883df95c2eaa549e0f8a957f1e3d53119763732885221ef488250a2d81d8 *third_party/cosmo/2/exp_test.com.gz ================================================ FILE: third_party/cosmo/2/expm1_test.com.dbg.gz.sha256 ================================================ bc3c4659476dba58bbd78534c8836686d24dca522ec5dbb63bb0151ae2c7df90 *third_party/cosmo/2/expm1_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/expm1_test.com.gz.sha256 ================================================ 707244b76f3f0d5f234b170ef273ce9624d41d11b0be6be969ae8f97660ef4ba *third_party/cosmo/2/expm1_test.com.gz ================================================ FILE: third_party/cosmo/2/fabs_test.com.dbg.gz.sha256 ================================================ ebe52d05e367c6871a82343fc8d133469e5041275e365c39335cc55a6fa45197 *third_party/cosmo/2/fabs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fabs_test.com.gz.sha256 ================================================ c0939b151a38ca4466cf24416baca690867031d6ecf572db22b1bc5db4dfdb4a *third_party/cosmo/2/fabs_test.com.gz ================================================ FILE: third_party/cosmo/2/fcntl_test.com.dbg.gz.sha256 ================================================ 53e79e4ff57961dbf8da716e3ceef7b8d7df6722867dbab07250a95da052ccbb *third_party/cosmo/2/fcntl_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fcntl_test.com.gz.sha256 ================================================ 6965b196983560ee194b7cf6d0482dbca359e7cdb24d3a5b0f45e5a20b7d54a1 *third_party/cosmo/2/fcntl_test.com.gz ================================================ FILE: third_party/cosmo/2/fexecve_test.com.dbg.gz.sha256 ================================================ 9a2bfd10596ad252b7bf1e16b4426bda828f3e815c8151192f953b857f492179 *third_party/cosmo/2/fexecve_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fexecve_test.com.gz.sha256 ================================================ 9ef160684d51cd99cfcc5cfe4786e103a6a264af8ac3040a2a521d508cabc61d *third_party/cosmo/2/fexecve_test.com.gz ================================================ FILE: third_party/cosmo/2/ffs_test.com.dbg.gz.sha256 ================================================ c26b6688444328cb44bea36b003db023b2006e64ff3fdf5150be94e3bbaaad97 *third_party/cosmo/2/ffs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ffs_test.com.gz.sha256 ================================================ 952325142ae09229ee367f16fd5f4defc649d2d4f3912455d3b041e99b1fa327 *third_party/cosmo/2/ffs_test.com.gz ================================================ FILE: third_party/cosmo/2/fgetln_test.com.dbg.gz.sha256 ================================================ 0f39976f335ebbbd2a48166a7817198768f85e1e832022dfa2d194d61cb7097a *third_party/cosmo/2/fgetln_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fgetln_test.com.gz.sha256 ================================================ cd05d32de9fa92095e82c63875016f88be1e27959f2c2286205ec3e2a7d4878b *third_party/cosmo/2/fgetln_test.com.gz ================================================ FILE: third_party/cosmo/2/fgets_test.com.dbg.gz.sha256 ================================================ ef772a9986faadd35dc800085b74b0451751268f6b0c3db941af42971af0aee7 *third_party/cosmo/2/fgets_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fgets_test.com.gz.sha256 ================================================ 9bb1038f2ff9c4e261611bb2ec1867720f66d299493456a022f2421f2fc3fec1 *third_party/cosmo/2/fgets_test.com.gz ================================================ FILE: third_party/cosmo/2/fgetwc_test.com.dbg.gz.sha256 ================================================ 3e447feade39dec34f1375b581cbb80024dbd77478be2b2f7c77c33af1dc1fc6 *third_party/cosmo/2/fgetwc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fgetwc_test.com.gz.sha256 ================================================ c1b02407c34e04a14453df8f92d2b5efc1c9e1e56835fa269cc53d8cb4dd8e19 *third_party/cosmo/2/fgetwc_test.com.gz ================================================ FILE: third_party/cosmo/2/fileexists_test.com.dbg.gz.sha256 ================================================ dfbffe3ab1baec968b55715adedc52b24255945007447762e638bd6f6c894406 *third_party/cosmo/2/fileexists_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fileexists_test.com.gz.sha256 ================================================ 84e5e23c7b8509fa2f944ceeb538e6b5b48c9429a426b95e3fca68e2004fda18 *third_party/cosmo/2/fileexists_test.com.gz ================================================ FILE: third_party/cosmo/2/findcontenttype_test.com.dbg.gz.sha256 ================================================ 9dc77af76868a67f1ec57f570ba5ae3f566d309de160811c7574971dc1d10347 *third_party/cosmo/2/findcontenttype_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/findcontenttype_test.com.gz.sha256 ================================================ 5b0b0d063c061bb5e816a02808f821786437689b6465df2f68727969af29442f *third_party/cosmo/2/findcontenttype_test.com.gz ================================================ FILE: third_party/cosmo/2/fingersyn_test.com.dbg.gz.sha256 ================================================ 91c83b74eb7fdb1e9be4cac9da0708862be9941a1dc28aa7eae31deac049606c *third_party/cosmo/2/fingersyn_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fingersyn_test.com.gz.sha256 ================================================ 4f1182402c1d8f37a8af146eef213ff35645625384dd11ebd6abfbe793a929e8 *third_party/cosmo/2/fingersyn_test.com.gz ================================================ FILE: third_party/cosmo/2/floor_test.com.dbg.gz.sha256 ================================================ 0ee46adbe85e178438e6ab71086962084f79c2775896bef5e31e343e3ca315d9 *third_party/cosmo/2/floor_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/floor_test.com.gz.sha256 ================================================ 19e728034ecaabf7af6bb0c137821c144c12d6f57a7dc0159ebeb53965d2bbb3 *third_party/cosmo/2/floor_test.com.gz ================================================ FILE: third_party/cosmo/2/fmemopen_test.com.dbg.gz.sha256 ================================================ 90c63de8e428d93824e6bed71e794f917de91f199d0d0022fc392229edfa7adc *third_party/cosmo/2/fmemopen_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fmemopen_test.com.gz.sha256 ================================================ c3fadb837252eb9c2c6ccd9c2e1e7367cbf939462cc767241011066eed14e926 *third_party/cosmo/2/fmemopen_test.com.gz ================================================ FILE: third_party/cosmo/2/fmod_test.com.dbg.gz.sha256 ================================================ a3eab887743ee6c0da9fb4f95a6e9daadfd9f8b0f7fbfc373e0faf79171283ee *third_party/cosmo/2/fmod_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fmod_test.com.gz.sha256 ================================================ d8a66cb658cb014287270235fcdbf6558b099a357d2d8014e3fdb05de6b68d1b *third_party/cosmo/2/fmod_test.com.gz ================================================ FILE: third_party/cosmo/2/fmt_test.com.dbg.gz.sha256 ================================================ ca665f87ab6c3ce727389e9cc4dcd78a5df10336083d756c548f468646a1f158 *third_party/cosmo/2/fmt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fmt_test.com.gz.sha256 ================================================ aebcc8bf062d47240b8beaaf37de823a017c90b3c3f0ef6384565f011c1e3325 *third_party/cosmo/2/fmt_test.com.gz ================================================ FILE: third_party/cosmo/2/fork_test.com.dbg.gz.sha256 ================================================ 3215ac6defda3006fb65e84394340db0a7fd7c40e1969256f73580fb37e3515a *third_party/cosmo/2/fork_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fork_test.com.gz.sha256 ================================================ 4b108559419a474074c25956c7f89407638d6831b28f82ca418e094046b082e3 *third_party/cosmo/2/fork_test.com.gz ================================================ FILE: third_party/cosmo/2/formatbinary64_test.com.dbg.gz.sha256 ================================================ 9bb34dfcd79905192a191803153b3ef417d56da444c5caffac3e751834eecf89 *third_party/cosmo/2/formatbinary64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formatbinary64_test.com.gz.sha256 ================================================ d84907df3aaa418c4773481329f2827e154e50933663a933f20cb4ca5badc44e *third_party/cosmo/2/formatbinary64_test.com.gz ================================================ FILE: third_party/cosmo/2/formatflex64_test.com.dbg.gz.sha256 ================================================ 51ef84e3be99d7a0c4e7edc98087300d3632a9d983e665d11c3db2769edd2c18 *third_party/cosmo/2/formatflex64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formatflex64_test.com.gz.sha256 ================================================ ca0e5d4ad5eb8de0c433a4f2e8f9aba54bc1a86d74a368a7a6d9e4b2f6aebdfe *third_party/cosmo/2/formatflex64_test.com.gz ================================================ FILE: third_party/cosmo/2/formathex64_test.com.dbg.gz.sha256 ================================================ afdfc9cfd0e7f84a21847eaffe6c975112c35b1cdaae9cde82e096e578dfdddd *third_party/cosmo/2/formathex64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formathex64_test.com.gz.sha256 ================================================ 43c044e8bfde0c47966c5de7fce75faa3fe10b24a1139e5fc38aa8f9da70a610 *third_party/cosmo/2/formathex64_test.com.gz ================================================ FILE: third_party/cosmo/2/formathttpdatetime_test.com.dbg.gz.sha256 ================================================ 1948818dcae2c150b875001bad2eda5c2b5e75879e378fe1e52219a22a1bef74 *third_party/cosmo/2/formathttpdatetime_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formathttpdatetime_test.com.gz.sha256 ================================================ 9baca7033b31f798e853902c9bb8504088f57c75a0c320602c6afa652d05c6ce *third_party/cosmo/2/formathttpdatetime_test.com.gz ================================================ FILE: third_party/cosmo/2/formatint32_test.com.dbg.gz.sha256 ================================================ ac33894de2c7904f6295e69ae27bc29530bb30d6753ef08978231bca7f206ac0 *third_party/cosmo/2/formatint32_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formatint32_test.com.gz.sha256 ================================================ fc1f834f09c14e51ffbcbc974d079494a05b8a457d01e1c262427f35e27e6c9d *third_party/cosmo/2/formatint32_test.com.gz ================================================ FILE: third_party/cosmo/2/formatint64_test.com.dbg.gz.sha256 ================================================ 190ccd3b4911e0b0f73acb50291a2ad7099a3e452a45ba320988c94a7eec43f7 *third_party/cosmo/2/formatint64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formatint64_test.com.gz.sha256 ================================================ 6da02914bd7716e76e52e1eb2c918f638ffcb87cb2659c4b700af62f69a4c91a *third_party/cosmo/2/formatint64_test.com.gz ================================================ FILE: third_party/cosmo/2/formatint64thousands_test.com.dbg.gz.sha256 ================================================ 8e60884f0cb117ee317e677b8b73a172f5fef7a162cdd6ee2c58698fc25cec51 *third_party/cosmo/2/formatint64thousands_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formatint64thousands_test.com.gz.sha256 ================================================ 01bafb2b005c9fd14cdac35ee168e1b37ae0b48e6ad7a8f5e5cda77e95060c55 *third_party/cosmo/2/formatint64thousands_test.com.gz ================================================ FILE: third_party/cosmo/2/formatoctal32_test.com.dbg.gz.sha256 ================================================ 264ce4fe8c9ea14b320d5e1aeeb9ff33507623569cd4ef18a0402c7e7dd8b4e7 *third_party/cosmo/2/formatoctal32_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formatoctal32_test.com.gz.sha256 ================================================ 63a408b7389ca192a6fe43d99b1b04420607417e6ad96f95c7892291589bdc5d *third_party/cosmo/2/formatoctal32_test.com.gz ================================================ FILE: third_party/cosmo/2/formatoctal64_test.com.dbg.gz.sha256 ================================================ 444492de3007688fa3384a6b2b73a8fa00c6cf697c3fdc28465b88e52f0428a3 *third_party/cosmo/2/formatoctal64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/formatoctal64_test.com.gz.sha256 ================================================ b049483dff909b84f6fc247b74f07116caff39bbc90dc04bfbe3757e63807dec *third_party/cosmo/2/formatoctal64_test.com.gz ================================================ FILE: third_party/cosmo/2/fputc_test.com.dbg.gz.sha256 ================================================ 8163ba55600d8ecd32303e34db586837012219c01b19bb1bcd56f0df32283562 *third_party/cosmo/2/fputc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fputc_test.com.gz.sha256 ================================================ 4b3e049596d99d68cea41b93909e7ffb7255f47fe75dbd57fa47bfdaf057a3a9 *third_party/cosmo/2/fputc_test.com.gz ================================================ FILE: third_party/cosmo/2/fputs_test.com.dbg.gz.sha256 ================================================ ab033faa6ed06a7487b2eb133b8a8b9934283c0647c7c434db1fa7263e31b901 *third_party/cosmo/2/fputs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fputs_test.com.gz.sha256 ================================================ daf14431b790a97c4fbb85f91a5b1cca6ac257d9dfd55340b2b278eed817a82c *third_party/cosmo/2/fputs_test.com.gz ================================================ FILE: third_party/cosmo/2/fread_test.com.dbg.gz.sha256 ================================================ e960c0130c3490886d9df7e3968aee267073e3a86fa04206d15207ae5fb1fa97 *third_party/cosmo/2/fread_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fread_test.com.gz.sha256 ================================================ 3cb80e97dd6e61ae6fdd5a598d14cd231bcfab54855930e87f8da0ec0762c1a2 *third_party/cosmo/2/fread_test.com.gz ================================================ FILE: third_party/cosmo/2/freopen_test.com.dbg.gz.sha256 ================================================ f4cebebcfe22cd0a33640428496b895be851a17d1a9cd417ac71ac5657598ba8 *third_party/cosmo/2/freopen_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/freopen_test.com.gz.sha256 ================================================ a14f2291219188ef0006fa965bcba961efeb5e103ef1c0f8168ba60792814278 *third_party/cosmo/2/freopen_test.com.gz ================================================ FILE: third_party/cosmo/2/fseeko_test.com.dbg.gz.sha256 ================================================ 2528d7fad6bd01cd0ac284725297a13203deef7defd95ee59224f6b3a37b85df *third_party/cosmo/2/fseeko_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fseeko_test.com.gz.sha256 ================================================ 62b486ed3e9b971e7e289dff0256ccb962349f77d0e8ecfdf33ae60b32ebc2b4 *third_party/cosmo/2/fseeko_test.com.gz ================================================ FILE: third_party/cosmo/2/fsum_test.com.dbg.gz.sha256 ================================================ 14ed5fdcb4f78e4ed2cf2e833b91d3849a48dd4401059edc82366336a3d4fb7c *third_party/cosmo/2/fsum_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fsum_test.com.gz.sha256 ================================================ 3bc5d2fd9195fc754049c29a88eb59f063f8eff0ecec0192521f47655d6dd4b5 *third_party/cosmo/2/fsum_test.com.gz ================================================ FILE: third_party/cosmo/2/ftell_test.com.dbg.gz.sha256 ================================================ b42311f2d4707d5e4f9d246fbf97815e06b594efcc9a47f6722335aa37e86893 *third_party/cosmo/2/ftell_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ftell_test.com.gz.sha256 ================================================ 7a36f38bedfe5d72dcc48fcec2b4d17466ce6dc23739f1e7aa9f298b5ea81b36 *third_party/cosmo/2/ftell_test.com.gz ================================================ FILE: third_party/cosmo/2/fun_test.com.dbg.gz.sha256 ================================================ 8c748dde89cae3affc363b04677a9350381249c41c37d592739bd6a84131cb86 *third_party/cosmo/2/fun_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fun_test.com.gz.sha256 ================================================ 4e5b72f298d61a48221295d489c8f467071180a2e1466a20f6c6bd72debe58f8 *third_party/cosmo/2/fun_test.com.gz ================================================ FILE: third_party/cosmo/2/fwrite_test.com.dbg.gz.sha256 ================================================ 4a277968122db5c0a5d019324ac1e8052e886909b31ae38747ab7e1eaedc4010 *third_party/cosmo/2/fwrite_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/fwrite_test.com.gz.sha256 ================================================ a79fa764621662fc29154e36fcf48905ada3d4a0da6e5eb2d006c2b476594dc2 *third_party/cosmo/2/fwrite_test.com.gz ================================================ FILE: third_party/cosmo/2/gamma_test.com.dbg.gz.sha256 ================================================ 536553b8e919e1060333350691decab2302262bc484df8b7fdbd8bd74e553649 *third_party/cosmo/2/gamma_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/gamma_test.com.gz.sha256 ================================================ f99b540df2e6937a01f0314526bcc5e1d24eaf2c782cd7bd245ba4f0c8349ba8 *third_party/cosmo/2/gamma_test.com.gz ================================================ FILE: third_party/cosmo/2/gclongjmp_test.com.dbg.gz.sha256 ================================================ afe3dccecba471e00e0f7cbfb0142b28be30708fe05cf99c295eebcddd03a22e *third_party/cosmo/2/gclongjmp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/gclongjmp_test.com.gz.sha256 ================================================ aa5f9999c6b6622aa0878ef8f398244a2f22fddeddb701c20600b7408af634b4 *third_party/cosmo/2/gclongjmp_test.com.gz ================================================ FILE: third_party/cosmo/2/getargs_test.com.dbg.gz.sha256 ================================================ 00f9d65d4facf3505ac40cdc06d041185b62f24bc0140e5b232058b856fbd4e4 *third_party/cosmo/2/getargs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getargs_test.com.gz.sha256 ================================================ 6f0421dce3482bb279f83ea2a94cac5d87bdc612579ffe4c27b72f9fd35dfd82 *third_party/cosmo/2/getargs_test.com.gz ================================================ FILE: third_party/cosmo/2/getciphersuite_test.com.dbg.gz.sha256 ================================================ 81c1d8bf18748b9b28bc7a1afa647e071be19a0873e76be63ad3cfa82e62db15 *third_party/cosmo/2/getciphersuite_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getciphersuite_test.com.gz.sha256 ================================================ ad1f90df971289e58f876ae1bcd8aefe49f9a324e5a0c791003acbe0b891117b *third_party/cosmo/2/getciphersuite_test.com.gz ================================================ FILE: third_party/cosmo/2/getcontext_test.com.dbg.gz.sha256 ================================================ bb926db48835ade47ea27d8d7b33568cc1b44c67919dede26305b24b6d7fdabd *third_party/cosmo/2/getcontext_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getcontext_test.com.gz.sha256 ================================================ 7cd4c3a0c505e57f1372b869affdf845fe768f2336a76b1a5fb66b5a230aa7c2 *third_party/cosmo/2/getcontext_test.com.gz ================================================ FILE: third_party/cosmo/2/getcwd_test.com.dbg.gz.sha256 ================================================ 7ece7b2a2bddaf50c49876461af75dc257df0f3f0c35f0a4d3ba72255cc712bd *third_party/cosmo/2/getcwd_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getcwd_test.com.gz.sha256 ================================================ 2085af3b863b6ce1581ee25d9726843b7e215d78b667d7485c54370e63cf62fd *third_party/cosmo/2/getcwd_test.com.gz ================================================ FILE: third_party/cosmo/2/getdelim_test.com.dbg.gz.sha256 ================================================ cdd45f683344b1a34d280d0c87d25546c4477d3cf599a6dffafbc89ab6f31f99 *third_party/cosmo/2/getdelim_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getdelim_test.com.gz.sha256 ================================================ 95aa74ad48b1ad4029e2d030d44f392002e1d6a5d13fe5dcdfb3b8709a9fa341 *third_party/cosmo/2/getdelim_test.com.gz ================================================ FILE: third_party/cosmo/2/getdosargv_test.com.dbg.gz.sha256 ================================================ 50f27e4753c08c2757a680c3e6054251de75fff569a366e0c1f99e15f414837a *third_party/cosmo/2/getdosargv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getdosargv_test.com.gz.sha256 ================================================ 5513f70052e5daf495b636701229bfe2f81fb4495b427c7d36c413585111214f *third_party/cosmo/2/getdosargv_test.com.gz ================================================ FILE: third_party/cosmo/2/getdosenviron_test.com.dbg.gz.sha256 ================================================ dc553d634196d2c776a67504cde496ce751b9a975d00feb18c10192894cc26fe *third_party/cosmo/2/getdosenviron_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getdosenviron_test.com.gz.sha256 ================================================ 959807fd31b45e14011c0173b13132987236cf12dc00b0485598daf2068b4abd *third_party/cosmo/2/getdosenviron_test.com.gz ================================================ FILE: third_party/cosmo/2/getentropy_test.com.dbg.gz.sha256 ================================================ 81419cd84e63e22028a1ca1e42b5835cc981f6f760afeebc56893c5f763f3a0d *third_party/cosmo/2/getentropy_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getentropy_test.com.gz.sha256 ================================================ 07998d00e31521c3c70a842520c72a63275ccb01253216ccac1c0268e3f2051c *third_party/cosmo/2/getentropy_test.com.gz ================================================ FILE: third_party/cosmo/2/getenv_test.com.dbg.gz.sha256 ================================================ f5ef59ea5a83d2974035fd46f12708bd3a39368a7b2b9e4f10a384f9be0c36bd *third_party/cosmo/2/getenv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getenv_test.com.gz.sha256 ================================================ 33129db368f501d632dba1d87fc7ad4ad53c5176f1f1196a0087601829dfcd44 *third_party/cosmo/2/getenv_test.com.gz ================================================ FILE: third_party/cosmo/2/getgroups_test.com.dbg.gz.sha256 ================================================ eb5a566efd19663c355b8732dd0d46f4ba06eb0971b2de0b421439b4534e233e *third_party/cosmo/2/getgroups_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getgroups_test.com.gz.sha256 ================================================ 4683d4852fd5d844e503656ea4fa141a085faa6064ab396002ec725de580e2fc *third_party/cosmo/2/getgroups_test.com.gz ================================================ FILE: third_party/cosmo/2/getintegercoefficients8_test.com.dbg.gz.sha256 ================================================ 3199d2ac4f26888eaf2b10ecc9d950e80599d8af87534aba2c1c50e3947d995e *third_party/cosmo/2/getintegercoefficients8_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getintegercoefficients8_test.com.gz.sha256 ================================================ c2ba4262e41e564be1d8e0cc20d75ba1343d6abfbab86e4e0a9ffa330d52e603 *third_party/cosmo/2/getintegercoefficients8_test.com.gz ================================================ FILE: third_party/cosmo/2/getintegercoefficients_test.com.dbg.gz.sha256 ================================================ b956792d4333ae9d25891036af5b68fad122e4c9295eebd13b561f614aa29119 *third_party/cosmo/2/getintegercoefficients_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getintegercoefficients_test.com.gz.sha256 ================================================ bb5a8c2afcce9234890f5e989e84b1c7f4fe5a78a7cd872fc439e8dec4fba7f4 *third_party/cosmo/2/getintegercoefficients_test.com.gz ================================================ FILE: third_party/cosmo/2/getitimer_test.com.dbg.gz.sha256 ================================================ c41c13f1f77fdbebf6061b02908eef49b51c489232d5a05f1cbec9155488bc5f *third_party/cosmo/2/getitimer_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getitimer_test.com.gz.sha256 ================================================ 7f1c6058515039fefe6e11660ac76df04e8ec648c30ba2b1605216d8a51ab0c3 *third_party/cosmo/2/getitimer_test.com.gz ================================================ FILE: third_party/cosmo/2/getpriority_test.com.dbg.gz.sha256 ================================================ c71131a80863dd7869e2e04b905d815b51661b61b909df2417f29c2b187cff5f *third_party/cosmo/2/getpriority_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getpriority_test.com.gz.sha256 ================================================ 2fb5666ad0d7e73da09d4d92ffac055c2d4b85b1a3b98c29fcb691b3f15a634e *third_party/cosmo/2/getpriority_test.com.gz ================================================ FILE: third_party/cosmo/2/getrandom_test.com.dbg.gz.sha256 ================================================ 643607fde6dbda1fa5ba0bf468b170aa747c9aae96fc48c8ef2c507408e94bb5 *third_party/cosmo/2/getrandom_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/getrandom_test.com.gz.sha256 ================================================ 662920d1f8b1d394b742c7976803a2f285802f06a134ee5c31c0e4581ad772c9 *third_party/cosmo/2/getrandom_test.com.gz ================================================ FILE: third_party/cosmo/2/grow_test.com.dbg.gz.sha256 ================================================ 36ae164187fc5746fc49664a4c02636a8a86d529f2b3e7b8668ee0d1809ee8db *third_party/cosmo/2/grow_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/grow_test.com.gz.sha256 ================================================ 2fa4b14405cfe803b46e8436656e19df5cc0fd45223d286b861ead973589a22f *third_party/cosmo/2/grow_test.com.gz ================================================ FILE: third_party/cosmo/2/gz_test.com.dbg.gz.sha256 ================================================ 1836a84c4794e62599de88c649a5a2cdd4d7c599b5d16f10855301d75408a371 *third_party/cosmo/2/gz_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/gz_test.com.gz.sha256 ================================================ 9ecf8a237547a0440b51d9038860374d274217e302907b7cb7f9fa48d438539f *third_party/cosmo/2/gz_test.com.gz ================================================ FILE: third_party/cosmo/2/halfblit_test.com.dbg.gz.sha256 ================================================ 872b2ae0409910ce681e177ebdaaabddcd288103429b63abe9358ee79a0519b8 *third_party/cosmo/2/halfblit_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/halfblit_test.com.gz.sha256 ================================================ c464a3db220dc441257c9dc7291b8ec84286e63af6b3e906fe05136f4656b666 *third_party/cosmo/2/halfblit_test.com.gz ================================================ FILE: third_party/cosmo/2/hascontrolcodes_test.com.dbg.gz.sha256 ================================================ ab02c442e0c77ba70ca8fe887ffc0032a8152dedf5872821416ce7818ae9a058 *third_party/cosmo/2/hascontrolcodes_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/hascontrolcodes_test.com.gz.sha256 ================================================ 5a4df550670c9f3cec776b3da21b07610007761470c7b0a9844be837b134bc53 *third_party/cosmo/2/hascontrolcodes_test.com.gz ================================================ FILE: third_party/cosmo/2/hexpcpy_test.com.dbg.gz.sha256 ================================================ ac75562a2eb046383e7bce3f8fc7e27326835cb985a1eeb70d88e6349e780148 *third_party/cosmo/2/hexpcpy_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/hexpcpy_test.com.gz.sha256 ================================================ ada42d0d612ff5ed44d71fdc525c5cdfb77147df26c69d5ddf8d413a1e05f45e *third_party/cosmo/2/hexpcpy_test.com.gz ================================================ FILE: third_party/cosmo/2/highwayhash64_test.com.dbg.gz.sha256 ================================================ 5cf97482dcb2bb05afe52b700258273a722b7bad08153debee738e79327892fe *third_party/cosmo/2/highwayhash64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/highwayhash64_test.com.gz.sha256 ================================================ bd8cbcde32718bf2618b7c142e7eaf3dbad2d819441a993b359832adb307eeef *third_party/cosmo/2/highwayhash64_test.com.gz ================================================ FILE: third_party/cosmo/2/hypot_test.com.dbg.gz.sha256 ================================================ a8d834b5c9be57ec1a5aded5b0b557b08a1eb95d9fab247f94383f305a8f3499 *third_party/cosmo/2/hypot_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/hypot_test.com.gz.sha256 ================================================ 1071afbd62a6189cbe28a409310faf6c82ac0a44d9f79d3bd053dc0e4cfbf47b *third_party/cosmo/2/hypot_test.com.gz ================================================ FILE: third_party/cosmo/2/iconv_test.com.dbg.gz.sha256 ================================================ a624163c1b28d07af091457058aaad91644b03d2116bc755bb6d0b45e651c792 *third_party/cosmo/2/iconv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/iconv_test.com.gz.sha256 ================================================ e516ad38c84ec5caf12ed346cd59f0462897bfd8a171c44a9ca50c7e894f11c9 *third_party/cosmo/2/iconv_test.com.gz ================================================ FILE: third_party/cosmo/2/illumination_test.com.dbg.gz.sha256 ================================================ 0261f2145220e46ccab08c50396fa8068ef269b56dc07b2099f2b7a7729c5830 *third_party/cosmo/2/illumination_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/illumination_test.com.gz.sha256 ================================================ 0205aa8a7da103e2dbaf0dd808d1415dd4ba8ae45dae289ae30018f35d98477b *third_party/cosmo/2/illumination_test.com.gz ================================================ FILE: third_party/cosmo/2/ilogb_test.com.dbg.gz.sha256 ================================================ 62ac77f3d4fff95c017f4423f317b3365d4bde01e6c43607e82a61c309d998cc *third_party/cosmo/2/ilogb_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ilogb_test.com.gz.sha256 ================================================ d67959ddc9a05853dd35d9fc52054c2abe308b9f7f643696b43f00d16e51a622 *third_party/cosmo/2/ilogb_test.com.gz ================================================ FILE: third_party/cosmo/2/imaxdiv_test.com.dbg.gz.sha256 ================================================ a1ec4cb7567465b7f8826ebe23f522cd6196117ec0a70e8a4795d170475a0f03 *third_party/cosmo/2/imaxdiv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/imaxdiv_test.com.gz.sha256 ================================================ b2850d35fc469ce39678f1c033e9e066f5681e6f147ece0d68d9f7755a8ccb9d *third_party/cosmo/2/imaxdiv_test.com.gz ================================================ FILE: third_party/cosmo/2/indentlines_test.com.dbg.gz.sha256 ================================================ 37006c075f4bccf55e174e5ad8476711a4d9a902422e5c86ad69bf8a63a58c2f *third_party/cosmo/2/indentlines_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/indentlines_test.com.gz.sha256 ================================================ 40a7b9ecb204d828689c3affa54f32402a968f23840edeec662943d8c7dc344b *third_party/cosmo/2/indentlines_test.com.gz ================================================ FILE: third_party/cosmo/2/inet_ntoa_test.com.dbg.gz.sha256 ================================================ 4ce09fe654e7a9aa2473611fa5ea2ac3b867860ff973ab962deffc750fede6d9 *third_party/cosmo/2/inet_ntoa_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/inet_ntoa_test.com.gz.sha256 ================================================ e03cc9aa842be4d3e11bf076bf632f174eb72f1d2f835d65321a1567f5e2bf98 *third_party/cosmo/2/inet_ntoa_test.com.gz ================================================ FILE: third_party/cosmo/2/inet_ntop_test.com.dbg.gz.sha256 ================================================ 7949648699cb2eaaaaa3b438a2b6f7fe9338e16175356e46bd9128bd6931983e *third_party/cosmo/2/inet_ntop_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/inet_ntop_test.com.gz.sha256 ================================================ 6022f20a32c694bad9e1e573fbac7a0dfefff75fcf5fa9d3d3671075d0e9d770 *third_party/cosmo/2/inet_ntop_test.com.gz ================================================ FILE: third_party/cosmo/2/inet_pton_test.com.dbg.gz.sha256 ================================================ 8151177fc7a6c617a7c3a55075c1818c85cfefa6c70feabbde41320c3d7812c7 *third_party/cosmo/2/inet_pton_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/inet_pton_test.com.gz.sha256 ================================================ 7a0277f80fba647ffe7f701d898c310968812fdfe6e74d1ae091e1850ca9473e *third_party/cosmo/2/inet_pton_test.com.gz ================================================ FILE: third_party/cosmo/2/integralarithmetic_test.com.dbg.gz.sha256 ================================================ 867d6043fed687e653d198db1b1df2d283b8dda535849be017f31d0d932e6764 *third_party/cosmo/2/integralarithmetic_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/integralarithmetic_test.com.gz.sha256 ================================================ 0389b021ac4acc3241026d52ecb582c9f4826e85e2a1a31ff4c08049dea435d3 *third_party/cosmo/2/integralarithmetic_test.com.gz ================================================ FILE: third_party/cosmo/2/interner_test.com.dbg.gz.sha256 ================================================ 95b3c454d317a71ba34c62891c9601087df6618dfbc855418a716bd2b25014e6 *third_party/cosmo/2/interner_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/interner_test.com.gz.sha256 ================================================ 4797298b2e3ac6ff2e7038400a3408e3209c4aba7ac1ffc16a3307128edba26f *third_party/cosmo/2/interner_test.com.gz ================================================ FILE: third_party/cosmo/2/inv3_test.com.dbg.gz.sha256 ================================================ f1b752e7051ab20d96eaed05ab6ba62da5bbebb5358358708a8b1cfa18c95165 *third_party/cosmo/2/inv3_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/inv3_test.com.gz.sha256 ================================================ f645f820ad0e5e4e3be73d722668989bf91f0d3817af26418bfee9f5a971a01f *third_party/cosmo/2/inv3_test.com.gz ================================================ FILE: third_party/cosmo/2/ioctl_siocgifconf_test.com.dbg.gz.sha256 ================================================ 533f7ea23fe63ee0a0cd25cf62bdc3de8a3c7b1f6591e8b44ed5c3242fb6e880 *third_party/cosmo/2/ioctl_siocgifconf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ioctl_siocgifconf_test.com.gz.sha256 ================================================ 17045d46d14021c07ba95c38ed6e6b03632fbe72df88b2b48f2e4e8748295890 *third_party/cosmo/2/ioctl_siocgifconf_test.com.gz ================================================ FILE: third_party/cosmo/2/iovs_test.com.dbg.gz.sha256 ================================================ 350b508db0aca82e7ded5b7beb3485a018395996786f96b154663b370e74761a *third_party/cosmo/2/iovs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/iovs_test.com.gz.sha256 ================================================ 3fdc24276fac6c7a3b57ef6814bec2bd588c02f4fcaf8f64ca52438626150672 *third_party/cosmo/2/iovs_test.com.gz ================================================ FILE: third_party/cosmo/2/isacceptablehost_test.com.dbg.gz.sha256 ================================================ 6d644607360a46d2a06d9f502e504c52c36370be876e163d7c8cc64da524eaa0 *third_party/cosmo/2/isacceptablehost_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/isacceptablehost_test.com.gz.sha256 ================================================ be2a97ff6880d64931057db43378208894a701bf1ac3b5f767de48f88c8193b2 *third_party/cosmo/2/isacceptablehost_test.com.gz ================================================ FILE: third_party/cosmo/2/isacceptablepath_test.com.dbg.gz.sha256 ================================================ ab2c6b5478497e1d048953b7966462964efe008fceb412e18dec7531be69a306 *third_party/cosmo/2/isacceptablepath_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/isacceptablepath_test.com.gz.sha256 ================================================ 0b369bca7f4af28823f94fe4d3e09c05ae711a4862c4801f1bf1d7a08fd9fa23 *third_party/cosmo/2/isacceptablepath_test.com.gz ================================================ FILE: third_party/cosmo/2/ismimetype_test.com.dbg.gz.sha256 ================================================ 5d066b150415da1ac1ee3d0d076ad3ba88a02f51c815710523cb8fa2cab01a4d *third_party/cosmo/2/ismimetype_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ismimetype_test.com.gz.sha256 ================================================ 3f8753a2612756b72a55f661fde363804c541b51e24c1f2d066da945e5586ca9 *third_party/cosmo/2/ismimetype_test.com.gz ================================================ FILE: third_party/cosmo/2/isnocompressext_test.com.dbg.gz.sha256 ================================================ 32f462b319f4681679cb097e570d95cc81a3871ab363bec5cd48f8a4c761b905 *third_party/cosmo/2/isnocompressext_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/isnocompressext_test.com.gz.sha256 ================================================ 820d206bda17106fe90115498a47e6ecc6188814ea00378a6debf8489fe98457 *third_party/cosmo/2/isnocompressext_test.com.gz ================================================ FILE: third_party/cosmo/2/iso8601_test.com.dbg.gz.sha256 ================================================ 7b3e9eef4c51fc44f2bf8fc178babfe4975ba7a18e994152801ff939e9c0057a *third_party/cosmo/2/iso8601_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/iso8601_test.com.gz.sha256 ================================================ 8841581f8bdc43419a0b525a703e05fd043a1d12d5649eeac10a20c335870f9d *third_party/cosmo/2/iso8601_test.com.gz ================================================ FILE: third_party/cosmo/2/isreasonablepath_test.com.dbg.gz.sha256 ================================================ ddb3353b74b5ee953a94b4512bda09b56309ecc245b772f1d038f4b5d56654de *third_party/cosmo/2/isreasonablepath_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/isreasonablepath_test.com.gz.sha256 ================================================ fe5aae804528c2d33717f28e0d6ff857c7b70f912fe2e4842ff5e39f79ce2fb5 *third_party/cosmo/2/isreasonablepath_test.com.gz ================================================ FILE: third_party/cosmo/2/isutf8_test.com.dbg.gz.sha256 ================================================ ea4c084d17065493596f8033bfc87be5266dba8a8fd70132bb3939bbf18d03a8 *third_party/cosmo/2/isutf8_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/isutf8_test.com.gz.sha256 ================================================ 5edc7cf6f594143a438501b6b4a3bcaf33ca4d585e91d2d4d739a0364761352a *third_party/cosmo/2/isutf8_test.com.gz ================================================ FILE: third_party/cosmo/2/itoa64radix16_test.com.dbg.gz.sha256 ================================================ a373bab161ede9da4151603ae88b14822f819c60948117b66ba01f6a33c4b746 *third_party/cosmo/2/itoa64radix16_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/itoa64radix16_test.com.gz.sha256 ================================================ 0193c55eefc72f73095deae3b61e3a027119785183d49aa3b2aae428a92fb6dc *third_party/cosmo/2/itoa64radix16_test.com.gz ================================================ FILE: third_party/cosmo/2/itsatrap_test.com.dbg.gz.sha256 ================================================ 11d5deec3312269773209f65221ed0752b33694fb364224f37dae9b099a7d346 *third_party/cosmo/2/itsatrap_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/itsatrap_test.com.gz.sha256 ================================================ 76484104a536fdd196fc154338ca2051455232799167acf05bac5c547d18b5d4 *third_party/cosmo/2/itsatrap_test.com.gz ================================================ FILE: third_party/cosmo/2/javadown_test.com.dbg.gz.sha256 ================================================ a60200457d52a89baa14aec2c0659b32d1e4cd27bc62355209e2aa728bc670fd *third_party/cosmo/2/javadown_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/javadown_test.com.gz.sha256 ================================================ 72190341d4d020134c769c5475220da47e8d93dc34f2524c691f4e554b7f448c *third_party/cosmo/2/javadown_test.com.gz ================================================ FILE: third_party/cosmo/2/joinpaths_test.com.dbg.gz.sha256 ================================================ 23e74d7785a9aa5ec3f40500fc9f504eb33546f8f3d82e46191005ca4fad535c *third_party/cosmo/2/joinpaths_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/joinpaths_test.com.gz.sha256 ================================================ b420712bc3eb56ef55b53f901d73fe16cc57bde4ab310512f5a206be382cca68 *third_party/cosmo/2/joinpaths_test.com.gz ================================================ FILE: third_party/cosmo/2/joinstrlist_test.com.dbg.gz.sha256 ================================================ 87241442bbb3911206d63f591964f4965af0d728cf3cb30c7a0c95cd20f87033 *third_party/cosmo/2/joinstrlist_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/joinstrlist_test.com.gz.sha256 ================================================ 9272af11b89bb6fe26596d3af56f788fa347225632f103172d6505f8a330f2ea *third_party/cosmo/2/joinstrlist_test.com.gz ================================================ FILE: third_party/cosmo/2/kbase36_test.com.dbg.gz.sha256 ================================================ 41ecc70c1a6f6ca328682f6f83563e31628ac7ed5d963dd7b25bb66935530a47 *third_party/cosmo/2/kbase36_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/kbase36_test.com.gz.sha256 ================================================ 5763a473c77a5fe8964da533b24769e4ccd59c896b0f9ec2a0c5cdc744ae61ac *third_party/cosmo/2/kbase36_test.com.gz ================================================ FILE: third_party/cosmo/2/kcp437_test.com.dbg.gz.sha256 ================================================ 7da2b2363c69074d79a1adeec70165ddd5b57ecbe962da088f87dbc9c783b968 *third_party/cosmo/2/kcp437_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/kcp437_test.com.gz.sha256 ================================================ 362e283d0bb91360351661839d768e64537050ccb5a7622af210f13f7986f65c *third_party/cosmo/2/kcp437_test.com.gz ================================================ FILE: third_party/cosmo/2/kprintf_test.com.dbg.gz.sha256 ================================================ e6582254e7fc253d655537709801055d6a4d9b11ac235605ff27e5e791688e27 *third_party/cosmo/2/kprintf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/kprintf_test.com.gz.sha256 ================================================ d8ec72756ef85677fc9465286cc4e8bbc810a938188dbd62df67783f9bc7980a *third_party/cosmo/2/kprintf_test.com.gz ================================================ FILE: third_party/cosmo/2/ldexp_test.com.dbg.gz.sha256 ================================================ a717217f384fa3c76244fd1b4ae40b8a76e7102a1786db3abd0005d013aa2d75 *third_party/cosmo/2/ldexp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ldexp_test.com.gz.sha256 ================================================ d094242874639a913f77037307c85b2a58b89b9cba336fcd7f5ea7c584ab5321 *third_party/cosmo/2/ldexp_test.com.gz ================================================ FILE: third_party/cosmo/2/lengthuint64_test.com.dbg.gz.sha256 ================================================ 87414910ee5055d568149734cfd090efcf9d18d3cf669f6bfc96bd0354a16bbb *third_party/cosmo/2/lengthuint64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lengthuint64_test.com.gz.sha256 ================================================ d1e49a3a849e26a08f2136c751f2f08a8cf9fba0a9dab83e4d7ae233aedf8064 *third_party/cosmo/2/lengthuint64_test.com.gz ================================================ FILE: third_party/cosmo/2/lock2_test.com.dbg.gz.sha256 ================================================ b687ed9f27318fbcce2660e5265ba59870d6777d82dc1ff428edc7b89209095a *third_party/cosmo/2/lock2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lock2_test.com.gz.sha256 ================================================ fed1324f63894a853f2a2d42f776426dc843eec9b498a22d26197646dd72b14f *third_party/cosmo/2/lock2_test.com.gz ================================================ FILE: third_party/cosmo/2/lock_ofd_test.com.dbg.gz.sha256 ================================================ 7697adb980b37dc473b5dc4d52938fc0b2b3621cfbf72c8861cf0b05e292d341 *third_party/cosmo/2/lock_ofd_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lock_ofd_test.com.gz.sha256 ================================================ 23a84487bcaf66491fcbd6940e8d902550e5bb1a9998e9c7633f362332ad7f88 *third_party/cosmo/2/lock_ofd_test.com.gz ================================================ FILE: third_party/cosmo/2/lock_test.com.dbg.gz.sha256 ================================================ 5773f35d0a40e615c325a714db5faa664860d97b44c6b0b2822f51abcab062de *third_party/cosmo/2/lock_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lock_test.com.gz.sha256 ================================================ 861de42ba4e1aada689b9243c202dd1c95f2079f02d958050afd2338c529ced5 *third_party/cosmo/2/lock_test.com.gz ================================================ FILE: third_party/cosmo/2/lockipc_test.com.dbg.gz.sha256 ================================================ 681cbccc5a938ef9ed5039d739768d31c8727e155317593d10ec0b119126aa8f *third_party/cosmo/2/lockipc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lockipc_test.com.gz.sha256 ================================================ df1d5582d9858cf5d1cd71e46ee4ad45b03540c3feb0181d2f349822e5081427 *third_party/cosmo/2/lockipc_test.com.gz ================================================ FILE: third_party/cosmo/2/lockscale_test.com.dbg.gz.sha256 ================================================ 7e0cdf8046f3081ad1077387227e49eee564e3d5daf91388f29d634796044755 *third_party/cosmo/2/lockscale_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lockscale_test.com.gz.sha256 ================================================ f07569afadc793271d9dcbce70252708699f44e61d96fda24bb9179bc0d10b47 *third_party/cosmo/2/lockscale_test.com.gz ================================================ FILE: third_party/cosmo/2/log10_test.com.dbg.gz.sha256 ================================================ 5a88f623901ef09283a9560fd2cce11db417e93e6d014e0ccd87606bf62bb4b9 *third_party/cosmo/2/log10_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/log10_test.com.gz.sha256 ================================================ d647e2ad8a3f162ed600b1a2f63e2b2f3a86219d2558e569d38c8784f3ab6d63 *third_party/cosmo/2/log10_test.com.gz ================================================ FILE: third_party/cosmo/2/log1p_test.com.dbg.gz.sha256 ================================================ 7ece073d8c261ca4edebf4b6b5fbacd2c3b6ce99024ce1e3a2d13fe3169ba2c1 *third_party/cosmo/2/log1p_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/log1p_test.com.gz.sha256 ================================================ a775dac605b0efe1855a849fa7d2c4468ffb09af53876805929fb865e574c4b7 *third_party/cosmo/2/log1p_test.com.gz ================================================ FILE: third_party/cosmo/2/log2_test.com.dbg.gz.sha256 ================================================ 9b172efa27854d6fae1789bda147d7091356fcfd15310d25635661217b0dd4c1 *third_party/cosmo/2/log2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/log2_test.com.gz.sha256 ================================================ 21cf424e3e382df15a6c64b66335d7233674645536dd5d8d338ee6784c2eab19 *third_party/cosmo/2/log2_test.com.gz ================================================ FILE: third_party/cosmo/2/log_test.com.dbg.gz.sha256 ================================================ 121232703186c42eccace93d2deca105dacce7ad7fe0e7c4e4e9186b8015cadc *third_party/cosmo/2/log_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/log_test.com.gz.sha256 ================================================ 7603da056abe74d4c317bbc6832d040f391eec95732f637038411ac0ed4cdd8b *third_party/cosmo/2/log_test.com.gz ================================================ FILE: third_party/cosmo/2/logb_test.com.dbg.gz.sha256 ================================================ 7d1cc2182377196dcc5d2e2664f5a99c0088aa71dbc7878a01e53570812e815d *third_party/cosmo/2/logb_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/logb_test.com.gz.sha256 ================================================ 424de909d19f661c4dc3d69e08a81fac76000516cb8639f4692477ae3419030c *third_party/cosmo/2/logb_test.com.gz ================================================ FILE: third_party/cosmo/2/longsort_test.com.dbg.gz.sha256 ================================================ 00c879a9b8da282af5a984aa3360fff0d2392a2946dd6640f5c1e4708da62464 *third_party/cosmo/2/longsort_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/longsort_test.com.gz.sha256 ================================================ 4b2882316d3c4450595a868adaadc5c5480ea803589fa377aa5d252108c70624 *third_party/cosmo/2/longsort_test.com.gz ================================================ FILE: third_party/cosmo/2/lseek_test.com.dbg.gz.sha256 ================================================ f72dd55bfe8b282ad371865c6818fc12777f36adc7444b2d386aad9cc9550dcf *third_party/cosmo/2/lseek_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lseek_test.com.gz.sha256 ================================================ c51bc452e175613673c98a1cf4838e0979c1fce894fa761becceea9f76886358 *third_party/cosmo/2/lseek_test.com.gz ================================================ FILE: third_party/cosmo/2/lz4decode_test.com.dbg.gz.sha256 ================================================ 49983f4f0c48fb85d074201f4b07cbf8c63b3e059cf72331fbebe3b3eb443b43 *third_party/cosmo/2/lz4decode_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/lz4decode_test.com.gz.sha256 ================================================ 6481095b0137cb5c6d91f1c0065bddfbe6a3c9167b1070aea259f4a883cc8f30 *third_party/cosmo/2/lz4decode_test.com.gz ================================================ FILE: third_party/cosmo/2/machine_test.com.dbg.gz.sha256 ================================================ 4437d59fdefbcf0e2d17be65cf44ce76c1c152a6cc09a2dc798ecf29eac5993d *third_party/cosmo/2/machine_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/machine_test.com.gz.sha256 ================================================ f96971189fe9f88cc543a1471a9fe615351f2d4ab13b89cfbaeeef75ba1cf1f8 *third_party/cosmo/2/machine_test.com.gz ================================================ FILE: third_party/cosmo/2/magikarp_test.com.dbg.gz.sha256 ================================================ 8c717f4bb995e57a3e89909f2757d8d86324eda3d20e5d48bb29e77e83d54e10 *third_party/cosmo/2/magikarp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/magikarp_test.com.gz.sha256 ================================================ fba0d3cca5c154c039f5e6d76e07af4368a01fa48ce4c9f6ade1caeebe738219 *third_party/cosmo/2/magikarp_test.com.gz ================================================ FILE: third_party/cosmo/2/makedirs_test.com.dbg.gz.sha256 ================================================ 8028ddbe9ca4fe669bb9a0d5a5c999b608de64f1a3d721788752ef985e0b60e6 *third_party/cosmo/2/makedirs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/makedirs_test.com.gz.sha256 ================================================ 94c3c37ddeb782140605f6824f5d9d8300e4f1ee78f8d40b93a7cd4217bbd3c8 *third_party/cosmo/2/makedirs_test.com.gz ================================================ FILE: third_party/cosmo/2/malloc_test.com.dbg.gz.sha256 ================================================ 03fc7c2b5ae1416f85797a00b135d2838ecbb8b5cb1cdd9a232aff0e1e079207 *third_party/cosmo/2/malloc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/malloc_test.com.gz.sha256 ================================================ badf632181fd03358c5ceb2a8c28bca8bf0ff2482530beb789fb754eb481b1ac *third_party/cosmo/2/malloc_test.com.gz ================================================ FILE: third_party/cosmo/2/mbedtls_test.com.dbg.gz.sha256 ================================================ 9067281f5018763113d73e09e252380f4d07b1e603217a17f7b933566ee9cd66 *third_party/cosmo/2/mbedtls_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mbedtls_test.com.gz.sha256 ================================================ ce50f28aa9d8221940a16b338f18866c84816c6285de8167881f0962faab2fc4 *third_party/cosmo/2/mbedtls_test.com.gz ================================================ FILE: third_party/cosmo/2/measureentropy_test.com.dbg.gz.sha256 ================================================ 93cec08eeda7a3287a803657350fbfcc1d1e1d4a0543e6bf18e30e40bcc501b3 *third_party/cosmo/2/measureentropy_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/measureentropy_test.com.gz.sha256 ================================================ 25f88fbc25c3ae7c7cf4338abb5f46a25bbd9f3f2c91a1b7e90b722b42c0f4d7 *third_party/cosmo/2/measureentropy_test.com.gz ================================================ FILE: third_party/cosmo/2/memcasecmp_test.com.dbg.gz.sha256 ================================================ 3d21d6d3a464592ebdfec6f5f083f24e7272261399b105d4d0744117b31f7951 *third_party/cosmo/2/memcasecmp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memcasecmp_test.com.gz.sha256 ================================================ c6fc5ec55b7eeb3864520e27bb2f16f1ba10262e3de9e721be5f824aed8e8f39 *third_party/cosmo/2/memcasecmp_test.com.gz ================================================ FILE: third_party/cosmo/2/memccpy_test.com.dbg.gz.sha256 ================================================ 178771c7b5d4b579c6d420fdaa083165fab7e8eba8d434df40905773c2f488f4 *third_party/cosmo/2/memccpy_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memccpy_test.com.gz.sha256 ================================================ 14550c7423fb6dce05c023ad588cbe667a9a1fe0ef15d302899c7ee053c16a8e *third_party/cosmo/2/memccpy_test.com.gz ================================================ FILE: third_party/cosmo/2/memcmp_test.com.dbg.gz.sha256 ================================================ ca3207db06158b15c76d208e735cbc7d5d6bf3f349d65b02763bcb787a5c4504 *third_party/cosmo/2/memcmp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memcmp_test.com.gz.sha256 ================================================ a79f0e95f350b9a5ac13c3e807fe159cf52396d779ae9bc758f6eca8dbeaa884 *third_party/cosmo/2/memcmp_test.com.gz ================================================ FILE: third_party/cosmo/2/memcpy_test.com.dbg.gz.sha256 ================================================ 678e68f2b86afe19a84f393c1483224c5e26ac8bbb8d29e076e1c5aafbf665b4 *third_party/cosmo/2/memcpy_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memcpy_test.com.gz.sha256 ================================================ 0d9f555ec0c0939b4595eb3ff7ca6676d9edacc0f6d452b83cc5032f37c7f132 *third_party/cosmo/2/memcpy_test.com.gz ================================================ FILE: third_party/cosmo/2/memfrob_test.com.dbg.gz.sha256 ================================================ 1098f7d4ddc2530f58e8a3ba7371dd8e342123072011eec4b9bcd2e24d38d6c6 *third_party/cosmo/2/memfrob_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memfrob_test.com.gz.sha256 ================================================ d27a70f71fe85400f6c2b6710a973a6d5df6de64f4de3afea4d24fc6d0aea246 *third_party/cosmo/2/memfrob_test.com.gz ================================================ FILE: third_party/cosmo/2/memmem_test.com.dbg.gz.sha256 ================================================ feac23ab6872dcafeb252ff46fb0fc9809e162e3682829f1a64f2291a034d0a9 *third_party/cosmo/2/memmem_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memmem_test.com.gz.sha256 ================================================ 75a04036d701af907b85778ff3a84408c459824237ae5e4ccd609c2299abbe0e *third_party/cosmo/2/memmem_test.com.gz ================================================ FILE: third_party/cosmo/2/memmove_test.com.dbg.gz.sha256 ================================================ bf46ca95bb4657f6a4d81618d79f3f93761a8366bde8ab63ebf918c751a157ff *third_party/cosmo/2/memmove_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memmove_test.com.gz.sha256 ================================================ 7beef583ced89f16bbb8a1dc9525417302a1e1cb3c9589177d8519a6733fe48d *third_party/cosmo/2/memmove_test.com.gz ================================================ FILE: third_party/cosmo/2/memory_test.com.dbg.gz.sha256 ================================================ 4b376d59ee97349cfe43a87b488f7138ced4e816421efedecea9826d16932b87 *third_party/cosmo/2/memory_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memory_test.com.gz.sha256 ================================================ f8a37334f2dfeca797e1ab76d0a94193d8a6934baec7c0d388794d33cd757fc4 *third_party/cosmo/2/memory_test.com.gz ================================================ FILE: third_party/cosmo/2/memrchr16_test.com.dbg.gz.sha256 ================================================ 24cb50cf061392ac98be278cdd0da4fe6592dbe1a38e140f06e7b13a68d2e350 *third_party/cosmo/2/memrchr16_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memrchr16_test.com.gz.sha256 ================================================ 078d426dfcab8964f1c3d0c0e3a40ddfeef9b6546e566639ab287050e4e19772 *third_party/cosmo/2/memrchr16_test.com.gz ================================================ FILE: third_party/cosmo/2/memrchr_test.com.dbg.gz.sha256 ================================================ e49645a6a0f2bad1d02693850ebdbd7a3113bae16a0dcb234c9aefec8e5af818 *third_party/cosmo/2/memrchr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memrchr_test.com.gz.sha256 ================================================ 0cd14f467c1a27d77c0dd99d6a028c2dbd686b2959f57b269ef6c06ffe5b35c9 *third_party/cosmo/2/memrchr_test.com.gz ================================================ FILE: third_party/cosmo/2/memset_test.com.dbg.gz.sha256 ================================================ 06ca14383b19c4435a54bd6bd32ade0175f0863cc94fd9bb338aa8206b64c6db *third_party/cosmo/2/memset_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memset_test.com.gz.sha256 ================================================ 23f3abb9f28959a66167b094aab97027e73a94068c41f149552c6441e6967b52 *third_party/cosmo/2/memset_test.com.gz ================================================ FILE: third_party/cosmo/2/memtrack_test.com.dbg.gz.sha256 ================================================ ecdf844e6fb63056b53c51fd6269b70c74e03d25a00d7a45045eee40e449d995 *third_party/cosmo/2/memtrack_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/memtrack_test.com.gz.sha256 ================================================ fe7d18b2ddcccbc9adb299c2370cc7ba4d1a560359f21ee77ef0ea87eaa4ee81 *third_party/cosmo/2/memtrack_test.com.gz ================================================ FILE: third_party/cosmo/2/mkdir_test.com.dbg.gz.sha256 ================================================ 23ba648375433aee0d8bfed50ebb426372eb962f8cfa5183240864243bd05427 *third_party/cosmo/2/mkdir_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mkdir_test.com.gz.sha256 ================================================ 5c4fbcad5bf4a9ccebcf4caf824b5db7dab47a201c7dd5ffb7ee10a98f27b0c5 *third_party/cosmo/2/mkdir_test.com.gz ================================================ FILE: third_party/cosmo/2/mkntcmdline_test.com.dbg.gz.sha256 ================================================ 6dcae375bb9be30c8c2f868b2797ac50e24298a9ed7e06c0c16a6165c60285b6 *third_party/cosmo/2/mkntcmdline_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mkntcmdline_test.com.gz.sha256 ================================================ 970485d6fb9200a4d7f0152cd691c30535846f7697270721757de7a9b7e43ec2 *third_party/cosmo/2/mkntcmdline_test.com.gz ================================================ FILE: third_party/cosmo/2/mkntenvblock_test.com.dbg.gz.sha256 ================================================ 28f1c17d098a9607eb65d1b7b9d109b98002d461b3385150c3566a1d208ddf62 *third_party/cosmo/2/mkntenvblock_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mkntenvblock_test.com.gz.sha256 ================================================ 69404f142a9907868f670953aa542e394ecb11fd278b92ae7cd5f926ecb793a0 *third_party/cosmo/2/mkntenvblock_test.com.gz ================================================ FILE: third_party/cosmo/2/mkntpath_test.com.dbg.gz.sha256 ================================================ 41670f81aed64cd9c44e5c5ad76f062ee63fbd59486ac63a6c47f27b28b9455c *third_party/cosmo/2/mkntpath_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mkntpath_test.com.gz.sha256 ================================================ a76058ffb2162c25d8eaa777cff51a49a04be116b7211d659db2a336083fa565 *third_party/cosmo/2/mkntpath_test.com.gz ================================================ FILE: third_party/cosmo/2/mkostempsm_test.com.dbg.gz.sha256 ================================================ cfd77f94f0b019badbf12c1643444afe7cdc7eafad38fc452316e452a2266055 *third_party/cosmo/2/mkostempsm_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mkostempsm_test.com.gz.sha256 ================================================ 901d79ceffd97e0416a32af3ac075461548eb599d925f2fc4d16f4c4987259c4 *third_party/cosmo/2/mkostempsm_test.com.gz ================================================ FILE: third_party/cosmo/2/mmap_test.com.dbg.gz.sha256 ================================================ 24320053d253f2cb5adbcd73d12642e095d5cbee58bb7f139ce2fdd32614e0f4 *third_party/cosmo/2/mmap_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mmap_test.com.gz.sha256 ================================================ b05d3395cf82c6a714644400b07de30a2a67d7bcee5f0a4d2f95b27a964be993 *third_party/cosmo/2/mmap_test.com.gz ================================================ FILE: third_party/cosmo/2/modrm_test.com.dbg.gz.sha256 ================================================ fc573db4b44ccbb58971728a3881a9e9c78f66fae4eadf149e1f691507f68aaf *third_party/cosmo/2/modrm_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/modrm_test.com.gz.sha256 ================================================ 5e966fb3918fe6d2eaa4ca6fa37e31b445bc3d5c7c39c2826afed406388d5b8d *third_party/cosmo/2/modrm_test.com.gz ================================================ FILE: third_party/cosmo/2/morton_test.com.dbg.gz.sha256 ================================================ bf7dd317f3afcbde44c996627fac77c5ec055287ca790f30030075f93e2a3cad *third_party/cosmo/2/morton_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/morton_test.com.gz.sha256 ================================================ 160c688772dccf737c449983ca006509c407a78994a9e1d7b1ad1bda9f244e68 *third_party/cosmo/2/morton_test.com.gz ================================================ FILE: third_party/cosmo/2/mprotect_test.com.dbg.gz.sha256 ================================================ b1aea0a56e12c55d0d297c5f3a1c070a5b5804c1fbde765679cd3abde1310299 *third_party/cosmo/2/mprotect_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mprotect_test.com.gz.sha256 ================================================ 887951a3940d5f81be1447723a294dff6836912acbde3360674c2675d73bec4f *third_party/cosmo/2/mprotect_test.com.gz ================================================ FILE: third_party/cosmo/2/mt19937_test.com.dbg.gz.sha256 ================================================ a1dbcaf13f3085c2214c9c67445886ad030113863f6f030c0f30bea80dc9f33f *third_party/cosmo/2/mt19937_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mt19937_test.com.gz.sha256 ================================================ cc3b746f052378521bfe0a549bd8863102685eca428f18f5716d3d7876806176 *third_party/cosmo/2/mt19937_test.com.gz ================================================ FILE: third_party/cosmo/2/mu_starvation_test.com.dbg.gz.sha256 ================================================ 0c8a07a0cff141083a3b65e3363e6487360f67563fe00d46ef189c9fcb567428 *third_party/cosmo/2/mu_starvation_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mu_starvation_test.com.gz.sha256 ================================================ d6609b53f9cc34a34d759a2a3c89b76bc186ac22d6dcc465b0163230fa6265bd *third_party/cosmo/2/mu_starvation_test.com.gz ================================================ FILE: third_party/cosmo/2/mu_test.com.dbg.gz.sha256 ================================================ f9f56b6a98ccc723ad85b462eaa44f57e271679c3383c7569839121f310b21d1 *third_party/cosmo/2/mu_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mu_test.com.gz.sha256 ================================================ 63ea8c6c369a5f369213eb1dfabbd1e4ff7502601af698b8c960b5bf57ff5a27 *third_party/cosmo/2/mu_test.com.gz ================================================ FILE: third_party/cosmo/2/mu_wait_example_test.com.dbg.gz.sha256 ================================================ 2d2c16ad4232c57fae9c61f92eae71ff8e3a95d18dd86e0f8cc3d7cb28bcfd91 *third_party/cosmo/2/mu_wait_example_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mu_wait_example_test.com.gz.sha256 ================================================ 2f42b030167daa9a289eb4eb59a491d8858cdee0923d2a944e02a98319e76bad *third_party/cosmo/2/mu_wait_example_test.com.gz ================================================ FILE: third_party/cosmo/2/mu_wait_test.com.dbg.gz.sha256 ================================================ e363510691ef19c4f470dc763f2ddbb64b82291b40b9879d7ade45afd82ea591 *third_party/cosmo/2/mu_wait_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mu_wait_test.com.gz.sha256 ================================================ e287ef4069462f445d41ade63e743ebfcc94dd033ca5792c606d7602b5a099d0 *third_party/cosmo/2/mu_wait_test.com.gz ================================================ FILE: third_party/cosmo/2/mulaw_test.com.dbg.gz.sha256 ================================================ 2117d369da1ceae17ea9833d8e0e7b3a12f54b825567dd78e66f990c1738f88f *third_party/cosmo/2/mulaw_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/mulaw_test.com.gz.sha256 ================================================ 8f2e08d87dc5e7ad697f8af42bcdb644f9ee06a1c6dad3d3b5cf8d81c9812ec9 *third_party/cosmo/2/mulaw_test.com.gz ================================================ FILE: third_party/cosmo/2/nanosleep_test.com.dbg.gz.sha256 ================================================ 6fe7a594c63e74113eca70602d42cb5f49bfe46706133c0d675940ca27907069 *third_party/cosmo/2/nanosleep_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/nanosleep_test.com.gz.sha256 ================================================ 5421b2ba4d696c0da2ece1cefaee111c7bbe593da72eaa8b60bbc436949ceb57 *third_party/cosmo/2/nanosleep_test.com.gz ================================================ FILE: third_party/cosmo/2/nointernet_test.com.dbg.gz.sha256 ================================================ 527922ebf5dbde376e87aa746aeb744f541a25a40aa0770074b4ab4af21ea72c *third_party/cosmo/2/nointernet_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/nointernet_test.com.gz.sha256 ================================================ 40a24431c60b7141b79d09c10b04212deaf01a55ee07ac4a47150aabb4cb96d4 *third_party/cosmo/2/nointernet_test.com.gz ================================================ FILE: third_party/cosmo/2/note_test.com.dbg.gz.sha256 ================================================ 22531925190f88f7675c19b8a1bba52cc39234f9476c1feb716a1c3b6e5648e7 *third_party/cosmo/2/note_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/note_test.com.gz.sha256 ================================================ 9f9666e9c5d2cf64ca27e1eafa9a48eb966b594f3ae27d39b6a0d74d64d748b1 *third_party/cosmo/2/note_test.com.gz ================================================ FILE: third_party/cosmo/2/nsync_test.com.dbg.gz.sha256 ================================================ 3aef603bbcbf6a22da89c6f4dd6e52e154fe4acb566a34dc7b6e18456853ddba *third_party/cosmo/2/nsync_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/nsync_test.com.gz.sha256 ================================================ 723dd2b96eca1f635cf44871402f135017c5650f8bc0440df8804a65a7401cd4 *third_party/cosmo/2/nsync_test.com.gz ================================================ FILE: third_party/cosmo/2/omg_test.com.dbg.gz.sha256 ================================================ feb631fcf7458db82e540e5466fad83e3a93a1d77f8adcb986d4b3f1f7e21e9f *third_party/cosmo/2/omg_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/omg_test.com.gz.sha256 ================================================ 10a3c29664bdd636510d3e61d213b9d341477ca31f48e192ac4f63677a7fcb88 *third_party/cosmo/2/omg_test.com.gz ================================================ FILE: third_party/cosmo/2/once_test.com.dbg.gz.sha256 ================================================ fd5e11ce578626211d4495c74901f99faa4429cefd0db0875aa302c855c36342 *third_party/cosmo/2/once_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/once_test.com.gz.sha256 ================================================ 1b217834a7bc4348baf7791bcd68469146cdeab8467286dd94ca8413e151ef72 *third_party/cosmo/2/once_test.com.gz ================================================ FILE: third_party/cosmo/2/open_test.com.dbg.gz.sha256 ================================================ 5cbf1d5be4a126b8c1a06b6fa5f2364a1a66d9633a8e4b9097e573288afeb891 *third_party/cosmo/2/open_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/open_test.com.gz.sha256 ================================================ 34d836a1b8378f4e190dd4505d8ec1bf416a3c451dd89733e16312104e6df042 *third_party/cosmo/2/open_test.com.gz ================================================ FILE: third_party/cosmo/2/openbsd_test.com.dbg.gz.sha256 ================================================ 4fe25c901a408a337d62719811ce1bd4e9c2b2397fed1abbefb7fae19d0dd26f *third_party/cosmo/2/openbsd_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/openbsd_test.com.gz.sha256 ================================================ f34302823886055024e0189241b8ffb29be17574c40235b42b2df93d244fba51 *third_party/cosmo/2/openbsd_test.com.gz ================================================ FILE: third_party/cosmo/2/palandprintf_test.com.dbg.gz.sha256 ================================================ 464976f25befa044fb89a9e0bf683de0d010b8eff52a9e47acecee3008708972 *third_party/cosmo/2/palandprintf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/palandprintf_test.com.gz.sha256 ================================================ b64b567c4b546325342688ae6607d1ef8d3101422c91b99c33ac9176407d8240 *third_party/cosmo/2/palandprintf_test.com.gz ================================================ FILE: third_party/cosmo/2/palignr_test.com.dbg.gz.sha256 ================================================ 6276fd7147e9a03b52d62e85a4c87afa5d0505a72c885cd708072f8c7b1c2801 *third_party/cosmo/2/palignr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/palignr_test.com.gz.sha256 ================================================ b52fcf7facaad60cd19f24d8f7e66110fe7ec67ec92b0c5191a8df0f6765eec8 *third_party/cosmo/2/palignr_test.com.gz ================================================ FILE: third_party/cosmo/2/parsecidr_test.com.dbg.gz.sha256 ================================================ e98015908d15524fafe10e85d815845a1e703b03fed6066084bb5112edd789df *third_party/cosmo/2/parsecidr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parsecidr_test.com.gz.sha256 ================================================ fbb174a638b1122a5e08a6238d159a96864ea87ac5e1cd4a1f5cc3ca3adf9f88 *third_party/cosmo/2/parsecidr_test.com.gz ================================================ FILE: third_party/cosmo/2/parsecontentlength_test.com.dbg.gz.sha256 ================================================ 4110fa235a840dde9780ba56bd6231e0d5f4429158ddf8f25a0413cee2311946 *third_party/cosmo/2/parsecontentlength_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parsecontentlength_test.com.gz.sha256 ================================================ bb63e29bb6d3da4f24d51766b7a0b4b9c47212d23427514f4c514ecb52d14915 *third_party/cosmo/2/parsecontentlength_test.com.gz ================================================ FILE: third_party/cosmo/2/parseforwarded_test.com.dbg.gz.sha256 ================================================ 0483d5c584beb743eb4ab0f6915c839cb9c03c7a337d7e3af4457195c8a50e18 *third_party/cosmo/2/parseforwarded_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parseforwarded_test.com.gz.sha256 ================================================ 687f0394a718e12469922266f046c7c90b56784f69eafeb2e0e04a6f66338377 *third_party/cosmo/2/parseforwarded_test.com.gz ================================================ FILE: third_party/cosmo/2/parsehoststxt_test.com.dbg.gz.sha256 ================================================ c00df83837b663674e98809b42c450ab27da1b74320382d81faee42fc3105bee *third_party/cosmo/2/parsehoststxt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parsehoststxt_test.com.gz.sha256 ================================================ 6707b83867b3d2c6dc556a0d20f2f2056ec9248f3e950dceb139b6bb0c831950 *third_party/cosmo/2/parsehoststxt_test.com.gz ================================================ FILE: third_party/cosmo/2/parsehttpdatetime_test.com.dbg.gz.sha256 ================================================ 3440e0fd7a7073d841aeb5937385b12f2f9ca89e065fb5daabf3f397eeecf0bf *third_party/cosmo/2/parsehttpdatetime_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parsehttpdatetime_test.com.gz.sha256 ================================================ ad660ae0ec5eae2fc63c18a06c85cd3a84df65d4c0fdf5a1d212a7e92454f1f5 *third_party/cosmo/2/parsehttpdatetime_test.com.gz ================================================ FILE: third_party/cosmo/2/parsehttpmessage_test.com.dbg.gz.sha256 ================================================ de918e4e54577478d1856152fe20a20e85bd5db27769fd8a3cc65ba6fcced308 *third_party/cosmo/2/parsehttpmessage_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parsehttpmessage_test.com.gz.sha256 ================================================ 2f0721c17b97f109b613a7c92b014e0e75b2cdcfd5cd32cbab2fe5077127df47 *third_party/cosmo/2/parsehttpmessage_test.com.gz ================================================ FILE: third_party/cosmo/2/parsehttprange_test.com.dbg.gz.sha256 ================================================ c2c0fe5aaca3000987621e6130a1a5777222eb355a0f79877332719264b975e7 *third_party/cosmo/2/parsehttprange_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parsehttprange_test.com.gz.sha256 ================================================ 3797782745735c9b222abc1e643ebb05e2a583fb3a9559908eb88febec99fc81 *third_party/cosmo/2/parsehttprange_test.com.gz ================================================ FILE: third_party/cosmo/2/parseip_test.com.dbg.gz.sha256 ================================================ 0da62f37490b820b986d2ce16e843ecc51d881911f291b268daa95c2a1fd32ef *third_party/cosmo/2/parseip_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parseip_test.com.gz.sha256 ================================================ 3793ea4d241dffaea3421437e0a3b84a2c803061b48d420a9a7ce064add4025f *third_party/cosmo/2/parseip_test.com.gz ================================================ FILE: third_party/cosmo/2/parseresolvconf_test.com.dbg.gz.sha256 ================================================ 13dacfc8905382072a74ff8e05b32ccd2c01bac1e870305ac4f7e241e5e259f7 *third_party/cosmo/2/parseresolvconf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parseresolvconf_test.com.gz.sha256 ================================================ 5cf9af2443255178fb94301528c394aed2b6096abd01d2c75fb8f42ef2f4f440 *third_party/cosmo/2/parseresolvconf_test.com.gz ================================================ FILE: third_party/cosmo/2/parseurl_test.com.dbg.gz.sha256 ================================================ 0f5e836108fd82c9e1d2ed63e190e39f5f5a3f2d0366ab319acf2b6189ff328e *third_party/cosmo/2/parseurl_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/parseurl_test.com.gz.sha256 ================================================ 3d2f20a255be78843a3899591894dfe9f4fef604c5faeb489460227b4ffb694f *third_party/cosmo/2/parseurl_test.com.gz ================================================ FILE: third_party/cosmo/2/pascalifydnsname_test.com.dbg.gz.sha256 ================================================ b97b640d196f57c295b4154b6e25701f71a08e307aa94d73c937217f74c4e2fd *third_party/cosmo/2/pascalifydnsname_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pascalifydnsname_test.com.gz.sha256 ================================================ 028e8986d60ad3a1dbb2c32ef9ef58e90e9d00ebd259428844e57f4527bfe37a *third_party/cosmo/2/pascalifydnsname_test.com.gz ================================================ FILE: third_party/cosmo/2/pcmpstr_test.com.dbg.gz.sha256 ================================================ 270a57db1103cb5fe5e36e2f97c6cdc4385945732e4f8b003e5e731745f35568 *third_party/cosmo/2/pcmpstr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pcmpstr_test.com.gz.sha256 ================================================ 3952d152cf2e1e4221fa8a918f6f32920e2de1d5259612647f6453d9bbe7fbd6 *third_party/cosmo/2/pcmpstr_test.com.gz ================================================ FILE: third_party/cosmo/2/pingpong_test.com.dbg.gz.sha256 ================================================ 89d26b9b9aac079f5e12fe286cfeb60ac86f55a391c00a9a955b854390a8d20e *third_party/cosmo/2/pingpong_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pingpong_test.com.gz.sha256 ================================================ 8c5e9424163bdfbfe734e27571a9142aadd98bf6dccd96d8dabe88785ac4eb89 *third_party/cosmo/2/pingpong_test.com.gz ================================================ FILE: third_party/cosmo/2/pledge2_test.com.dbg.gz.sha256 ================================================ 8de8753f112d1d790180ac4b05ffbd6471f03e5e9626adf25c9fb9fb40ffb561 *third_party/cosmo/2/pledge2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pledge2_test.com.gz.sha256 ================================================ 95450d8db76bbbc1112ae81e84a9fdbd37d7f744eadca5e83f92690c7bf8d149 *third_party/cosmo/2/pledge2_test.com.gz ================================================ FILE: third_party/cosmo/2/pledge_test.com.dbg.gz.sha256 ================================================ 10dd1f3ef7b709216a455d0b4763ae1a740ae9c04f9deae2512f472aeb4e5872 *third_party/cosmo/2/pledge_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pledge_test.com.gz.sha256 ================================================ 9f21d4cc6edc98993f55efa66324fedb09bf0fb848d360b8b78dfbd26bfdfcdf *third_party/cosmo/2/pledge_test.com.gz ================================================ FILE: third_party/cosmo/2/plinko_test.com.dbg.gz.sha256 ================================================ 8c24b1eb027c5906631cfc4823a4c3279610794272073ee71156e278208b45d2 *third_party/cosmo/2/plinko_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/plinko_test.com.gz.sha256 ================================================ 2464269f73c9a5612e5cd7e9811ee791de99d71c9520398da56588c3826e4367 *third_party/cosmo/2/plinko_test.com.gz ================================================ FILE: third_party/cosmo/2/pmulhrsw_test.com.dbg.gz.sha256 ================================================ 33aa0a7bcf766934f96b64b30308b94d8e8d438541c007c16e4b88f79a12f779 *third_party/cosmo/2/pmulhrsw_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pmulhrsw_test.com.gz.sha256 ================================================ 13b6674409b5d6c6844789d431c633c2254f1c4ff265e61c5cb9a0a233cd2ee0 *third_party/cosmo/2/pmulhrsw_test.com.gz ================================================ FILE: third_party/cosmo/2/poll_test.com.dbg.gz.sha256 ================================================ 9e118d9063ec84d44a61645bca9c366dd5e487d8b39f4bfc55ec2582833a06a3 *third_party/cosmo/2/poll_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/poll_test.com.gz.sha256 ================================================ 9642b9eb9cb6af6f7e3cd39810f844abdabbd5a3b5a2649c79cf08d6ad442c76 *third_party/cosmo/2/poll_test.com.gz ================================================ FILE: third_party/cosmo/2/popcnt_test.com.dbg.gz.sha256 ================================================ 22f8c0746e78fd3998b610ebf6644c9f44809bba3a68a2aad5335421a4010aa5 *third_party/cosmo/2/popcnt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/popcnt_test.com.gz.sha256 ================================================ 01b4e728daec992f2a2e4ec21c9d36343e41b186888c4b3d64d2905e5a57a484 *third_party/cosmo/2/popcnt_test.com.gz ================================================ FILE: third_party/cosmo/2/popen_test.com.dbg.gz.sha256 ================================================ c158d6aa8b8a2097da60f3348542a9666a33fbd847aa9234d29e37eb80ee6ee5 *third_party/cosmo/2/popen_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/popen_test.com.gz.sha256 ================================================ b7320aa725a8d47a3cd66527d50b86264e309633e3f7ba20e56176c8effa7cb8 *third_party/cosmo/2/popen_test.com.gz ================================================ FILE: third_party/cosmo/2/posix_fadvise_test.com.dbg.gz.sha256 ================================================ 1a4a0d705336d9adfb52309ff30fe0904d4ee8ecfd2b3fb1df2cd04f95fc1f98 *third_party/cosmo/2/posix_fadvise_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/posix_fadvise_test.com.gz.sha256 ================================================ b13d930cab6b35961cd71afac40f187155bcc22756b5f6f54244ee7820a41c81 *third_party/cosmo/2/posix_fadvise_test.com.gz ================================================ FILE: third_party/cosmo/2/posix_spawn_test.com.dbg.gz.sha256 ================================================ 5150b4b1b95d1b51737a656d8582052fa3485fbe532824767807534766d570e6 *third_party/cosmo/2/posix_spawn_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/posix_spawn_test.com.gz.sha256 ================================================ 6cc1086b98ac734f430eb2f717581e7513173cf820c14482b73e3a25be42c10d *third_party/cosmo/2/posix_spawn_test.com.gz ================================================ FILE: third_party/cosmo/2/pow10_test.com.dbg.gz.sha256 ================================================ 265b2f239a21accabab0c0aa406a037a2412cea7fd170036bde1e1b6b2182bc1 *third_party/cosmo/2/pow10_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pow10_test.com.gz.sha256 ================================================ 9d50aea3ce34d607179d66dcd160c0bf58596bdff65cbda583edc89507018aab *third_party/cosmo/2/pow10_test.com.gz ================================================ FILE: third_party/cosmo/2/powl_test.com.dbg.gz.sha256 ================================================ 574c984e3e4e601e48b41743de692261af56f45a24298256af281680011849d7 *third_party/cosmo/2/powl_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/powl_test.com.gz.sha256 ================================================ 4a2a5da9461e437481d48eddbfd02bd3acf12b806d15211d849c924b5d5b5b75 *third_party/cosmo/2/powl_test.com.gz ================================================ FILE: third_party/cosmo/2/pread_test.com.dbg.gz.sha256 ================================================ d7ed17f32b09056999dd5150d3103d88e74b1096ae066a41623bd7459dba17f9 *third_party/cosmo/2/pread_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pread_test.com.gz.sha256 ================================================ fa23c945cd36d72bda1a6462c275b8214ebe6ede8a7fe02ce2750c1a0941bd89 *third_party/cosmo/2/pread_test.com.gz ================================================ FILE: third_party/cosmo/2/preadv_test.com.dbg.gz.sha256 ================================================ f0464611099c956c2f3efdf7dc4dc03e2f21f7860a7fa21ff151f5a91641d4e8 *third_party/cosmo/2/preadv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/preadv_test.com.gz.sha256 ================================================ a062f6d2585d40041bbc923a88274350ef380559ec71564f4ab8e465c4ab66ff *third_party/cosmo/2/preadv_test.com.gz ================================================ FILE: third_party/cosmo/2/printargs_test.com.dbg.gz.sha256 ================================================ c87e10a06be315a22c06993cd63a7f4963b622774f8747642599c4f58adb1aca *third_party/cosmo/2/printargs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/printargs_test.com.gz.sha256 ================================================ 44bc076ead398c250ea2f69e303bea858919faca7fa8e0aa41e62a8f02358527 *third_party/cosmo/2/printargs_test.com.gz ================================================ FILE: third_party/cosmo/2/prototxt_test.com.dbg.gz.sha256 ================================================ d60d3eb290715e1a7397edbbe51b294fea52210888fc114dc68658e8472dac59 *third_party/cosmo/2/prototxt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/prototxt_test.com.gz.sha256 ================================================ 45fe32054858bdf6c945642b942aeaa4a585d83ed5644c7b5acb9bf0f51fb3a0 *third_party/cosmo/2/prototxt_test.com.gz ================================================ FILE: third_party/cosmo/2/pshuf_test.com.dbg.gz.sha256 ================================================ 8a8f8c30249cdfee4e349babad18ca6ceb04051ccdea9c9f6eb227639482a9c5 *third_party/cosmo/2/pshuf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pshuf_test.com.gz.sha256 ================================================ 39d677a82ae462d7601acf6a8d9d85746e6a01ddc70f64f1e1942adab4e3addb *third_party/cosmo/2/pshuf_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_atfork_test.com.dbg.gz.sha256 ================================================ 8830aaa436d43980375370f65bebdd0a7f5dcea6e3a3c0c41d78f31570413d1b *third_party/cosmo/2/pthread_atfork_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_atfork_test.com.gz.sha256 ================================================ d81304a820c3ad930fbc027da2a2de0bd8faa97f44f36be2ca1b9e39477ba250 *third_party/cosmo/2/pthread_atfork_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_barrier_wait_test.com.dbg.gz.sha256 ================================================ 996ce4887d9936eda01e3a0b8e119e3b3328155ad6c561308867fa610c44cc73 *third_party/cosmo/2/pthread_barrier_wait_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_barrier_wait_test.com.gz.sha256 ================================================ dfd1c9627e8e5dbd6033e43c180419db235cae4073186c3cbe72a97aa46e2b2a *third_party/cosmo/2/pthread_barrier_wait_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_cancel_test.com.dbg.gz.sha256 ================================================ 4ac8af933b0f482a2c09170096f85ac8ffec886dd9ae2cfbf604a008819b3f38 *third_party/cosmo/2/pthread_cancel_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_cancel_test.com.gz.sha256 ================================================ 09eaeba7c4d18a85155d849f08819b39d30658628c5021d89eec1b447d8ab869 *third_party/cosmo/2/pthread_cancel_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_cond_signal_test.com.dbg.gz.sha256 ================================================ fdddac58927017beebb8795cad942b91e680f2cc8c351a574d497404a3429ae0 *third_party/cosmo/2/pthread_cond_signal_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_cond_signal_test.com.gz.sha256 ================================================ bbba18107a0800a6d1af40aa41f2ed54adaf80614542bd4c737656192b85bfad *third_party/cosmo/2/pthread_cond_signal_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_create_test.com.dbg.gz.sha256 ================================================ 0ea07383beb6dd927a0b600fcd90782cf1e14678a787bbaad88cbd7220e0fc41 *third_party/cosmo/2/pthread_create_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_create_test.com.gz.sha256 ================================================ d327c401e5eaf92ceb5f90368c9bb7e584480da987c803fbfd987d8320086892 *third_party/cosmo/2/pthread_create_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_detach_test.com.dbg.gz.sha256 ================================================ 4194106f334b0cc7feab49fcc0f865e360f7f19aee172a29e238eee969fdaf38 *third_party/cosmo/2/pthread_detach_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_detach_test.com.gz.sha256 ================================================ e7a98180949685bac7a7c2081372eddba8cadb9c857d39bba9cf9c41dd9dff1c *third_party/cosmo/2/pthread_detach_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_exit_test.com.dbg.gz.sha256 ================================================ 7784a26790d342f6b24f8c73c2832ba339629d0fe7b3986b8bf7cd94945bcbd1 *third_party/cosmo/2/pthread_exit_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_exit_test.com.gz.sha256 ================================================ c93846b3c601bf608f9ce9f9c6a594c0e22acfacdc2b5e13e87b1a6736f30b01 *third_party/cosmo/2/pthread_exit_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_key_create_test.com.dbg.gz.sha256 ================================================ 3944c49178ced4d1e6ec25f99c80dc45bab726b7c25dd461619df86bc441205e *third_party/cosmo/2/pthread_key_create_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_key_create_test.com.gz.sha256 ================================================ 0ac8bf575bdc63c88af61bfe008ffc8fe61c222be6dfe64daf61245a82221bdf *third_party/cosmo/2/pthread_key_create_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_kill_test.com.dbg.gz.sha256 ================================================ d3271abbcec21425bb0ab7902031eeba6f669e7fc3b4417b74d7c2fb98f7f125 *third_party/cosmo/2/pthread_kill_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_kill_test.com.gz.sha256 ================================================ 435f45043ddf4d4e44c8e162795d2044ff6ae5651d01238659a819e4771070ac *third_party/cosmo/2/pthread_kill_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_mutex_lock2_test.com.dbg.gz.sha256 ================================================ 72cfeb0b0bc91d3de96962fc182d806a0b5f26fb5291eb7213e83d82a984f7c3 *third_party/cosmo/2/pthread_mutex_lock2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_mutex_lock2_test.com.gz.sha256 ================================================ c65fb4682a440bdf6df8b2f0f13a497273013d82c050a5fc4c186d47bf2b31e6 *third_party/cosmo/2/pthread_mutex_lock2_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_mutex_lock_test.com.dbg.gz.sha256 ================================================ f0896e9ce8c132ff7e1507692908cab92f1e06e2060ebd85093e41e37c3130e3 *third_party/cosmo/2/pthread_mutex_lock_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_mutex_lock_test.com.gz.sha256 ================================================ e234713bc92fa658bc8e9a38ad536b4f0edd48357f48b055a80f0d21391c0923 *third_party/cosmo/2/pthread_mutex_lock_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_once_test.com.dbg.gz.sha256 ================================================ b39d8d4d48d23b06a36bd7dacafe28f16713e8d08cb6f7a1b2263d004cdbc2a3 *third_party/cosmo/2/pthread_once_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_once_test.com.gz.sha256 ================================================ 1f5c6622d7511c03f3b72c712a908afdc7c71437522ed228db1ff514964ffeae *third_party/cosmo/2/pthread_once_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_rwlock_rdlock_test.com.dbg.gz.sha256 ================================================ b25273cc7cc38b98f063bf9062228c3a538425ac629b991cd47f65d918117788 *third_party/cosmo/2/pthread_rwlock_rdlock_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_rwlock_rdlock_test.com.gz.sha256 ================================================ d8b07ef1d1d52488f49d689b00f3714093aff769e3181029e27648a122199098 *third_party/cosmo/2/pthread_rwlock_rdlock_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_setname_np_test.com.dbg.gz.sha256 ================================================ 95bbb433853fc9d580f1a5d9282c98af402859aeaee37df5688ccb3ab6669214 *third_party/cosmo/2/pthread_setname_np_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_setname_np_test.com.gz.sha256 ================================================ 36c9b690a24c75ce1e3a4a445eb034ef65a942ebc69b2a3f81aca2ac493e2264 *third_party/cosmo/2/pthread_setname_np_test.com.gz ================================================ FILE: third_party/cosmo/2/pthread_spin_lock_test.com.dbg.gz.sha256 ================================================ c9253c7fac98fed0db9d0222113a1f9908174813025e1714f74845e76529e326 *third_party/cosmo/2/pthread_spin_lock_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pthread_spin_lock_test.com.gz.sha256 ================================================ 10bd69ae8099711f4cce9c586df084494982ec4c26a886dd70e10cfccd63fb6d *third_party/cosmo/2/pthread_spin_lock_test.com.gz ================================================ FILE: third_party/cosmo/2/ptrace_test.com.dbg.gz.sha256 ================================================ e0f0d172e6ad0354161c2472a7cb62d145f69a593d4c1d790a302e51d3e10ab5 *third_party/cosmo/2/ptrace_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ptrace_test.com.gz.sha256 ================================================ 1860b84f7251db2f1641bc4d88a7fa678be1500aa88e70037e003d4f90383458 *third_party/cosmo/2/ptrace_test.com.gz ================================================ FILE: third_party/cosmo/2/pty_test.com.dbg.gz.sha256 ================================================ b9c5b0efae93498c82afb5478a4f80cd59f0284f42d99b02f05d322b57a2eb85 *third_party/cosmo/2/pty_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pty_test.com.gz.sha256 ================================================ 0219e5b71b3d0ff31d81d5dc7a2e4c316842d2f91f04e78e1b9fe2db94b290c0 *third_party/cosmo/2/pty_test.com.gz ================================================ FILE: third_party/cosmo/2/putenv_test.com.dbg.gz.sha256 ================================================ c52c7ee432a3bdac0d30dcb0bb80d8d7934291d7cf2104e8ad0f398d59aa4de1 *third_party/cosmo/2/putenv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/putenv_test.com.gz.sha256 ================================================ e79689beaad790159ab920624a1d376503c4fdf2a4ccf6440c30c17d7a971ffe *third_party/cosmo/2/putenv_test.com.gz ================================================ FILE: third_party/cosmo/2/pwrite_test.com.dbg.gz.sha256 ================================================ 957f84c738c144f3f46afedbe537c993632f02278085891a89af30f05bc6b5ca *third_party/cosmo/2/pwrite_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/pwrite_test.com.gz.sha256 ================================================ aafc963493bdc8641cff377a3a6a28a32d9cbcc3cbdc34ccf0f7cc5c89cdb1fb *third_party/cosmo/2/pwrite_test.com.gz ================================================ FILE: third_party/cosmo/2/qsort_test.com.dbg.gz.sha256 ================================================ 41e0dd947608b56afb5bd9cb6d52acfb75249996d9cc99a82c991ec20f087d88 *third_party/cosmo/2/qsort_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/qsort_test.com.gz.sha256 ================================================ 47af44bda67e9c3557f9bb0185345aae2f013943c964497424fa3b5904be1c29 *third_party/cosmo/2/qsort_test.com.gz ================================================ FILE: third_party/cosmo/2/raise_race_test.com.dbg.gz.sha256 ================================================ dc90d6d8767dc6c2abbaff811a3492796585755aa60e76bfbc9b02d3da4ebcbf *third_party/cosmo/2/raise_race_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/raise_race_test.com.gz.sha256 ================================================ 463183fba06c1a5179cc1ec7459e0beb6d3fff8c3094d50e210862fe5469b31f *third_party/cosmo/2/raise_race_test.com.gz ================================================ FILE: third_party/cosmo/2/raise_test.com.dbg.gz.sha256 ================================================ aa732f8ff4415634eeeca102ac03bccdb448b698890de562090b04251f1ea2f8 *third_party/cosmo/2/raise_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/raise_test.com.gz.sha256 ================================================ 82f3ced9e60699a6614e0e2698e2b6aa1c8490ae58610e72b8c767ccddf2fb49 *third_party/cosmo/2/raise_test.com.gz ================================================ FILE: third_party/cosmo/2/rand64_test.com.dbg.gz.sha256 ================================================ 6cb7985151cad6a82ecce7ecf1eeee2d04cbec64e678cbba6ae031148ac53089 *third_party/cosmo/2/rand64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/rand64_test.com.gz.sha256 ================================================ ec18678128d07be110f1ead46662bbaa2a5c06a2e9dd3c03157770249c99461a *third_party/cosmo/2/rand64_test.com.gz ================================================ FILE: third_party/cosmo/2/rand_test.com.dbg.gz.sha256 ================================================ 5ce0e5155c8d7b0eeee1269a3ddab60fcbafe9eae7bf253068dad8bf21667925 *third_party/cosmo/2/rand_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/rand_test.com.gz.sha256 ================================================ bee6eb7e7a108f7072ccef4e7e9b68e968f7bc75039dd2a03bb66fe7863e8cec *third_party/cosmo/2/rand_test.com.gz ================================================ FILE: third_party/cosmo/2/read_test.com.dbg.gz.sha256 ================================================ e8a9a0a8c162b945da40ecfce3a4ff5f0e55eb23f83eb466ef7c6f5f0a693d3e *third_party/cosmo/2/read_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/read_test.com.gz.sha256 ================================================ ec8c22fa6918a37244df94b0caa529b01fa70f9262007051e23a19e858f1e4e5 *third_party/cosmo/2/read_test.com.gz ================================================ FILE: third_party/cosmo/2/readansi_test.com.dbg.gz.sha256 ================================================ 2ce31f453a10b0e42ca39ebb64ffc881ca0fa65f4a1d4fac371dbc8b03a067c7 *third_party/cosmo/2/readansi_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/readansi_test.com.gz.sha256 ================================================ 44d9d574f5185755666d655cd7e42c74fd352703d8a226401e2987de22914b01 *third_party/cosmo/2/readansi_test.com.gz ================================================ FILE: third_party/cosmo/2/readlinkat_test.com.dbg.gz.sha256 ================================================ 251230ab5b7f14ee2b211cda28d2e48f99a1bbfa8020501534c228c15eac1779 *third_party/cosmo/2/readlinkat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/readlinkat_test.com.gz.sha256 ================================================ 0891de755332373e7bc3d903be36f72de5ed375e2447acef6ddfd28a4d7f3e8d *third_party/cosmo/2/readlinkat_test.com.gz ================================================ FILE: third_party/cosmo/2/realloc_in_place_test.com.dbg.gz.sha256 ================================================ fa9a01b118b0b70266e1fbb690dba38b68f04e784765f2cec42b04549a996972 *third_party/cosmo/2/realloc_in_place_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/realloc_in_place_test.com.gz.sha256 ================================================ 055a37b28b72acf40e7916545c5114adf011a16b91b59ee20ac22aaacbb48000 *third_party/cosmo/2/realloc_in_place_test.com.gz ================================================ FILE: third_party/cosmo/2/redbean_test.com.dbg.gz.sha256 ================================================ 3b6f7689739bc2cb1c6ff1f95cf3dfb3afa23fe9c65b576f4675daaef23638b2 *third_party/cosmo/2/redbean_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/redbean_test.com.gz.sha256 ================================================ ab1b75356696cbaef8d942b813549b047a73ca24dcb5bc27eeec7cd1e52978b0 *third_party/cosmo/2/redbean_test.com.gz ================================================ FILE: third_party/cosmo/2/regex_test.com.dbg.gz.sha256 ================================================ 95cb414c767d44ff8e093565c5d93ee5334e08b004efcb21a2737458cb832321 *third_party/cosmo/2/regex_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/regex_test.com.gz.sha256 ================================================ 5ac50fab0989ab7b4994c28b2be0df4201537d967abf955bf6406bb255bd37f5 *third_party/cosmo/2/regex_test.com.gz ================================================ FILE: third_party/cosmo/2/renameat_test.com.dbg.gz.sha256 ================================================ cc3f4b03ec4948e914f5afe0e3bf43de678dcda38fcce36e1280699a2959f39b *third_party/cosmo/2/renameat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/renameat_test.com.gz.sha256 ================================================ 5c2c9063eb3c2f5ec818d9af406fec804a3d77fb7f1538db3641acf6f96d8460 *third_party/cosmo/2/renameat_test.com.gz ================================================ FILE: third_party/cosmo/2/replacestr_test.com.dbg.gz.sha256 ================================================ 08267108d1e2c17e191b6ee5bd053b7fce7574560eca8a0ff4adb263a0de2d2f *third_party/cosmo/2/replacestr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/replacestr_test.com.gz.sha256 ================================================ b2849af2858dc465462acc2f4a72570f1206c5fbe41c9c5a555bfe5107174d50 *third_party/cosmo/2/replacestr_test.com.gz ================================================ FILE: third_party/cosmo/2/reservefd_test.com.dbg.gz.sha256 ================================================ b81169624e29f251c8528e4da4a5519ec793b93d3dd4878399e5f454c8348595 *third_party/cosmo/2/reservefd_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/reservefd_test.com.gz.sha256 ================================================ 0861822186520f1df9b23b7b2c6e5c7ede19283c1b9dd1c51d7c709557b6aa9d *third_party/cosmo/2/reservefd_test.com.gz ================================================ FILE: third_party/cosmo/2/resolvehostsreverse_test.com.dbg.gz.sha256 ================================================ 55df6dfe924acc83fdb9495603b78b9576b3686db413330409630726b0f55303 *third_party/cosmo/2/resolvehostsreverse_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/resolvehostsreverse_test.com.gz.sha256 ================================================ 03ecc0a9231a8fa1e454b5d6b4fe1523b4c835bb6d9e97ddb2a07dcd155547c8 *third_party/cosmo/2/resolvehostsreverse_test.com.gz ================================================ FILE: third_party/cosmo/2/resolvehoststxt_test.com.dbg.gz.sha256 ================================================ e0d78c6d6715fbf18fdc84921d638c1155471b475848deefd83ef6143541794c *third_party/cosmo/2/resolvehoststxt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/resolvehoststxt_test.com.gz.sha256 ================================================ 1c97c7a2b33453ebd96e546d84b2feb663e69c41d1aa355e384dcd0e2814601f *third_party/cosmo/2/resolvehoststxt_test.com.gz ================================================ FILE: third_party/cosmo/2/reverse_test.com.dbg.gz.sha256 ================================================ 7b8a649203703afa71c63819034a90fcd0438da95d53dbdf55f83a03835f8cc4 *third_party/cosmo/2/reverse_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/reverse_test.com.gz.sha256 ================================================ 84047c8cad3e0a96b31179f12afd37feca24b652bde20057a62f6d48ca83bf0f *third_party/cosmo/2/reverse_test.com.gz ================================================ FILE: third_party/cosmo/2/rgb2ansi_test.com.dbg.gz.sha256 ================================================ 6e400a33e9c6d4b8ddda9f3d906a9f76c4a19a6d04fa78f6ff73abb7c7a9640c *third_party/cosmo/2/rgb2ansi_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/rgb2ansi_test.com.gz.sha256 ================================================ 0bc8d8884593194a130c59a3e7851ab280595b7c1ec50d3eed5cd318c8965c57 *third_party/cosmo/2/rgb2ansi_test.com.gz ================================================ FILE: third_party/cosmo/2/rngset_test.com.dbg.gz.sha256 ================================================ 16a844f17e55b43f0f481e096a5b27613087cf9318cc68dbbf2baafea8686862 *third_party/cosmo/2/rngset_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/rngset_test.com.gz.sha256 ================================================ 8b84008dcc3b43d16bd05ad5efe186ac6abe31758f13d6c9c1a6570c9796dc7f *third_party/cosmo/2/rngset_test.com.gz ================================================ FILE: third_party/cosmo/2/round_test.com.dbg.gz.sha256 ================================================ 68c32e7640a3a6908f470bd8b8ce9097ecb92b8ef47c13b21bb216afed0f5140 *third_party/cosmo/2/round_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/round_test.com.gz.sha256 ================================================ c7e3cb380f6c12afeadcf2c6a7677d69f15b964dd63ed3be3cc55829e7aee898 *third_party/cosmo/2/round_test.com.gz ================================================ FILE: third_party/cosmo/2/rounddown2pow_test.com.dbg.gz.sha256 ================================================ 267f470e53c78076aab56b9649f75e625644ba9e3ef03f601ab8def505c16916 *third_party/cosmo/2/rounddown2pow_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/rounddown2pow_test.com.gz.sha256 ================================================ 43a3c42b254c587b40681bc08d0395a0bf99d275603434afe066a67f7fa1b1d2 *third_party/cosmo/2/rounddown2pow_test.com.gz ================================================ FILE: third_party/cosmo/2/roundup2log_test.com.dbg.gz.sha256 ================================================ 39c5e80a80b905755300eec7a5dbe9a7638460e2d8c2bda707a6442562d34b38 *third_party/cosmo/2/roundup2log_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/roundup2log_test.com.gz.sha256 ================================================ 6073e10e044517a2050a3d7a07b81bc4c6a0a7b6ca6cf7451cb8e593f1df1b1a *third_party/cosmo/2/roundup2log_test.com.gz ================================================ FILE: third_party/cosmo/2/roundup2pow_test.com.dbg.gz.sha256 ================================================ 607797eeeeb97a4a1901fb8d4712fcacea3579cc59560f6b041276e81c9dd8bc *third_party/cosmo/2/roundup2pow_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/roundup2pow_test.com.gz.sha256 ================================================ 036f28b9de0c141f1bc1bd44b8735b26581a35c3af3c320bdb036241aef74e7f *third_party/cosmo/2/roundup2pow_test.com.gz ================================================ FILE: third_party/cosmo/2/sad16x8n_test.com.dbg.gz.sha256 ================================================ 01065e6da2b3bf0ddc63275ae894e2e3a7915a77d4c632659def8079648209c0 *third_party/cosmo/2/sad16x8n_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sad16x8n_test.com.gz.sha256 ================================================ e7f141868dc3f7519c6fdd98108ad64446f814b26e79e96d21a621cf24aca756 *third_party/cosmo/2/sad16x8n_test.com.gz ================================================ FILE: third_party/cosmo/2/scale_test.com.dbg.gz.sha256 ================================================ bac12d1a5962277e4d312f980198d4d16fcba992f5b2e41aa90384afc07902f4 *third_party/cosmo/2/scale_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/scale_test.com.gz.sha256 ================================================ 5cc89b207965c04cd3a23c9c25fdd6d775e7710fd366bfa37474e9670b8c45d3 *third_party/cosmo/2/scale_test.com.gz ================================================ FILE: third_party/cosmo/2/scalevolume_test.com.dbg.gz.sha256 ================================================ 31e5959860c9e1e96ea54c7a1470afec9f77218cd24e7de0ef22d64ba7abd409 *third_party/cosmo/2/scalevolume_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/scalevolume_test.com.gz.sha256 ================================================ b1566e10de51db9859312d9c52f0bcb5d4663930ecac41e7fc79fd4561bea5b2 *third_party/cosmo/2/scalevolume_test.com.gz ================================================ FILE: third_party/cosmo/2/sched_getaffinity_test.com.dbg.gz.sha256 ================================================ a8e5d51f6de0b700cb5b3b4ea6b887292212cef534c9e1662626f1113357c24e *third_party/cosmo/2/sched_getaffinity_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sched_getaffinity_test.com.gz.sha256 ================================================ 06a4cbb523c6a50f1611f8a9aacb45013159b19f4a57f3352ff6b0d289c3f55b *third_party/cosmo/2/sched_getaffinity_test.com.gz ================================================ FILE: third_party/cosmo/2/sched_setscheduler_test.com.dbg.gz.sha256 ================================================ 1478abc3ce90a9a4d864c6a6662d5fa0ba69ffe709dd017506a33c58fd30b278 *third_party/cosmo/2/sched_setscheduler_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sched_setscheduler_test.com.gz.sha256 ================================================ 90a7b88a4e937e4e6e4f22a588d484965c6aa51dea3f43bd78ed3e8d6602191c *third_party/cosmo/2/sched_setscheduler_test.com.gz ================================================ FILE: third_party/cosmo/2/sched_yield_test.com.dbg.gz.sha256 ================================================ cb33fa7e1257f41daf4a37bd69bfcc4c5c11b854f1fe3b906fbe7fdb9f21b37e *third_party/cosmo/2/sched_yield_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sched_yield_test.com.gz.sha256 ================================================ 473584a36f348b5950549eca2d3010cd9282ba960d042ff65e1c50a9c43ae800 *third_party/cosmo/2/sched_yield_test.com.gz ================================================ FILE: third_party/cosmo/2/seccomp_test.com.dbg.gz.sha256 ================================================ 3326c73a47dc3f2630b816c6abeff8f7cf22b8a637ffaa2352d6aa00a72b2cf6 *third_party/cosmo/2/seccomp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/seccomp_test.com.gz.sha256 ================================================ 89a167df3849febc358eed799ffb43f9278723b78668425209ab873ad8a243b0 *third_party/cosmo/2/seccomp_test.com.gz ================================================ FILE: third_party/cosmo/2/secp384r1_test.com.dbg.gz.sha256 ================================================ b089dbb0578ed2a9be74ed8697a90e9a7ee99e5dac5002d446b5e4bcb69bcd8c *third_party/cosmo/2/secp384r1_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/secp384r1_test.com.gz.sha256 ================================================ fc0328b3f31d6cb9e6cf1dd8a629ee030d119ffadb44ed81ada4bf5b64c0a436 *third_party/cosmo/2/secp384r1_test.com.gz ================================================ FILE: third_party/cosmo/2/select_test.com.dbg.gz.sha256 ================================================ a891ed186cfd833a7849c3dcc953e95eec52c39ba19361d818c42b263a28b7b5 *third_party/cosmo/2/select_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/select_test.com.gz.sha256 ================================================ 041af3dd90142e541af59ef0cb33cee9503cfb942229eef31cdb8924f3074bd1 *third_party/cosmo/2/select_test.com.gz ================================================ FILE: third_party/cosmo/2/sem_open_test.com.dbg.gz.sha256 ================================================ 0ad0f283603197d6705cc3336fca03ce4cbba6970cfc9c5fa3f96b8e7c955a6f *third_party/cosmo/2/sem_open_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sem_open_test.com.gz.sha256 ================================================ d70aaf367899c5ef1727cf7fa17c7a42aede922e00def6055dba07bfac5208d6 *third_party/cosmo/2/sem_open_test.com.gz ================================================ FILE: third_party/cosmo/2/sem_timedwait_test.com.dbg.gz.sha256 ================================================ 927ae752ac936112b4e5fb7fc9d8122e63c1be2c1d566d4d03dd7c74ff577d2d *third_party/cosmo/2/sem_timedwait_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sem_timedwait_test.com.gz.sha256 ================================================ 5a3889514ec88d5361c5559fb06dd99a897f2623dfa4750053664043d1b5ca50 *third_party/cosmo/2/sem_timedwait_test.com.gz ================================================ FILE: third_party/cosmo/2/sendfile_test.com.dbg.gz.sha256 ================================================ 665cf289d5e653e8df455914b7cce5686b41fc7149ff8dbf6dfa14ce57bb0440 *third_party/cosmo/2/sendfile_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sendfile_test.com.gz.sha256 ================================================ 660f6d142946577be17d1eccc5c45e807899514087923f2813221c0326795a88 *third_party/cosmo/2/sendfile_test.com.gz ================================================ FILE: third_party/cosmo/2/sendrecvmsg_test.com.dbg.gz.sha256 ================================================ de1bfcb80e685f2e30dd118b32ed8a53f1f8fad3da84f84aec267380c2835839 *third_party/cosmo/2/sendrecvmsg_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sendrecvmsg_test.com.gz.sha256 ================================================ a37d156da9f39e3bb9a4b7de04f1b9730729021cbbb15d58661b145944b73c72 *third_party/cosmo/2/sendrecvmsg_test.com.gz ================================================ FILE: third_party/cosmo/2/servicestxt_test.com.dbg.gz.sha256 ================================================ 8b67e6590a2cb35856ec5b245d141a752a0ce81be745c9277f1c87321f75f010 *third_party/cosmo/2/servicestxt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/servicestxt_test.com.gz.sha256 ================================================ 10c9e37b5aa5ab265d2ca40529810250d8803efece79ee0300156938246545f8 *third_party/cosmo/2/servicestxt_test.com.gz ================================================ FILE: third_party/cosmo/2/setitimer_test.com.dbg.gz.sha256 ================================================ 29c9159a37b07d0f1183fe0cfa6d54e77786fdfa6a2befc33b6e86ab069deb9b *third_party/cosmo/2/setitimer_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/setitimer_test.com.gz.sha256 ================================================ 639b579331090fdf6d3efca402370405a96f57294b0b99b6dad779cc46c9eced *third_party/cosmo/2/setitimer_test.com.gz ================================================ FILE: third_party/cosmo/2/setlocale_test.com.dbg.gz.sha256 ================================================ c37757d1d2794e81d31e725963e0c5a7b36b60ddace635e6c4a0990c2745a2b5 *third_party/cosmo/2/setlocale_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/setlocale_test.com.gz.sha256 ================================================ 043e3764995929caed33c9b68e09c0126ee233e4a54e971d86eeece6292f1123 *third_party/cosmo/2/setlocale_test.com.gz ================================================ FILE: third_party/cosmo/2/setrlimit_test.com.dbg.gz.sha256 ================================================ 2af50510275bd51acf2bb8e85f3576f6fa5c0f88526be9551f19638187bda966 *third_party/cosmo/2/setrlimit_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/setrlimit_test.com.gz.sha256 ================================================ f4fb62821b54e65123320e078a148103c6685255e5b733a8220eea56c999b85c *third_party/cosmo/2/setrlimit_test.com.gz ================================================ FILE: third_party/cosmo/2/setsockopt_test.com.dbg.gz.sha256 ================================================ c6268b99357ec952108397ac1f8e488ba81492c7e425dcbde0a2aace6ecaebde *third_party/cosmo/2/setsockopt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/setsockopt_test.com.gz.sha256 ================================================ 3d0ddf1b538ec21d8092a982a9868352601133e3ad96ed5994befd9aaacfd96f *third_party/cosmo/2/setsockopt_test.com.gz ================================================ FILE: third_party/cosmo/2/signal_test.com.dbg.gz.sha256 ================================================ a103bde47b38c6fd92699022638f9b17ef3996e70ccc7d430d71f734741a3c9a *third_party/cosmo/2/signal_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/signal_test.com.gz.sha256 ================================================ d36176fd3a02bcd4019d7b3dc046e985455b86d92e4e1c10e0434efb56058b2d *third_party/cosmo/2/signal_test.com.gz ================================================ FILE: third_party/cosmo/2/sigpending_test.com.dbg.gz.sha256 ================================================ a499c0d40e0a87a6c314e297e11f7ecd8e2f33a05d9b887dd09f72b4a16c8fda *third_party/cosmo/2/sigpending_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sigpending_test.com.gz.sha256 ================================================ 500848bbd6ea12f9ba5a93c0aa8c58393e74a979bb8f62729e51aa75353e3fe7 *third_party/cosmo/2/sigpending_test.com.gz ================================================ FILE: third_party/cosmo/2/sigprocmask_test.com.dbg.gz.sha256 ================================================ 6fd9ea7cbaa7e4eebbbfa1f30624bd83ca1e957904e4e084f9cac8cf51538b5e *third_party/cosmo/2/sigprocmask_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sigprocmask_test.com.gz.sha256 ================================================ 434706c79540ea18c2dc394960d925bfb718cf1e2b8dde1cd0ea8c2dad460cf4 *third_party/cosmo/2/sigprocmask_test.com.gz ================================================ FILE: third_party/cosmo/2/sigsetjmp_test.com.dbg.gz.sha256 ================================================ 59602543e39d1d47d9fd7467fdf0cbcd837f9e405b93cbc17f4b8100ba031ab6 *third_party/cosmo/2/sigsetjmp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sigsetjmp_test.com.gz.sha256 ================================================ 5fb6fafbd352277b6e33d0f6b2627eb053adf1123ea09c994ce495d86a9cd1e0 *third_party/cosmo/2/sigsetjmp_test.com.gz ================================================ FILE: third_party/cosmo/2/sigsuspend_test.com.dbg.gz.sha256 ================================================ fcfe6debfa632790248145f91a31526e1dfc7bb9617a74736381129b1a979bba *third_party/cosmo/2/sigsuspend_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sigsuspend_test.com.gz.sha256 ================================================ ccde77da3b71d67079ac1341131abc1243fc0141e57aab5666bc25e0719fdf28 *third_party/cosmo/2/sigsuspend_test.com.gz ================================================ FILE: third_party/cosmo/2/sigtimedwait_test.com.dbg.gz.sha256 ================================================ a25eb54d38c47b8f15f96a2809f45b7aa2e8c323fc61463c63e0d95b7bab2880 *third_party/cosmo/2/sigtimedwait_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sigtimedwait_test.com.gz.sha256 ================================================ 36857f06e1f26b814dc147cf024c446fac44e2db59f381fe64d071703703a0b3 *third_party/cosmo/2/sigtimedwait_test.com.gz ================================================ FILE: third_party/cosmo/2/sin_test.com.dbg.gz.sha256 ================================================ 1c0a57c0b0b57b7661f9d781c87613f7364ed248ccdd28cca4cbcb5c76a27d6b *third_party/cosmo/2/sin_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sin_test.com.gz.sha256 ================================================ 7960263948d384fdd1813ccbe404013a9adb5c1a142ce8ea1c4f24417c5ee321 *third_party/cosmo/2/sin_test.com.gz ================================================ FILE: third_party/cosmo/2/sincos_test.com.dbg.gz.sha256 ================================================ fac2a3e10ffc1db91dbb9eeabce8c8628c2604f22c13cb3539fa3a1c5fc83231 *third_party/cosmo/2/sincos_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sincos_test.com.gz.sha256 ================================================ c296541ac46fbc19aa4bb36077c8be239628fdcd397800603559db56fe7750c4 *third_party/cosmo/2/sincos_test.com.gz ================================================ FILE: third_party/cosmo/2/sinh_test.com.dbg.gz.sha256 ================================================ 6236bd37c535ad88f95387abc08e7da71897d22b2a1e19a83c89ce101ba4b861 *third_party/cosmo/2/sinh_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sinh_test.com.gz.sha256 ================================================ 202616dc554c689278bcae4689835817205d117d54e7e08288b4588894c559df *third_party/cosmo/2/sinh_test.com.gz ================================================ FILE: third_party/cosmo/2/sizetol_test.com.dbg.gz.sha256 ================================================ 2485143d186c5fe57062f28a5726cf0d859e47bd2da65ca22bfd1e52e4e79bc1 *third_party/cosmo/2/sizetol_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sizetol_test.com.gz.sha256 ================================================ 7510777cda51a56f23dfd4f62ca66a7e86c19af040a2f67dc1644450c0381bfa *third_party/cosmo/2/sizetol_test.com.gz ================================================ FILE: third_party/cosmo/2/sleb128_test.com.dbg.gz.sha256 ================================================ dbd47188c7968d8a043ffe8b438ee91c1399a6765bd772ea28286bef79248177 *third_party/cosmo/2/sleb128_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sleb128_test.com.gz.sha256 ================================================ 966f030d77c166c10820c47dfb3d2a3068d5493b6041dc4395278dc1cbcabce4 *third_party/cosmo/2/sleb128_test.com.gz ================================================ FILE: third_party/cosmo/2/snprintf_test.com.dbg.gz.sha256 ================================================ fddf813c5ac3a12056ea0c490584b3881f9852bedf8a1daca3e9124a6a273302 *third_party/cosmo/2/snprintf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/snprintf_test.com.gz.sha256 ================================================ 311217a01cf64278e977b8bf7a5d76e6fd9c82b759cf92b933ca66bcd7984b02 *third_party/cosmo/2/snprintf_test.com.gz ================================================ FILE: third_party/cosmo/2/socket_test.com.dbg.gz.sha256 ================================================ 61c1a8a0ba1ca92566fd643c73641d7098ca238b3b64d4ecbf60e22441bf8ea3 *third_party/cosmo/2/socket_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/socket_test.com.gz.sha256 ================================================ c6965dd0afea222dbfa75cbbb0043458323e81ffc0efe068d8f523a55f586bee *third_party/cosmo/2/socket_test.com.gz ================================================ FILE: third_party/cosmo/2/socketpair_test.com.dbg.gz.sha256 ================================================ 69caa48e75deb9b92b0fbec762d284217156949a78cd55c08fe95dec2f8479bb *third_party/cosmo/2/socketpair_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/socketpair_test.com.gz.sha256 ================================================ f4d4803d0a5d665452dd8f038b1ead1add422dc971377df42af8df5a5fe8bb91 *third_party/cosmo/2/socketpair_test.com.gz ================================================ FILE: third_party/cosmo/2/sortedints_test.com.dbg.gz.sha256 ================================================ 95379ca4379db57d852a33d3e4511849a38ba8d622365967bca36cd6fa8f5154 *third_party/cosmo/2/sortedints_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sortedints_test.com.gz.sha256 ================================================ 917a141dbeb25dc330095369052e40b2a4afbe79fb3709dd989bf956f9ec1c9d *third_party/cosmo/2/sortedints_test.com.gz ================================================ FILE: third_party/cosmo/2/spawn_test.com.dbg.gz.sha256 ================================================ 1b9281d5c0b960c89da0b8541628e24fb010c2593110cbc2e56f3152de6af7c6 *third_party/cosmo/2/spawn_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/spawn_test.com.gz.sha256 ================================================ 061560376a20c4ed09b211baedc5aa950d3b746a4169c87cb05d4fe71f912039 *third_party/cosmo/2/spawn_test.com.gz ================================================ FILE: third_party/cosmo/2/splice_test.com.dbg.gz.sha256 ================================================ c03805ca215775923d6cbc84ff45295da21fe81a0c5d0c07791649aa040351e5 *third_party/cosmo/2/splice_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/splice_test.com.gz.sha256 ================================================ 0aff112115918607083b9e197d976b2309ccc756388023a1b1dd9b442b07b24e *third_party/cosmo/2/splice_test.com.gz ================================================ FILE: third_party/cosmo/2/sprintf_s_test.com.dbg.gz.sha256 ================================================ c8ddb5ddc0d65d214e85cb3a4fb27a1265dd54b64f54dd54994e84e3670e300e *third_party/cosmo/2/sprintf_s_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sprintf_s_test.com.gz.sha256 ================================================ 8e137d0d28674d195e6bac39ebb16e13c5b5f6469d12092a434837b2a46471a6 *third_party/cosmo/2/sprintf_s_test.com.gz ================================================ FILE: third_party/cosmo/2/sqrt_test.com.dbg.gz.sha256 ================================================ 111af1e179c357558254d0e15aa63613a4b5579163ae164906659ce2a4171c5f *third_party/cosmo/2/sqrt_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sqrt_test.com.gz.sha256 ================================================ bf2447ccd775a0e1f4edbc55d2fb7e0c08a776f978d76938923a97f3df9e58b6 *third_party/cosmo/2/sqrt_test.com.gz ================================================ FILE: third_party/cosmo/2/sscanf_test.com.dbg.gz.sha256 ================================================ 0f0e8cdaf8429051c2c049d2710aa3ab411a0d58fb1b29d2c61912cdbff782c5 *third_party/cosmo/2/sscanf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sscanf_test.com.gz.sha256 ================================================ 810ce06561753783ca8764320cd81ac306664f835555745ab080f4accb9e042d *third_party/cosmo/2/sscanf_test.com.gz ================================================ FILE: third_party/cosmo/2/stackrw_test.com.dbg.gz.sha256 ================================================ c0924317f7fb5c8f3ffe75aa6d5329e283120b5bba2ee58aa498f76b92bf8a06 *third_party/cosmo/2/stackrw_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/stackrw_test.com.gz.sha256 ================================================ 24747a155a923a921d7362890cb87273df03fb30215801b2c9f19f5b790d1641 *third_party/cosmo/2/stackrw_test.com.gz ================================================ FILE: third_party/cosmo/2/stackrwx_test.com.dbg.gz.sha256 ================================================ 45c37f5598038c7c136858baa6247657df70e5ee136371a799cbc800f42cfb8d *third_party/cosmo/2/stackrwx_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/stackrwx_test.com.gz.sha256 ================================================ 10d8b5c9b97718d3c9fe2e49216f0b77c96e804c67b660299c1df1ae5b365ddc *third_party/cosmo/2/stackrwx_test.com.gz ================================================ FILE: third_party/cosmo/2/stat_test.com.dbg.gz.sha256 ================================================ e01185f1fa66d4e315d808783bdb46a64205861a09e0ca47e53472824a62dd96 *third_party/cosmo/2/stat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/stat_test.com.gz.sha256 ================================================ ae30c90bf560542460732c3c787852c7e3cb7f4f769589ae7e68d2b1910ea72a *third_party/cosmo/2/stat_test.com.gz ================================================ FILE: third_party/cosmo/2/statfs_test.com.dbg.gz.sha256 ================================================ 705750bcbdd7fef23db62023f7558dca4669ec9b7874e1571935aea8ca4bd2f6 *third_party/cosmo/2/statfs_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/statfs_test.com.gz.sha256 ================================================ 4471b8db6fae9659f8e6745d578a359a2ff6352330f96bc6421c1cf4c21dec38 *third_party/cosmo/2/statfs_test.com.gz ================================================ FILE: third_party/cosmo/2/str_test.com.dbg.gz.sha256 ================================================ ded03ed781de3f465f34818a339de8d8338071624effaa472fffa60704dffae0 *third_party/cosmo/2/str_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/str_test.com.gz.sha256 ================================================ 1fad3b777124f041bf91fabf11b4df8d946003cb0d525359dbb459d635124940 *third_party/cosmo/2/str_test.com.gz ================================================ FILE: third_party/cosmo/2/strcasecmp_test.com.dbg.gz.sha256 ================================================ cfdc1f7ab5d4bf7fc9ae60890c357a0e95081bee988bc8f891c29307adbeea63 *third_party/cosmo/2/strcasecmp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strcasecmp_test.com.gz.sha256 ================================================ 9357f1e3060fb46b40021c83a9b6d198d935409a66dce6522edce55d150f4bad *third_party/cosmo/2/strcasecmp_test.com.gz ================================================ FILE: third_party/cosmo/2/strcaseconv_test.com.dbg.gz.sha256 ================================================ 53e8418c344876b726159278d09c2d95a7a5f74000fcd376a604bc60cf69a91d *third_party/cosmo/2/strcaseconv_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strcaseconv_test.com.gz.sha256 ================================================ b590f3c389066c1f891a1d8c869137c5359ecf3c83792624fc71872847d529f1 *third_party/cosmo/2/strcaseconv_test.com.gz ================================================ FILE: third_party/cosmo/2/strcasestr_test.com.dbg.gz.sha256 ================================================ 31b00b68c794b23336bbcd5dfea2b13057792a5a353159046ec70655b289206a *third_party/cosmo/2/strcasestr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strcasestr_test.com.gz.sha256 ================================================ f2c20619172d02cc73faee7c5e6f5e9ddebf1041db9dd2f2e430957dedf93ce4 *third_party/cosmo/2/strcasestr_test.com.gz ================================================ FILE: third_party/cosmo/2/strcat_test.com.dbg.gz.sha256 ================================================ 5ece08563c698e65b7341d67e504d2e92970953e1f5b8f4c282f67ef6cea9bad *third_party/cosmo/2/strcat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strcat_test.com.gz.sha256 ================================================ 51d18fd6cd4958987e01ff830db134c24a60486d91463fae21f0c1e6312f69bf *third_party/cosmo/2/strcat_test.com.gz ================================================ FILE: third_party/cosmo/2/strchr_test.com.dbg.gz.sha256 ================================================ cf2934f816ab0eca2e1f887558844e6d5995bb5e72c515aba31e8c8b9d83a2af *third_party/cosmo/2/strchr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strchr_test.com.gz.sha256 ================================================ 684c3b22bdc8eb71856b1961a59be5cbf97a086eee3c0c12edbec39c4700086a *third_party/cosmo/2/strchr_test.com.gz ================================================ FILE: third_party/cosmo/2/strclen_test.com.dbg.gz.sha256 ================================================ 63a2a31630a45d6cecb2334ba9d3429ea7ad43fcf0702742e5c455551f0d5a62 *third_party/cosmo/2/strclen_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strclen_test.com.gz.sha256 ================================================ 0158b1c9879a57dd2784d6f74d40d097aadea81d153f983ab07e112f2136251b *third_party/cosmo/2/strclen_test.com.gz ================================================ FILE: third_party/cosmo/2/strcmp_test.com.dbg.gz.sha256 ================================================ 0fc9427474f15bd8a980ab1a080a88fe38628697e0c3096c02499faee383b8fe *third_party/cosmo/2/strcmp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strcmp_test.com.gz.sha256 ================================================ 863c10bd8f188f8d3aedd9bc43a76b7b3b6fb5cdf80526166f64800bb7052a97 *third_party/cosmo/2/strcmp_test.com.gz ================================================ FILE: third_party/cosmo/2/strcpy_test.com.dbg.gz.sha256 ================================================ 499726487cd03f7c76328adc6df54e1066ddab7229629237f7fd2c6d361d0fb7 *third_party/cosmo/2/strcpy_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strcpy_test.com.gz.sha256 ================================================ aa9a1435ff5892e4283ae7bae2d0f8e19fa2c619b90df0f781c6cf7d3b44b2b8 *third_party/cosmo/2/strcpy_test.com.gz ================================================ FILE: third_party/cosmo/2/strcspn_test.com.dbg.gz.sha256 ================================================ cea196f592ab97662d588ae9347fc0251589d39eeed132e576ddb36d5ad14a45 *third_party/cosmo/2/strcspn_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strcspn_test.com.gz.sha256 ================================================ ad75864b1859fdff3b675279634c333f27b837ae046d6dcf2bd104b90b2a4f87 *third_party/cosmo/2/strcspn_test.com.gz ================================================ FILE: third_party/cosmo/2/strdup_test.com.dbg.gz.sha256 ================================================ f0471d34c63c9748708cecb516332e8bb3c0c7f444751a15fde3391d69655ac3 *third_party/cosmo/2/strdup_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strdup_test.com.gz.sha256 ================================================ 7a757cf96971b047ec6205cfe6dc2d8957189d1e35d30b8e70a501896a3afce5 *third_party/cosmo/2/strdup_test.com.gz ================================================ FILE: third_party/cosmo/2/strerror_r_test.com.dbg.gz.sha256 ================================================ 074737f13180e4e438f1744896661c9632f4c670fa4c638f0010d2bcc0f5b48c *third_party/cosmo/2/strerror_r_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strerror_r_test.com.gz.sha256 ================================================ 407c25db3839d56e7a8a44f3f319f6aaf9d1933df8a85a10c6756c4da844cdbd *third_party/cosmo/2/strerror_r_test.com.gz ================================================ FILE: third_party/cosmo/2/strftime_test.com.dbg.gz.sha256 ================================================ ba4eb363153c02b7e95e3c389890188f2525217cd907952d93ecc6f2801f9c0f *third_party/cosmo/2/strftime_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strftime_test.com.gz.sha256 ================================================ 41c4ac71667d3843b769d8c058e78a4f005550c18bbc8c8c1dc29757ce26f92d *third_party/cosmo/2/strftime_test.com.gz ================================================ FILE: third_party/cosmo/2/stripcomponents_test.com.dbg.gz.sha256 ================================================ 899952ca12b342341a15cb2886e6bf0441894b9a939ea6ea1b6c51c4123f64c5 *third_party/cosmo/2/stripcomponents_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/stripcomponents_test.com.gz.sha256 ================================================ 84932ac4a8a44a53a972f6adf33de604a8fd6a713459dcb0a15b16260dbcc129 *third_party/cosmo/2/stripcomponents_test.com.gz ================================================ FILE: third_party/cosmo/2/stripexts_test.com.dbg.gz.sha256 ================================================ 7cd7207a8443a669d38da76f5527a821e1a885c6ff85a07b755b87134ee895e1 *third_party/cosmo/2/stripexts_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/stripexts_test.com.gz.sha256 ================================================ 47753a9501df30fb4f3ecac6e3b291a806165ece7538955d85b0273674f4b79a *third_party/cosmo/2/stripexts_test.com.gz ================================================ FILE: third_party/cosmo/2/strlcpy_test.com.dbg.gz.sha256 ================================================ 1e47e2401e3383c37c546bbf88bb4fab1ff36f65875c5620f6e32590999a811e *third_party/cosmo/2/strlcpy_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strlcpy_test.com.gz.sha256 ================================================ a9e6fe76296455fd05a9ab9ac24a1788c6858d61384bfbe08876774b2116f13e *third_party/cosmo/2/strlcpy_test.com.gz ================================================ FILE: third_party/cosmo/2/strlen_test.com.dbg.gz.sha256 ================================================ 54b269dced3e31328f09c6cbb2aa17c2e308f79d3bbdb96ca02cbf24a2e6a4f5 *third_party/cosmo/2/strlen_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strlen_test.com.gz.sha256 ================================================ 2471d44fbbfdcb7e760dd81e87f95876301ab4a1a7710fbff3ac2e092515d07c *third_party/cosmo/2/strlen_test.com.gz ================================================ FILE: third_party/cosmo/2/strnlen_test.com.dbg.gz.sha256 ================================================ 6ab12007253e4e98dddffb64cf322998305cf3222f4b36f7da01c1bc2c34df03 *third_party/cosmo/2/strnlen_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strnlen_test.com.gz.sha256 ================================================ 69104b13079f08f6c6619430519594d27e47586e0fc88de43dd0d26fdd66b31e *third_party/cosmo/2/strnlen_test.com.gz ================================================ FILE: third_party/cosmo/2/strnwidth_test.com.dbg.gz.sha256 ================================================ 16764c6f59079a43542e9f3470c3901b33fce9195d2209777194ba2d8172e104 *third_party/cosmo/2/strnwidth_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strnwidth_test.com.gz.sha256 ================================================ 6c1bb69eed505555e26ffe09b601e82501b1f825cb7e989a4e38535a56483946 *third_party/cosmo/2/strnwidth_test.com.gz ================================================ FILE: third_party/cosmo/2/strpbrk_test.com.dbg.gz.sha256 ================================================ 9a282c0bcbd1eedfb555400b3b9d6d39b3b26bf2aac34e729b8c42bc84801208 *third_party/cosmo/2/strpbrk_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strpbrk_test.com.gz.sha256 ================================================ 8c4cb441ccb4b86c2c0950813833044076f5e7a8299e1f62483d01145c6e572b *third_party/cosmo/2/strpbrk_test.com.gz ================================================ FILE: third_party/cosmo/2/strrchr_test.com.dbg.gz.sha256 ================================================ 81dd2993dea1e8200cdda9229eccd2ad98ea7906f3a160c15d3272ae5905de05 *third_party/cosmo/2/strrchr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strrchr_test.com.gz.sha256 ================================================ 2cb7b6c248bb0edadfc592314d5cd399ca35e7cdbf6118d33929061f3729bcb2 *third_party/cosmo/2/strrchr_test.com.gz ================================================ FILE: third_party/cosmo/2/strsak32_test.com.dbg.gz.sha256 ================================================ 9b58e90193f10ee7b4a731daa0b1528165df1046772519ee39c57bc1a13fd53e *third_party/cosmo/2/strsak32_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strsak32_test.com.gz.sha256 ================================================ 51ff8644af79f5fb95fb616143f24e6449178e95a25e357c2079ad2448c7367e *third_party/cosmo/2/strsak32_test.com.gz ================================================ FILE: third_party/cosmo/2/strsignal_r_test.com.dbg.gz.sha256 ================================================ 636188f85d34d506d208854fc73209970e8a3ae8f439dd344be3ace99cf6bbac *third_party/cosmo/2/strsignal_r_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strsignal_r_test.com.gz.sha256 ================================================ 2180b0a3b8b421d1bdc19014b1e2a635c93f54d4a77d0d126942b1c8fa3cb19d *third_party/cosmo/2/strsignal_r_test.com.gz ================================================ FILE: third_party/cosmo/2/strstr_test.com.dbg.gz.sha256 ================================================ 446a06192701708d69d2a1cdd04d257cc5e7a4f0e786c5a1a4c7508bd8622c5d *third_party/cosmo/2/strstr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strstr_test.com.gz.sha256 ================================================ d41186a88f8676df8a491e0221d8e08988329b1d54466d9a886fbfe43d3d96f8 *third_party/cosmo/2/strstr_test.com.gz ================================================ FILE: third_party/cosmo/2/strtod_test.com.dbg.gz.sha256 ================================================ 0c96002acc3faae07d5785d56211907cbfc4751b518f3cbd57bd4f609f07ad27 *third_party/cosmo/2/strtod_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strtod_test.com.gz.sha256 ================================================ fca4af926a0aa4c79999f7e2489212f23baac7881ae2b5dfc8cb2e9402a0396f *third_party/cosmo/2/strtod_test.com.gz ================================================ FILE: third_party/cosmo/2/strtok_r_test.com.dbg.gz.sha256 ================================================ 38cd119e2933a6eb060612e44108c5a4de418f1329b9cf8f383aa582b171200c *third_party/cosmo/2/strtok_r_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strtok_r_test.com.gz.sha256 ================================================ 76b451ff8950958308ce70e291d36f05c0c506d129e63108dc6acbe6bca6a727 *third_party/cosmo/2/strtok_r_test.com.gz ================================================ FILE: third_party/cosmo/2/strtolower_test.com.dbg.gz.sha256 ================================================ 82cbb92f4e71dc83261687c29f5549afa6b7a11bad760f61fb71ba71952ee98b *third_party/cosmo/2/strtolower_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/strtolower_test.com.gz.sha256 ================================================ 8ec03d5b03606a3d0c0ff4244ec5b0d23fe128eb04c8f477a63e6f8de594039b *third_party/cosmo/2/strtolower_test.com.gz ================================================ FILE: third_party/cosmo/2/symlinkat_test.com.dbg.gz.sha256 ================================================ 493e36aa34e78c259b5fe88419211ea4885f186eb6cd099a7d0dee74b1162871 *third_party/cosmo/2/symlinkat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/symlinkat_test.com.gz.sha256 ================================================ 8b1e62144021c3e366600071d40cddece64665e195bf164162c8017398fd3bcb *third_party/cosmo/2/symlinkat_test.com.gz ================================================ FILE: third_party/cosmo/2/sys_ptrace_test.com.dbg.gz.sha256 ================================================ 55733bfa6398f83032e02ae4557237907e053514b24028d187de8b4b1c1fa031 *third_party/cosmo/2/sys_ptrace_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/sys_ptrace_test.com.gz.sha256 ================================================ a7e767fd7c63f93e5a7655c72562ec809d2f85dc9a5779532c675ff035b828ea *third_party/cosmo/2/sys_ptrace_test.com.gz ================================================ FILE: third_party/cosmo/2/system_test.com.dbg.gz.sha256 ================================================ 0d98b15a2d6763a75559a7a576810dec05c5fadebdaa2e026e138d85f187d0dc *third_party/cosmo/2/system_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/system_test.com.gz.sha256 ================================================ dadf2f2814a3b573287ef05f3a6bd58e46592259a85588b47ed0fbc3c4bcc3a0 *third_party/cosmo/2/system_test.com.gz ================================================ FILE: third_party/cosmo/2/tan_test.com.dbg.gz.sha256 ================================================ 650da38e2d641267e0d6b58b13ea92b2c699d208c8737da2d6a729052ea3cc0c *third_party/cosmo/2/tan_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tan_test.com.gz.sha256 ================================================ 37d6cc558b9575fe5162d07305c4e942163405b5431203ab08bdcc21824d2b06 *third_party/cosmo/2/tan_test.com.gz ================================================ FILE: third_party/cosmo/2/tanh_test.com.dbg.gz.sha256 ================================================ 405de53fd60f6beeb12ece7f72b901cc6dbf0f67d5dcb3761f5631c29155f42c *third_party/cosmo/2/tanh_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tanh_test.com.gz.sha256 ================================================ 8def315d8ca21a64bd4f47ff4f842adbc3fa7747b481d8dd85f066b546f2e9ce *third_party/cosmo/2/tanh_test.com.gz ================================================ FILE: third_party/cosmo/2/tarjan_test.com.dbg.gz.sha256 ================================================ 9ed43efecf46e03923955fd540f5208efeda0b931a84d3eb8882d9fb5f11374e *third_party/cosmo/2/tarjan_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tarjan_test.com.gz.sha256 ================================================ 28887dd7fc71fd57ecf9de97bb66648e63a1f163a5c4ec72ecfab2604e68b4c9 *third_party/cosmo/2/tarjan_test.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.cbc.com.dbg.gz.sha256 ================================================ 894fab3f7608a186376cb3c98a690c33b7ae89ead0dbc6ba89b230499eaa011a *third_party/cosmo/2/test_suite_aes.cbc.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.cbc.com.gz.sha256 ================================================ 85ef9656311e876fb6000fc6842239df1baa7585e8c373fd3cbf94c34a4d40c5 *third_party/cosmo/2/test_suite_aes.cbc.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.cfb.com.dbg.gz.sha256 ================================================ 9712913da373635b9c4669f47eb96245c9d879faed1d185ee68af95ddaceb233 *third_party/cosmo/2/test_suite_aes.cfb.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.cfb.com.gz.sha256 ================================================ ef856ae59ad36e83f0001886aa7fa087152edb70f636d3c991a529fde7b78f2c *third_party/cosmo/2/test_suite_aes.cfb.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.ecb.com.dbg.gz.sha256 ================================================ 900175ad2aefea31f4debd6393f7fe200337ebdde7521fc6563ebe10312b61a5 *third_party/cosmo/2/test_suite_aes.ecb.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.ecb.com.gz.sha256 ================================================ f80e528ab2c19e7dd9a7ac84b0bc9843b53aca3a7c60260dc7b9ac2c44c319cd *third_party/cosmo/2/test_suite_aes.ecb.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.ofb.com.dbg.gz.sha256 ================================================ 407f2ee28e374d56db5a8a3218ee73774754a7339a14efaa051a0ded1e4c1f81 *third_party/cosmo/2/test_suite_aes.ofb.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.ofb.com.gz.sha256 ================================================ ccf18590dde976c4adec13de308b3121e25d01348bf1ecd851c22b001dc80de2 *third_party/cosmo/2/test_suite_aes.ofb.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.rest.com.dbg.gz.sha256 ================================================ fd49cf14394c22fc8ca0284b1163b786d54ac1b6f405dd6d127e4539cd6ec04d *third_party/cosmo/2/test_suite_aes.rest.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.rest.com.gz.sha256 ================================================ c031bf898be86893ed89237b41637c2faf2d366d0c9e7a20478b9ae42a18b039 *third_party/cosmo/2/test_suite_aes.rest.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.xts.com.dbg.gz.sha256 ================================================ fff373a956b0799b63692a1db51dca1a6002488269d9fbcc32bbd2ac0f43acf8 *third_party/cosmo/2/test_suite_aes.xts.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_aes.xts.com.gz.sha256 ================================================ de47fe92e462ae08f6be6645b37fcf1e50f734b8b3d5b9e9f20262a47bf86a7b *third_party/cosmo/2/test_suite_aes.xts.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_asn1parse.com.dbg.gz.sha256 ================================================ df475367fed6ebc5a4c90e0fa322b371ebeafcb85df76306ed9ca0c0402f7354 *third_party/cosmo/2/test_suite_asn1parse.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_asn1parse.com.gz.sha256 ================================================ faf14a16be13ec8f1a8cd6a3a660bf65146d78548931400c884f554c305e1d0b *third_party/cosmo/2/test_suite_asn1parse.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_asn1write.com.dbg.gz.sha256 ================================================ ac1a38ee95eb25c57e058922ad2085ef829b88d0ef8b29b084326055fc969a19 *third_party/cosmo/2/test_suite_asn1write.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_asn1write.com.gz.sha256 ================================================ cb00a47b20461642baec09e55346793175c34433c7995583496a5c6dc06c444c *third_party/cosmo/2/test_suite_asn1write.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_base64.com.dbg.gz.sha256 ================================================ 65cc6c19515143ddf869d23807a0ba54b72acb2ac75d1aa5ef88a0d7c6011de0 *third_party/cosmo/2/test_suite_base64.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_base64.com.gz.sha256 ================================================ fa4b67f2b9a7389bdcd857dc5aa73323672683e7ad4615cb4203be6e1fb17dc1 *third_party/cosmo/2/test_suite_base64.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_blowfish.com.dbg.gz.sha256 ================================================ 8613cf2d1c15d56aa9fbd9742c886e52c5a822449976d6e2d061c6aea54f312d *third_party/cosmo/2/test_suite_blowfish.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_blowfish.com.gz.sha256 ================================================ 6b038652bf5db4dd46a3794f0edcb5e19a47e8e4906fa0f9a6e58089024e4ef1 *third_party/cosmo/2/test_suite_blowfish.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_chacha20.com.dbg.gz.sha256 ================================================ aafc9874ba08db8655e9cf97b76d4cf9dea9f6b989150de3b71c326a844e9c9e *third_party/cosmo/2/test_suite_chacha20.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_chacha20.com.gz.sha256 ================================================ b36a06829d7c6028a07905096090fb3876e75fe3197406dcb00b49e48654284f *third_party/cosmo/2/test_suite_chacha20.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_chachapoly.com.dbg.gz.sha256 ================================================ e47f3309d28814d2f50528cc84065ba8aed63b251bfc7a8c7e4b4a3553074d25 *third_party/cosmo/2/test_suite_chachapoly.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_chachapoly.com.gz.sha256 ================================================ eaa6eb3a014b151df48aa34fe665dd4baabf514c3f0488a45e03d96fcf01fbc1 *third_party/cosmo/2/test_suite_chachapoly.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.aes.com.dbg.gz.sha256 ================================================ 6fcb85b26fc6e4f2c834e24eee82a17f9d5888d5def684a176ea69051e5ff7f7 *third_party/cosmo/2/test_suite_cipher.aes.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.aes.com.gz.sha256 ================================================ d4758026ef45385dcd7a9a1e2d6c35c5d89b2c15e181d7bf24216f52cedb2d14 *third_party/cosmo/2/test_suite_cipher.aes.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.blowfish.com.dbg.gz.sha256 ================================================ 6cc199eb3345c3db99374f127248a2244977af08ef8da5fb953e3b262e133d5d *third_party/cosmo/2/test_suite_cipher.blowfish.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.blowfish.com.gz.sha256 ================================================ b64f1bbd67c2d0b57e6f025a0f60821b2502c49e924863e1180118e9ade99bc6 *third_party/cosmo/2/test_suite_cipher.blowfish.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.ccm.com.dbg.gz.sha256 ================================================ 9e770989a32d00c5c15ce95f5f45cea0ed8087aec0aae76852a8b9e1a0040693 *third_party/cosmo/2/test_suite_cipher.ccm.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.ccm.com.gz.sha256 ================================================ 86bae6c7494e2b306ebc58962a54fad86dc1305e61a921721011d6be46269d35 *third_party/cosmo/2/test_suite_cipher.ccm.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.chacha20.com.dbg.gz.sha256 ================================================ 15268eedfa1f449947b00ebfea513e33f1914d816b228c83eabe295453f0d0f8 *third_party/cosmo/2/test_suite_cipher.chacha20.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.chacha20.com.gz.sha256 ================================================ 1836de894fa43f9924d6fca53c86329aac83821f636fdd334098950668de088f *third_party/cosmo/2/test_suite_cipher.chacha20.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.chachapoly.com.dbg.gz.sha256 ================================================ 7ff112c75aad82d4f1718ae09a1be4eea6d4fb6847e6526e880535c9a8d5f1be *third_party/cosmo/2/test_suite_cipher.chachapoly.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.chachapoly.com.gz.sha256 ================================================ fa07693949806d03e113ced0b4c50203a5aeeecf89194dbb0e63292c2abbb572 *third_party/cosmo/2/test_suite_cipher.chachapoly.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.des.com.dbg.gz.sha256 ================================================ 6c33a24e5acfd4e5d991f98526bf5df5b347412970013bda6fa030e37d471b57 *third_party/cosmo/2/test_suite_cipher.des.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.des.com.gz.sha256 ================================================ 4c09ded73b0f07cc6c30704bc7d4d1c018385edb450708d145d4d19d5734b4e3 *third_party/cosmo/2/test_suite_cipher.des.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.gcm.com.dbg.gz.sha256 ================================================ ef0174340d4a18ce45b996308dd6e71b561090a63db25b671aa791b6c32a4abb *third_party/cosmo/2/test_suite_cipher.gcm.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.gcm.com.gz.sha256 ================================================ b6a4d9f8e2c3833fc4db91bb3d0247b37d432b7bb7247e8c962df37afe24ca99 *third_party/cosmo/2/test_suite_cipher.gcm.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.misc.com.dbg.gz.sha256 ================================================ b53a2c3049f2c5b5e448cc1108af0603125d37a06b671262c24b6cd202d6c97a *third_party/cosmo/2/test_suite_cipher.misc.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.misc.com.gz.sha256 ================================================ f33386a818a8f043e82ff4f4676f3caf5c7fc79383333348d40645b3ab1b245c *third_party/cosmo/2/test_suite_cipher.misc.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.nist_kw.com.dbg.gz.sha256 ================================================ ef138326dc1cd5c6d237933c292a4021cce99219c220d870fd2beeb871943d44 *third_party/cosmo/2/test_suite_cipher.nist_kw.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.nist_kw.com.gz.sha256 ================================================ 25e49bd42eb4ebcd30ca9f8e038b491436fb9754475579f3a758267ddf0bc137 *third_party/cosmo/2/test_suite_cipher.nist_kw.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.null.com.dbg.gz.sha256 ================================================ 975c66d7d10a8a9876d89c985527067175010df28b0dd12e1e21b9f78774dcc6 *third_party/cosmo/2/test_suite_cipher.null.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.null.com.gz.sha256 ================================================ 17ab5d41bcbe8f0bc3111a097b031477d182135bad2eb1fe85807d12572b478b *third_party/cosmo/2/test_suite_cipher.null.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.padding.com.dbg.gz.sha256 ================================================ 477d11e79dc81d456e2ed5d5a0dfbfaf80377c6e0fad5538729e58e2345d552c *third_party/cosmo/2/test_suite_cipher.padding.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_cipher.padding.com.gz.sha256 ================================================ a20d4ec658cc17032b87817eb77fa14e7be9d0e9a5915945f2c3ff330fc51afb *third_party/cosmo/2/test_suite_cipher.padding.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_ctr_drbg.com.dbg.gz.sha256 ================================================ b51cac9e0b878223ba1f0778b46939d34947ee48017ea896e95d2e068922e79d *third_party/cosmo/2/test_suite_ctr_drbg.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_ctr_drbg.com.gz.sha256 ================================================ dcd6752e8f36ae0bd97b0776980eb5b43c9097aedb3c6d35e9bc9ce6ed8fb72e *third_party/cosmo/2/test_suite_ctr_drbg.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_des.com.dbg.gz.sha256 ================================================ 49d83828d5490f707562258f4317176570a54a57bccf28dc4380f63875382cde *third_party/cosmo/2/test_suite_des.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_des.com.gz.sha256 ================================================ 78f9943113cd2e5aec3e29c6184f9f99c6ee8e36856b58c3b84d71f4952e5575 *third_party/cosmo/2/test_suite_des.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_dhm.com.dbg.gz.sha256 ================================================ 08d201d1643e8e886278b49119a03fdd966bb2bb2ae323fa6944817544a44c15 *third_party/cosmo/2/test_suite_dhm.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_dhm.com.gz.sha256 ================================================ d4df29df3f0b35091550b5b1356c23a74e899039193c12f091d274521e59fe44 *third_party/cosmo/2/test_suite_dhm.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_ecdh.com.dbg.gz.sha256 ================================================ dd475853821de50b013587e76a08dbd72b1a88d9a6cce82bd33c861ba34748e7 *third_party/cosmo/2/test_suite_ecdh.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_ecdh.com.gz.sha256 ================================================ 26bee59d291de22cf4b13a6acfeff42ae5c962b99efdbdbc517c13ffcbf5aa62 *third_party/cosmo/2/test_suite_ecdh.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_ecdsa.com.dbg.gz.sha256 ================================================ c13d985b61d70496078ddec8209ff28e5519441210e002958a8961da04665c3d *third_party/cosmo/2/test_suite_ecdsa.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_ecdsa.com.gz.sha256 ================================================ bee3fdf9db9d02b4a916f51306beeb1cb4b1b1042817d3cf44f605ba1b221b5c *third_party/cosmo/2/test_suite_ecdsa.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_ecp.com.dbg.gz.sha256 ================================================ 2bc77353222fd885ba0a7fa202e2c62f54cc4f86352f299d425bbf4655409a99 *third_party/cosmo/2/test_suite_ecp.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_ecp.com.gz.sha256 ================================================ 3e1476f611051f8fb10113a9882e921eb9b5c0b3326c40311ef23c1005f49beb *third_party/cosmo/2/test_suite_ecp.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_entropy.com.dbg.gz.sha256 ================================================ 86bbdcde1fa2a2be63b80ea21bffd19aa2a160741109ec147a73e957cc1b6873 *third_party/cosmo/2/test_suite_entropy.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_entropy.com.gz.sha256 ================================================ d11be302f5b192fb4b2bcd06b7595428f6c928a5350ef0540b7c100403f36368 *third_party/cosmo/2/test_suite_entropy.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_error.com.dbg.gz.sha256 ================================================ c22d51506abda5ecc5be8eee178d3b87f8c16ea0324ca332b87851af5c2c2fcd *third_party/cosmo/2/test_suite_error.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_error.com.gz.sha256 ================================================ 8a0b55f0223fb7c51ff55e31359a2aa7fc78735f3b95ef1ee1206b710ccf0ba4 *third_party/cosmo/2/test_suite_error.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes128_de.com.dbg.gz.sha256 ================================================ f93c4b630d0a62cbb4fe5b8e4f1d1b74478b990e6fd0054febba745fc13b6546 *third_party/cosmo/2/test_suite_gcm.aes128_de.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes128_de.com.gz.sha256 ================================================ 9feb3efb18daae46b2edf45cac274866c373c54c4088d21388bc9292ba320fd5 *third_party/cosmo/2/test_suite_gcm.aes128_de.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes128_en.com.dbg.gz.sha256 ================================================ a93d30a707a4081a5297b1951e0603b146aeddbc111bc4359f68f7920600731f *third_party/cosmo/2/test_suite_gcm.aes128_en.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes128_en.com.gz.sha256 ================================================ 8fbe37baefee1497c1463c30bfe2fdbdd29005be4de70a71c2c7ec2c48922c67 *third_party/cosmo/2/test_suite_gcm.aes128_en.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes192_de.com.dbg.gz.sha256 ================================================ 725d29c76d1f1260e3450028d7814d7d74bf0e4f219a989e523a8e04a9e07604 *third_party/cosmo/2/test_suite_gcm.aes192_de.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes192_de.com.gz.sha256 ================================================ 4fb0a16802c8a7ec81a49f6ac70715bad4eef77849958e0c7b875838bdee2e78 *third_party/cosmo/2/test_suite_gcm.aes192_de.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes192_en.com.dbg.gz.sha256 ================================================ 1eb290aa263c9eb0bd5cd1e97b8213f4c11d6bde63f66f9e8fdbb5cf50905a55 *third_party/cosmo/2/test_suite_gcm.aes192_en.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes192_en.com.gz.sha256 ================================================ 7cdf8cd41236bd644110490f90b17013c99a569e1e2e065ac8fcbf2777fb6847 *third_party/cosmo/2/test_suite_gcm.aes192_en.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes256_de.com.dbg.gz.sha256 ================================================ 46f2a120ee328552c3d028a60dbeb3806bf2e67a67c6d8612de34cba65aa873b *third_party/cosmo/2/test_suite_gcm.aes256_de.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes256_de.com.gz.sha256 ================================================ 11e13598fd23569046e2897e3fd2027f405de48d24c1b024ab39cd69c50a97d7 *third_party/cosmo/2/test_suite_gcm.aes256_de.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes256_en.com.dbg.gz.sha256 ================================================ 0608eef00f9d8a7c0d915dcfc8d66f5a6fa5678dd1c76c8832eda33ec75c2fae *third_party/cosmo/2/test_suite_gcm.aes256_en.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.aes256_en.com.gz.sha256 ================================================ ae1ca6400387c91b9990d9c832147966feb62a5ef549e9bf44bf26351d972dfc *third_party/cosmo/2/test_suite_gcm.aes256_en.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.misc.com.dbg.gz.sha256 ================================================ 2801f04c0a84f23a4fd53079cd9af8b15cf568a28c43cf1e2b0d91503c03a74c *third_party/cosmo/2/test_suite_gcm.misc.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_gcm.misc.com.gz.sha256 ================================================ 1408e57f7d12edb532015f7b46ac8ee5adf140769beca9932145d8d4c0bc1e62 *third_party/cosmo/2/test_suite_gcm.misc.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_hkdf.com.dbg.gz.sha256 ================================================ b9358479dd205b4a0f306c1585b8aa6a7262cc0b0d167414cf8e288e6d050173 *third_party/cosmo/2/test_suite_hkdf.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_hkdf.com.gz.sha256 ================================================ 3d49b88013e2fc991caa404830c7c7d87dbf3af7d3d7c7b96638079fee55b79e *third_party/cosmo/2/test_suite_hkdf.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.misc.com.dbg.gz.sha256 ================================================ ecebd3cdd7cf31dc3df5dc2bf7b01ef28e26b015d3963d34a7e863edaad40203 *third_party/cosmo/2/test_suite_hmac_drbg.misc.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.misc.com.gz.sha256 ================================================ bc1dfae4b46b31376306e044f1fe5374b8a47b27d643551a603c36d35ae9a4fb *third_party/cosmo/2/test_suite_hmac_drbg.misc.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.no_reseed.com.dbg.gz.sha256 ================================================ e5357685088b05e9b03c133d47e7c3fbf43d82b21b1fe577e1e0e97e2898c5cc *third_party/cosmo/2/test_suite_hmac_drbg.no_reseed.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.no_reseed.com.gz.sha256 ================================================ a1f60eb97eb9686c67202664bf7b3e522c02bbecf26e7ff85def4734fec10fae *third_party/cosmo/2/test_suite_hmac_drbg.no_reseed.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.nopr.com.dbg.gz.sha256 ================================================ a9ca22ac108cd807e56b389d8e0af6c90036af0e170bf3286e622bcdf3cb636e *third_party/cosmo/2/test_suite_hmac_drbg.nopr.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.nopr.com.gz.sha256 ================================================ c18bf8137abf43385360043b9196ed0c81f23c31966b8d3261cbc9881590e790 *third_party/cosmo/2/test_suite_hmac_drbg.nopr.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.pr.com.dbg.gz.sha256 ================================================ 7871587e9853ba38a21869eb40b0d258e1bc8f6555b92876604a09a71265d2e9 *third_party/cosmo/2/test_suite_hmac_drbg.pr.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_hmac_drbg.pr.com.gz.sha256 ================================================ 63fa5e629f52d759e50cbe54b9e9764d3a9da590e8c801a9a58574934a0d206a *third_party/cosmo/2/test_suite_hmac_drbg.pr.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_md.com.dbg.gz.sha256 ================================================ 8da5330ec3e5b72a73afb8f654cbd92830a39c69b9bcc8e7cf11424651e3dd42 *third_party/cosmo/2/test_suite_md.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_md.com.gz.sha256 ================================================ c21b65e7830f0472bee74a8aaef8ca9cfa902fa9e38b9a3379d7fdf6f420c800 *third_party/cosmo/2/test_suite_md.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_mdx.com.dbg.gz.sha256 ================================================ b170332f148ec143fe70b46a31bc5179c6f54cad2ebbfdd365ff0071bb718d12 *third_party/cosmo/2/test_suite_mdx.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_mdx.com.gz.sha256 ================================================ 8097c1a58f35d3c44d9753e10daeb2d5e41e47fefbe47ddd8fddd023e4496e0b *third_party/cosmo/2/test_suite_mdx.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_memory_buffer_alloc.com.dbg.gz.sha256 ================================================ 663020496a1e887988f5d2984fee5bdf83d4a9085437372584fce59d004e3588 *third_party/cosmo/2/test_suite_memory_buffer_alloc.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_memory_buffer_alloc.com.gz.sha256 ================================================ 76001252ed21c20fc551fc85ab672db7e037cffec592b412fc6c9dcac26404df *third_party/cosmo/2/test_suite_memory_buffer_alloc.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_mpi.com.dbg.gz.sha256 ================================================ 5f81ff565e415381e39c6e8a83bccf6c71cb427d699802f57ef9814f7ef5ed46 *third_party/cosmo/2/test_suite_mpi.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_mpi.com.gz.sha256 ================================================ 8a6dcc7caf054fadf088fe751dda009ec8e94f9a9c7cc3d751a08a864feba7a7 *third_party/cosmo/2/test_suite_mpi.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_net.com.dbg.gz.sha256 ================================================ 8b3b0a39b2ba7db6af5fc2bd665b4314af468c916dab6701c9d79e004ec5d442 *third_party/cosmo/2/test_suite_net.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_net.com.gz.sha256 ================================================ 604a687fe7a1754b1bb76a60d008c0abf371b0403adfada1dee0250249902e21 *third_party/cosmo/2/test_suite_net.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_nist_kw.com.dbg.gz.sha256 ================================================ 85ae2696ce045b3182409fdc9d177895d8115d581d887c36b7c7ba3a82cad660 *third_party/cosmo/2/test_suite_nist_kw.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_nist_kw.com.gz.sha256 ================================================ 3573f6ff68389a670e4fe6d49542a41b22a8206c6e49d6988da607ac2f6c773b *third_party/cosmo/2/test_suite_nist_kw.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_oid.com.dbg.gz.sha256 ================================================ b2831aa2667484cbeefffdb0b16fc75de9f3b8a0833a4a5ad09467eaf40cc45f *third_party/cosmo/2/test_suite_oid.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_oid.com.gz.sha256 ================================================ bcee392d443a401434881dada76f07f47a9e761c54eb4a542794e2046a8a2890 *third_party/cosmo/2/test_suite_oid.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_pem.com.dbg.gz.sha256 ================================================ c61fc25dbf9eafbc9465d851f44a8b0193928066ce2caac029318417f18f97d3 *third_party/cosmo/2/test_suite_pem.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_pem.com.gz.sha256 ================================================ 278802f87a33e8721184ded72bbfaa1c967aa86265e51e9744a3a025fa20a202 *third_party/cosmo/2/test_suite_pem.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_pk.com.dbg.gz.sha256 ================================================ 67a171acd8950cd45fec51b93c947f6f7ef249b57d8acb3b11afa9ad30058820 *third_party/cosmo/2/test_suite_pk.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_pk.com.gz.sha256 ================================================ 325a8266957c475769682131cbeaa18f61cbdb4ee4bfdd796303dff9f3440a49 *third_party/cosmo/2/test_suite_pk.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkcs1_v15.com.dbg.gz.sha256 ================================================ 443fae48e511b3248aa23af4bf302d49911865444446db9fa4de4fdf8f52ac94 *third_party/cosmo/2/test_suite_pkcs1_v15.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkcs1_v15.com.gz.sha256 ================================================ 59e9db28eddb0634db95aa24e4a751c3ee00351c36d5f1ab5cd0e309d901ec5b *third_party/cosmo/2/test_suite_pkcs1_v15.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkcs1_v21.com.dbg.gz.sha256 ================================================ bf3970a2a905a810e49a7efd8946d80c8cde78bdf6755689396947aa1c74e4e7 *third_party/cosmo/2/test_suite_pkcs1_v21.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkcs1_v21.com.gz.sha256 ================================================ 3b47bc730bc0edb13822c82e5d84dfba424e655d9756d03b426958d7dec679ad *third_party/cosmo/2/test_suite_pkcs1_v21.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkcs5.com.dbg.gz.sha256 ================================================ 09dc26ffad20edeca9aa8026094a1b40baa4097a5aae12d05a356e00573ecb01 *third_party/cosmo/2/test_suite_pkcs5.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkcs5.com.gz.sha256 ================================================ 2439c701673bbf4b6641a495b8ba1adfe96b3c54e798da6d803670177fc04239 *third_party/cosmo/2/test_suite_pkcs5.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkparse.com.dbg.gz.sha256 ================================================ 0e92e4c45c6ea07592a30eb23867bfe0618779b68b0306b373446620b78fc62a *third_party/cosmo/2/test_suite_pkparse.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkparse.com.gz.sha256 ================================================ 5a9ca5de49e6cf52337abd053b8338bd0e5be6f907faffd9db971e29d798fb80 *third_party/cosmo/2/test_suite_pkparse.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkwrite.com.dbg.gz.sha256 ================================================ d61ff6776b99e4ece99415e138f9b8eb36590ce25b11cca72bb9dc6098f062fa *third_party/cosmo/2/test_suite_pkwrite.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_pkwrite.com.gz.sha256 ================================================ 4a6aa7684d06758651777882de8355ebb75d5db3d02c28e50ca3384dab4e13a7 *third_party/cosmo/2/test_suite_pkwrite.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_poly1305.com.dbg.gz.sha256 ================================================ 3d547c4d3ff9899f215c8ac8c78708854feb5bb0e83c800ab179df3df5c9a1c2 *third_party/cosmo/2/test_suite_poly1305.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_poly1305.com.gz.sha256 ================================================ 7f3a04b03aecb53228975b38f09c8d5d9fc7b206b5fdb646955e4b192186cebb *third_party/cosmo/2/test_suite_poly1305.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_random.com.dbg.gz.sha256 ================================================ 76bc16fde4881d11c0ab6bb8f019d07544ff46d6e2304bae545f670121fa2883 *third_party/cosmo/2/test_suite_random.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_random.com.gz.sha256 ================================================ d081021d4f45d3fdb1c2284444889e4fa055d10e05e8ce11b752ca55d262a969 *third_party/cosmo/2/test_suite_random.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_rsa.com.dbg.gz.sha256 ================================================ 13bdef2f6ad8b7706998b8b576874978c0d5f007dce231ba021ea799721bd12b *third_party/cosmo/2/test_suite_rsa.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_rsa.com.gz.sha256 ================================================ d014f1cf1ce9ef4a7f5024c1ad42bb43569bb305b201f94487539588489eb801 *third_party/cosmo/2/test_suite_rsa.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_shax.com.dbg.gz.sha256 ================================================ 3f56df8e6e534ad179b177f00501e703de348547665e96e7bc1db72d3b98e6fb *third_party/cosmo/2/test_suite_shax.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_shax.com.gz.sha256 ================================================ 997418f17fdb60e15ee2a582db59b8dc717fcb7e0f3f1811faa8016be5238eba *third_party/cosmo/2/test_suite_shax.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_ssl.com.dbg.gz.sha256 ================================================ 630d5953b1ba28c8e670b1e6b235afdb3a87470cfa00514d0e113cda173e1e72 *third_party/cosmo/2/test_suite_ssl.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_ssl.com.gz.sha256 ================================================ 7b8e5b99641eaaea78c96148b9d6dfcd026387db6660cca1dff2dc5d24e3b964 *third_party/cosmo/2/test_suite_ssl.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_timing.com.dbg.gz.sha256 ================================================ 5c8a232d61afb2d649d14c9e1b45e06089383f4ca7e43b7db48881dcad259d83 *third_party/cosmo/2/test_suite_timing.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_timing.com.gz.sha256 ================================================ b7816b70b64fe1001ff6d016397eb8853d7cd56a93786f1e30b56eff8a0d7e1b *third_party/cosmo/2/test_suite_timing.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_version.com.dbg.gz.sha256 ================================================ 18636ab02cf6e140ea7293fc04c8d996b5639a27c8464af4ad9a6905ad7d34e9 *third_party/cosmo/2/test_suite_version.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_version.com.gz.sha256 ================================================ 88ae6c179987f88c07cde43e01a6fe16adf5154bb2967532dcda8c53bb89adb2 *third_party/cosmo/2/test_suite_version.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_x509parse.com.dbg.gz.sha256 ================================================ 8d834d75c857a7346e20eb6c829ec2aeef4b936ad9b02a4aefcbafd4729790ba *third_party/cosmo/2/test_suite_x509parse.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_x509parse.com.gz.sha256 ================================================ a028cea72d7d2c8f8817f47ea753ce532e51d3f07a140d559ab337be9fc1e496 *third_party/cosmo/2/test_suite_x509parse.com.gz ================================================ FILE: third_party/cosmo/2/test_suite_x509write.com.dbg.gz.sha256 ================================================ 63a6d1f9bcd6477e9befa6d1e79dce045d9b955dbf4d56709e7b403f057c229d *third_party/cosmo/2/test_suite_x509write.com.dbg.gz ================================================ FILE: third_party/cosmo/2/test_suite_x509write.com.gz.sha256 ================================================ c2421fc678e51a0a9cadd4306b4a13edbdb7b63c0d2b305fb7972f27aa415559 *third_party/cosmo/2/test_suite_x509write.com.gz ================================================ FILE: third_party/cosmo/2/tgamma_test.com.dbg.gz.sha256 ================================================ 1b6fc586c3c35d3e749c5350334fc2b1a067e779d38045eb2383befc948aed51 *third_party/cosmo/2/tgamma_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tgamma_test.com.gz.sha256 ================================================ dd5a46eb7c0013c49dc65dbad0cbc3885541322b33f7f901adc31bc13f71d732 *third_party/cosmo/2/tgamma_test.com.gz ================================================ FILE: third_party/cosmo/2/timevaltofiletime_test.com.dbg.gz.sha256 ================================================ 1912ba360a7a62963c0883213a48cd339297e7881bd6a168cb29c9cf5e449ccd *third_party/cosmo/2/timevaltofiletime_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/timevaltofiletime_test.com.gz.sha256 ================================================ fd566c2a22bfd87fc969e6107d040abd1b62e7e346946464a37e26a3d28a975e *third_party/cosmo/2/timevaltofiletime_test.com.gz ================================================ FILE: third_party/cosmo/2/tkill_test.com.dbg.gz.sha256 ================================================ cd6f2498e6550da6a9fed5cf999a74080adb2e826b6885fec33342ddd223ce9b *third_party/cosmo/2/tkill_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tkill_test.com.gz.sha256 ================================================ bca5e12542e3e75e8f638a2c712eb3b74da55304bcfdb22ceb1f7b4d6990f379 *third_party/cosmo/2/tkill_test.com.gz ================================================ FILE: third_party/cosmo/2/tls_test.com.dbg.gz.sha256 ================================================ f5b260a658f9af9e169571b10de0f99ab83e1be54d3e1f6803f852a7fd75f6ee *third_party/cosmo/2/tls_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tls_test.com.gz.sha256 ================================================ 695ee274f42353e6b6e16f5c08e96c46ea7ab34372c82df833ccee470ae9e795 *third_party/cosmo/2/tls_test.com.gz ================================================ FILE: third_party/cosmo/2/tmpfile_test.com.dbg.gz.sha256 ================================================ 00cb6ccc04fdd65c58055d564d8abb9e4b2546d932b6f77a607b9a0fe2e156db *third_party/cosmo/2/tmpfile_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tmpfile_test.com.gz.sha256 ================================================ 9ad581ea7e7942a8bead4de0d53eca1058e7df64172ee21d5a0ebb793084d040 *third_party/cosmo/2/tmpfile_test.com.gz ================================================ FILE: third_party/cosmo/2/tokenbucket_test.com.dbg.gz.sha256 ================================================ bacb2f4117b167e6eab4e005cd3db43908d1657547135db99dc5f9df0587540b *third_party/cosmo/2/tokenbucket_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tokenbucket_test.com.gz.sha256 ================================================ f332239aa78b436e538c076c8198adc09fbcf575b6c38ae849a480a6de5b0d4c *third_party/cosmo/2/tokenbucket_test.com.gz ================================================ FILE: third_party/cosmo/2/towupper_test.com.dbg.gz.sha256 ================================================ dc2c37fcb03824a1a6f8e36b4551779827bd819a80eef83548f8518e644d784c *third_party/cosmo/2/towupper_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/towupper_test.com.gz.sha256 ================================================ a83d18f56db13e2409214b536a2f4156c1a91734736cc46a86c95329addbe779 *third_party/cosmo/2/towupper_test.com.gz ================================================ FILE: third_party/cosmo/2/tpenc_test.com.dbg.gz.sha256 ================================================ 83cf663f5d22841ca1e14193d9a0cf6e9c49621ab145232f931f4cab540dcfc9 *third_party/cosmo/2/tpenc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tpenc_test.com.gz.sha256 ================================================ e25363afa322de025d549222d99579e932dbcb106a0792bb1702ed5a50137329 *third_party/cosmo/2/tpenc_test.com.gz ================================================ FILE: third_party/cosmo/2/tprecode16to8_test.com.dbg.gz.sha256 ================================================ 2a77d3e20bba860c4dcb38f488cabe2aae39246184bf3f154a28b8c7cca5fe79 *third_party/cosmo/2/tprecode16to8_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tprecode16to8_test.com.gz.sha256 ================================================ 4e63f2d25029bce0051d3b1d84cb6b76b3c692c8bf8f0f4e130210af2daf48b2 *third_party/cosmo/2/tprecode16to8_test.com.gz ================================================ FILE: third_party/cosmo/2/tprecode8to16_test.com.dbg.gz.sha256 ================================================ e3f2f4df80d9d6e32c60654abb509164269bdde4a2b7409026e0e8b7a337c8d3 *third_party/cosmo/2/tprecode8to16_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/tprecode8to16_test.com.gz.sha256 ================================================ 27b4cdd3fe71061bec52ab61105f2a338dc68ad61169c0bcb44aeabd2ec38dcc *third_party/cosmo/2/tprecode8to16_test.com.gz ================================================ FILE: third_party/cosmo/2/trunc_test.com.dbg.gz.sha256 ================================================ b5407aca1f459deb5c7724209d5abf0ac9fe25eef17efdf3c46d8acd2b12c29e *third_party/cosmo/2/trunc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/trunc_test.com.gz.sha256 ================================================ 039bf561776a6f964d78060be3a003dd26bfb6c58da707a1ac6aa79dbdf3096e *third_party/cosmo/2/trunc_test.com.gz ================================================ FILE: third_party/cosmo/2/ttymove_test.com.dbg.gz.sha256 ================================================ 1b65f82a176f70a29008c08e3a32bcf74f2d5b5980024036a6ee0e94b4abe55d *third_party/cosmo/2/ttymove_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ttymove_test.com.gz.sha256 ================================================ 2d20e82c2b90a32e93acb94cade8162fdb44cc49e22b233d8e92866cf3ca07d2 *third_party/cosmo/2/ttymove_test.com.gz ================================================ FILE: third_party/cosmo/2/ttyraster_test.com.dbg.gz.sha256 ================================================ e3123ede3b785e36523ece448dc4fe2279693827bd953e3431ef5bac7ecc9be8 *third_party/cosmo/2/ttyraster_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ttyraster_test.com.gz.sha256 ================================================ 42c3d7c6778fae09bead0556dc8f26fb557831cbac5d70dabeb9f620e430bd3c *third_party/cosmo/2/ttyraster_test.com.gz ================================================ FILE: third_party/cosmo/2/uleb128_test.com.dbg.gz.sha256 ================================================ fd7f33d8e187c236ab17991ee473839dec44409dc58e0521d1877597534108ba *third_party/cosmo/2/uleb128_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/uleb128_test.com.gz.sha256 ================================================ 72ad186035a0b1994e77748e8ecedba2d893877fed81bd1156cd99dd8e05037c *third_party/cosmo/2/uleb128_test.com.gz ================================================ FILE: third_party/cosmo/2/uleb64_test.com.dbg.gz.sha256 ================================================ 44ab6af3ad420f722fa3685647271a5a384135bf11c44254ba71c22ac395c05e *third_party/cosmo/2/uleb64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/uleb64_test.com.gz.sha256 ================================================ 3559bc8e932573db19e336298aa105f0467c535175023aad04de7b7c97a40136 *third_party/cosmo/2/uleb64_test.com.gz ================================================ FILE: third_party/cosmo/2/unchunk_test.com.dbg.gz.sha256 ================================================ a58f3e665fdb001ef2b3aa97a693694769b990a99f33a896b6f1eb9c2c657a80 *third_party/cosmo/2/unchunk_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/unchunk_test.com.gz.sha256 ================================================ 07f16d7ece1d0d66801c990ef92011c39a10a08e4d07fa62f377d22679c277f5 *third_party/cosmo/2/unchunk_test.com.gz ================================================ FILE: third_party/cosmo/2/underlong_test.com.dbg.gz.sha256 ================================================ 07e66419cd8515dfaf4236997673c6d948d4b258c8d42c3774ec1e2c8866f8e9 *third_party/cosmo/2/underlong_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/underlong_test.com.gz.sha256 ================================================ 53ff56228de731f47bc9b1a0291a82b3ee70363a920043374c4be46089563309 *third_party/cosmo/2/underlong_test.com.gz ================================================ FILE: third_party/cosmo/2/ungetc_test.com.dbg.gz.sha256 ================================================ 47ea3dcac3d176deb6c8766c46d326eaf6bf6025594ba312820b40a1bbaa2ada *third_party/cosmo/2/ungetc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ungetc_test.com.gz.sha256 ================================================ 3d19b5e80d553926923fd473f590e8be2304f1add6c1aeda71bb28fd915ac46a *third_party/cosmo/2/ungetc_test.com.gz ================================================ FILE: third_party/cosmo/2/unlinkat_test.com.dbg.gz.sha256 ================================================ 81dfa3a2ff04f43c7fcd3ffeec74ec82dc10791354f93c4e89c75cb02c37c37d *third_party/cosmo/2/unlinkat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/unlinkat_test.com.gz.sha256 ================================================ d4416f72722cc9a16fb645901bd18d8d7fe9d9cf781df78b3f8b6f82dfbcde9a *third_party/cosmo/2/unlinkat_test.com.gz ================================================ FILE: third_party/cosmo/2/unveil_test.com.dbg.gz.sha256 ================================================ e1f61f13e36128c709b6642e28b0ef049f4bf2d6c0dfc1494104286a59e77d98 *third_party/cosmo/2/unveil_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/unveil_test.com.gz.sha256 ================================================ 9c1e881df86827a03c52b8a845c7462a6ee43605d1dcebdb3507bf30f75c3789 *third_party/cosmo/2/unveil_test.com.gz ================================================ FILE: third_party/cosmo/2/utf16to32_test.com.dbg.gz.sha256 ================================================ 2ba8ee0411f8b58475b689fe9ceb8e8292601c86235d3e80ca46d6b105180c26 *third_party/cosmo/2/utf16to32_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/utf16to32_test.com.gz.sha256 ================================================ 0ebc15cd47f3dd0b410dbe82fbfe3e0ad5eb72d9578aac5e24ec969997d1e095 *third_party/cosmo/2/utf16to32_test.com.gz ================================================ FILE: third_party/cosmo/2/utf16to8_test.com.dbg.gz.sha256 ================================================ cb0f288cfbb19b19632f324cedc865de78a34fadae2478a8f77eabcbb72f630e *third_party/cosmo/2/utf16to8_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/utf16to8_test.com.gz.sha256 ================================================ 50f5208329824169f178169ae6b4423fe2940c9f1ab6b2d92db41fb4b4911c44 *third_party/cosmo/2/utf16to8_test.com.gz ================================================ FILE: third_party/cosmo/2/utf8to16_test.com.dbg.gz.sha256 ================================================ a0382141e77e92bc0ce0284bf5675ebe5b03f11f45d34007c19707dbc61e3148 *third_party/cosmo/2/utf8to16_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/utf8to16_test.com.gz.sha256 ================================================ c6ca3c9c6ae0dd0b2669d8ff1e64a919aa4b9e1d30556eadca4da378695f04d9 *third_party/cosmo/2/utf8to16_test.com.gz ================================================ FILE: third_party/cosmo/2/utf8to32_test.com.dbg.gz.sha256 ================================================ 50153631c8f89da7aff695c15caf365270d2aef02efec83ddf848cd79f8ef75d *third_party/cosmo/2/utf8to32_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/utf8to32_test.com.gz.sha256 ================================================ 5d685a8917c31f2537779c5cffa3203de83134a6d010781d1111c1fc4454f50d *third_party/cosmo/2/utf8to32_test.com.gz ================================================ FILE: third_party/cosmo/2/vappendf_test.com.dbg.gz.sha256 ================================================ d533d5c3568a97a5e42ff83752fbb794425fbe21f480ed1579c2e73b0ed424ec *third_party/cosmo/2/vappendf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/vappendf_test.com.gz.sha256 ================================================ e7a7bde5d0b83adaaed7487ae0eaf0ac52f6eee5767d40a1d3bd4da8e54eec94 *third_party/cosmo/2/vappendf_test.com.gz ================================================ FILE: third_party/cosmo/2/vfork_test.com.dbg.gz.sha256 ================================================ c770dabf6b912964d96efd6f17b9b12667d07957707da51a0b84d7c00849d213 *third_party/cosmo/2/vfork_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/vfork_test.com.gz.sha256 ================================================ 6e172163551d58dbfde9599c0a0a55c83e4ad2e454cb394782cfb0607e51e3d1 *third_party/cosmo/2/vfork_test.com.gz ================================================ FILE: third_party/cosmo/2/visualizecontrolcodes_test.com.dbg.gz.sha256 ================================================ b5ffdd4a4fd7a4dea093bd79a4a125ea4a1b8463c18cd1a50659aec804abb53f *third_party/cosmo/2/visualizecontrolcodes_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/visualizecontrolcodes_test.com.gz.sha256 ================================================ ce8bfd7d65e92b52fbf7503c8770b432e91ac9e6779a3a95c1defdf3125556ab *third_party/cosmo/2/visualizecontrolcodes_test.com.gz ================================================ FILE: third_party/cosmo/2/wait_test.com.dbg.gz.sha256 ================================================ 201feb4fd3d58eb83ebf812b33a5e2f00cacad7e49fdd5a59658c8f47e3d83d9 *third_party/cosmo/2/wait_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/wait_test.com.gz.sha256 ================================================ 936f8c6c4de9600e8a502f4d6476ca52b1ea08397c79ca38bfc249ff36d8d6a1 *third_party/cosmo/2/wait_test.com.gz ================================================ FILE: third_party/cosmo/2/wcsrchr_test.com.dbg.gz.sha256 ================================================ 9adc19fce6a309ba7c1b022bd24c9ae7beea134bfd321e07e6cb5918692ac5fd *third_party/cosmo/2/wcsrchr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/wcsrchr_test.com.gz.sha256 ================================================ 6b49c698d4d9413ef34c3c5d2adc0ab5fb517f6c7948d09bc2bbb4b70086e663 *third_party/cosmo/2/wcsrchr_test.com.gz ================================================ FILE: third_party/cosmo/2/wcwidth_test.com.dbg.gz.sha256 ================================================ 663cf6df3e51fd16e64e8f25e931169f5e045b8f0a1ca3e1e9008542dbbe1a3c *third_party/cosmo/2/wcwidth_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/wcwidth_test.com.gz.sha256 ================================================ 668a688432f62cf1da7685ae3ea12a2570cd071ae9442d7af8949724d960f87d *third_party/cosmo/2/wcwidth_test.com.gz ================================================ FILE: third_party/cosmo/2/windex_test.com.dbg.gz.sha256 ================================================ c00a4de71a0aa3795b63c3b3cea957202a1a28fae1dc3a011767cf9c0bfc120d *third_party/cosmo/2/windex_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/windex_test.com.gz.sha256 ================================================ 521f1e75cca7f961adcf7df843f9b319a2cf00d490bd9bc1f432f5e4d7bd82ae *third_party/cosmo/2/windex_test.com.gz ================================================ FILE: third_party/cosmo/2/wmemrchr_test.com.dbg.gz.sha256 ================================================ 4ba81018fc32b1a6059befc53a198f30e178686bf59bfa46b959533dff04d834 *third_party/cosmo/2/wmemrchr_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/wmemrchr_test.com.gz.sha256 ================================================ 0ac4aa8efc300a03d0df5180371dba5219c6eb7e57daa714fb8fb1a1d9eec5ac *third_party/cosmo/2/wmemrchr_test.com.gz ================================================ FILE: third_party/cosmo/2/write_test.com.dbg.gz.sha256 ================================================ 4307db7fbd1fb6591c3d0d538b6ef4bb3c70e75054d8aaa300c46d9f3fb2a269 *third_party/cosmo/2/write_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/write_test.com.gz.sha256 ================================================ cd55393d4feb2f8552c62f0c9046f58f6f59641da04b3ac65bbec5c44d596a99 *third_party/cosmo/2/write_test.com.gz ================================================ FILE: third_party/cosmo/2/wut_test.com.dbg.gz.sha256 ================================================ 74785e7da5a5304bb13baeb1a01754c01cadc62447788e271d2c7bac5bfdaacc *third_party/cosmo/2/wut_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/wut_test.com.gz.sha256 ================================================ d1229f490c74fad405047f34a3fb7a9a7bb9195418dbadb1e118b485a7fda8d7 *third_party/cosmo/2/wut_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_binary_test.com.dbg.gz.sha256 ================================================ 3aed3fd84d2ac5f9c7e07085fe05969cb89e83b7aaec8010f58449a211408d27 *third_party/cosmo/2/x86ild_popular_binary_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_binary_test.com.gz.sha256 ================================================ 403f155bdc4a1d6cdf272aa797e3583db0c0e1064c4947912d96dbe88fcd03fd *third_party/cosmo/2/x86ild_popular_binary_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_cmov_test.com.dbg.gz.sha256 ================================================ 59172e35f0f04d5fe74f555531ac424728fd955d19fdaa3142bd6b5a309c5298 *third_party/cosmo/2/x86ild_popular_cmov_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_cmov_test.com.gz.sha256 ================================================ 6960c4c5f5919415987174dd6c4d707ac68f626c8ac8c9b1cd5b034d3af4e3c9 *third_party/cosmo/2/x86ild_popular_cmov_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i186_test.com.dbg.gz.sha256 ================================================ d321ccf3fab3caca8d71055510fc2c8fe8c20abe879f4d4e153c298f37156ae4 *third_party/cosmo/2/x86ild_popular_i186_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i186_test.com.gz.sha256 ================================================ a55ed616cde3b0131cbb31c51bfac39fe5aac636ed4b8e0f06807e75790f8589 *third_party/cosmo/2/x86ild_popular_i186_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i386_test.com.dbg.gz.sha256 ================================================ 470d2e34faa02b74a784b5daf8be33efc001582d7b28279bab11f732e4ef5587 *third_party/cosmo/2/x86ild_popular_i386_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i386_test.com.gz.sha256 ================================================ 4f5f60fad01d9520dd4fea9e7f90b47466b549ffd74c27cb310b618e9dbff767 *third_party/cosmo/2/x86ild_popular_i386_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i86_2_test.com.dbg.gz.sha256 ================================================ da1491258fdf8b1f341cd27ff0b3b03fc9e502b63f7ee4b06c72b084440e9c71 *third_party/cosmo/2/x86ild_popular_i86_2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i86_2_test.com.gz.sha256 ================================================ b6b7142752599028107e2bcfe09ff5d96bef48cfd6e00c36749be9c7af243984 *third_party/cosmo/2/x86ild_popular_i86_2_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i86_test.com.dbg.gz.sha256 ================================================ f9a3c7cdb4704384a4d1721cdac7f3a33ed316dde4845d9a15347af3d0d4b335 *third_party/cosmo/2/x86ild_popular_i86_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_i86_test.com.gz.sha256 ================================================ cedb5794ab14720249952fad9e8e33fb994f906ae82112d60aa5a771a617a17b *third_party/cosmo/2/x86ild_popular_i86_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_logical_test.com.dbg.gz.sha256 ================================================ 31b61a8d2484313011c5afe36a8ff6b54680e6d0a2787ae55c1d23954ead86f0 *third_party/cosmo/2/x86ild_popular_logical_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_logical_test.com.gz.sha256 ================================================ 0669bf20adac429d308918ff0cb1511a6ff4b6a7b68e570f084504f0214b3228 *third_party/cosmo/2/x86ild_popular_logical_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_misc_test.com.dbg.gz.sha256 ================================================ 3560d9eddc281105a446e2314eb47701275b53d2567cb71b3908e7f027967830 *third_party/cosmo/2/x86ild_popular_misc_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_popular_misc_test.com.gz.sha256 ================================================ 2c22c4288d85ed52bb36331eb662b01cd6ca3fbdda1b23544a92fd310af22290 *third_party/cosmo/2/x86ild_popular_misc_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_test.com.dbg.gz.sha256 ================================================ 7cf9c5fbbd3a0794a7ccd236e2e5c611c25c3af9401ea5d284482cacdeeb09aa *third_party/cosmo/2/x86ild_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_test.com.gz.sha256 ================================================ a1d1c63884fd17d5568c59c6d4665889196f73e09b796b22eb4440382a3c3f62 *third_party/cosmo/2/x86ild_test.com.gz ================================================ FILE: third_party/cosmo/2/x86ild_widenop_test.com.dbg.gz.sha256 ================================================ 21139b14268e5176dccfc2b665e3774448510080f226af0495972c0717525319 *third_party/cosmo/2/x86ild_widenop_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/x86ild_widenop_test.com.gz.sha256 ================================================ fe52c7bbfebbff769803a3bb29da4f72fe9b3f46c8e7600c20870cbbacc0c372 *third_party/cosmo/2/x86ild_widenop_test.com.gz ================================================ FILE: third_party/cosmo/2/xasprintf_test.com.dbg.gz.sha256 ================================================ d923f4af4447cbad70fe467cb802cbc471ad55f4b4ccdefd8aede8539ad3a525 *third_party/cosmo/2/xasprintf_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/xasprintf_test.com.gz.sha256 ================================================ 219e3e17929f4588ee7b5f57b8df2e06d4bb2052d184af244e820c0bde8a8cfe *third_party/cosmo/2/xasprintf_test.com.gz ================================================ FILE: third_party/cosmo/2/xfixpath_test.com.dbg.gz.sha256 ================================================ 1dc6eeb24596455a96b9ae6b223c4772713fa40533e42fd94157f3e5154a5219 *third_party/cosmo/2/xfixpath_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/xfixpath_test.com.gz.sha256 ================================================ 5b112114c873294e5b6a8d1f86cedcd4296a5965f8a1aadc84e22c39a809fa72 *third_party/cosmo/2/xfixpath_test.com.gz ================================================ FILE: third_party/cosmo/2/xjoinpaths_test.com.dbg.gz.sha256 ================================================ b0fef3f6717e7bcd5373f9ae357fc87a96b24c83ef003d5e76ba87029ca3fc40 *third_party/cosmo/2/xjoinpaths_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/xjoinpaths_test.com.gz.sha256 ================================================ 7846eed399d0b8d04f999c80b4a72c7e3392de700d657bb984e3468b19488037 *third_party/cosmo/2/xjoinpaths_test.com.gz ================================================ FILE: third_party/cosmo/2/xlaterrno_test.com.dbg.gz.sha256 ================================================ 4bb5edfd06081fa1a55cf65ff1e9da054629ac3e1e95596b150bcae96a8e8a92 *third_party/cosmo/2/xlaterrno_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/xlaterrno_test.com.gz.sha256 ================================================ c1e6a6366ed4fd5517154bfac96f8251694151dbbe2cbd4f8978255b407ada17 *third_party/cosmo/2/xlaterrno_test.com.gz ================================================ FILE: third_party/cosmo/2/xslurp_test.com.dbg.gz.sha256 ================================================ 26558eeb04fbef59eb443f01b712da27d318c08040f09cbe641a620e886e8641 *third_party/cosmo/2/xslurp_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/xslurp_test.com.gz.sha256 ================================================ b3795004d6ca354e31046fbea86e5429e38b47cb037af2d96fdd1257622259ab *third_party/cosmo/2/xslurp_test.com.gz ================================================ FILE: third_party/cosmo/2/xstrcat_test.com.dbg.gz.sha256 ================================================ dbf09670f259bebd3587433f47ae886b77800e3ccb9264624a7224412e8f15c0 *third_party/cosmo/2/xstrcat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/xstrcat_test.com.gz.sha256 ================================================ 6c2cbef7b693cc80c4d110081c844bb39afcbd89163b2e2a59f6b4dab3184126 *third_party/cosmo/2/xstrcat_test.com.gz ================================================ FILE: third_party/cosmo/2/ycbcr2rgb2_test.com.dbg.gz.sha256 ================================================ 5f04d38fb47cec33c4608b108f0d7aa4fc09e202d8b82b9d0026d79e16a51cd6 *third_party/cosmo/2/ycbcr2rgb2_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/ycbcr2rgb2_test.com.gz.sha256 ================================================ 435a51434a0b48cb8a7e65ba6178efad77412f149bb77ec2d03acb63a09d660d *third_party/cosmo/2/ycbcr2rgb2_test.com.gz ================================================ FILE: third_party/cosmo/2/zleb64_test.com.dbg.gz.sha256 ================================================ 8ba8873c4b190f3dd113a336b6a89b567d60263e1a3a48a85aa22154693a39fc *third_party/cosmo/2/zleb64_test.com.dbg.gz ================================================ FILE: third_party/cosmo/2/zleb64_test.com.gz.sha256 ================================================ aa8159a3dea1b1c9bf8fe552d81f2444367e9be0f5695f8759d7845813a42d5b *third_party/cosmo/2/zleb64_test.com.gz ================================================ FILE: third_party/cosmo/3/sqlite_test.com.dbg.gz.sha256 ================================================ 70b4ee4307743a80dc09efe6eae9d157b25fd0281d40393b5c030216d23c8179 *third_party/cosmo/3/sqlite_test.com.dbg.gz ================================================ FILE: third_party/cosmo/3/sqlite_test.com.gz.sha256 ================================================ e55a9f5146ab68c658c7ebc3b60dbe9c92dcba40fbb091bc332be1337e1734b1 *third_party/cosmo/3/sqlite_test.com.gz ================================================ FILE: third_party/cosmo/4/dtoa_test.com.dbg.gz.sha256 ================================================ 5cf3cd60c45255ecc226dcdc368a688c66cfb69b47a3165c9aa4c277370f07df *third_party/cosmo/4/dtoa_test.com.dbg.gz ================================================ FILE: third_party/cosmo/4/dtoa_test.com.gz.sha256 ================================================ 02d94cc824a11db7f0e2f8c4517e2f05284dfe981ece0a2b2ea51de73b05d8df *third_party/cosmo/4/dtoa_test.com.gz ================================================ FILE: third_party/cosmo/4/writev_test.com.dbg.gz.sha256 ================================================ 7831aca9eff86dcbe76bd517d401097b9fa5cd8e57161478b4e0bf308c6eab5a *third_party/cosmo/4/writev_test.com.dbg.gz ================================================ FILE: third_party/cosmo/4/writev_test.com.gz.sha256 ================================================ 4c85486b04e1b50b58715afe544cecbf35ad2e40a5f1987383026ea1e6a1ba6a *third_party/cosmo/4/writev_test.com.gz ================================================ FILE: third_party/cosmo/5/pipe_test.com.dbg.gz.sha256 ================================================ 53c1954479cb53b9f020fde8c1b056ffbfa0067e9538f12f5ce73a8a95b20290 *third_party/cosmo/5/pipe_test.com.dbg.gz ================================================ FILE: third_party/cosmo/5/pipe_test.com.gz.sha256 ================================================ 9aa7d5b7a9c5ce3b487a92ec8ab81d90f36ed8b3c80e0ac60c57bcd50eff4f9f *third_party/cosmo/5/pipe_test.com.gz ================================================ FILE: third_party/cosmo/5/sigaction_test.com.dbg.gz.sha256 ================================================ 79f804fce956d13bf35cca5d7f3aa6cffc85bcd2e324bba00c6c70f86b0cd949 *third_party/cosmo/5/sigaction_test.com.dbg.gz ================================================ FILE: third_party/cosmo/5/sigaction_test.com.gz.sha256 ================================================ 0e4f327d3b22bd05d2c418eaaf7f1f5799f8014135fc0a1fda1eda52fae81ac5 *third_party/cosmo/5/sigaction_test.com.gz ================================================ FILE: third_party/cosmo/5/unix_test.com.dbg.gz.sha256 ================================================ 699146f4bed6416e91ffd213b254ec223862da0722f999a15f3d2c4ab82ed3d0 *third_party/cosmo/5/unix_test.com.dbg.gz ================================================ FILE: third_party/cosmo/5/unix_test.com.gz.sha256 ================================================ 69fb7f47c553600f417e364d97c7d2ae7e7ae4474db30a23437dacef2358e0b0 *third_party/cosmo/5/unix_test.com.gz ================================================ FILE: third_party/cosmo/7/munmap_test.com.dbg.gz.sha256 ================================================ 62c4375a79ca6826bdcf1c82125a5e40857a03d6371cc054e8f1f1cf32069cd5 *third_party/cosmo/7/munmap_test.com.dbg.gz ================================================ FILE: third_party/cosmo/7/munmap_test.com.gz.sha256 ================================================ 216def82234c8a7641cca6b0b3f5e08cfd5c2e5bf172136d94e6a295875445df *third_party/cosmo/7/munmap_test.com.gz ================================================ FILE: third_party/cosmo/7/utimensat_test.com.dbg.gz.sha256 ================================================ b7bdbc50e324f4830b78bb5b48d0179e02420ab2b66c28699c8958b9e985c037 *third_party/cosmo/7/utimensat_test.com.dbg.gz ================================================ FILE: third_party/cosmo/7/utimensat_test.com.gz.sha256 ================================================ f594da2ceb9997e50a14a1f39ba2927a292b40aae762a71f5b68eb091d2aa06f *third_party/cosmo/7/utimensat_test.com.gz ================================================ FILE: third_party/cosmo/8/ftruncate_test.com.dbg.gz.sha256 ================================================ daf10d74b893612404b51e2d672311604c683070ca3fdb6510941e450c31eeb0 *third_party/cosmo/8/ftruncate_test.com.dbg.gz ================================================ FILE: third_party/cosmo/8/ftruncate_test.com.gz.sha256 ================================================ e1e43ab58345eeca0f02ff6ae7814221d7cba39153fc2982a08e292925847211 *third_party/cosmo/8/ftruncate_test.com.gz ================================================ FILE: third_party/cosmo/8/intrin_test.com.dbg.gz.sha256 ================================================ 9b6e74924cb619aac4c1e4a775c610b3739260034a35580f2d3f3d8d80ea28ac *third_party/cosmo/8/intrin_test.com.dbg.gz ================================================ FILE: third_party/cosmo/8/intrin_test.com.gz.sha256 ================================================ 127622ee2fe636c4b491e524e4b4082f144ce7eeb5dd5ec896f78f4f86063249 *third_party/cosmo/8/intrin_test.com.gz ================================================ FILE: third_party/cosmo/cosmo.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ .PRECIOUS: third_party/cosmo/%.gz third_party/cosmo/%.gz: third_party/cosmo/%.gz.sha256 o/tool/sha256sum curl -so $@ https://justine.storage.googleapis.com/cosmotests/$(subst third_party/cosmo/,,$@) o/tool/sha256sum -c $< .PRECIOUS: third_party/cosmo/%.com.dbg third_party/cosmo/%.com.dbg: third_party/cosmo/%.com.dbg.gz gzip -dc <$< >$@ chmod +x $@ .PRECIOUS: third_party/cosmo/%.com third_party/cosmo/%.com: third_party/cosmo/%.com.gz gzip -dc <$< >$@ chmod +x $@ o/$(MODE)/third_party/cosmo/%.com.ok: \ third_party/cosmo/%.com \ third_party/cosmo/%.com.dbg \ o/$(MODE)/blink/blink $(VM) @mkdir -p $(@D) o/$(MODE)/blink/blink $< @touch $@ COSMO_TESTS = \ o/$(MODE)/third_party/cosmo/8/intrin_test.com.ok \ o/$(MODE)/third_party/cosmo/2/lockscale_test.com.ok \ o/$(MODE)/third_party/cosmo/2/palignr_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pmulhrsw_test.com.ok \ o/$(MODE)/third_party/cosmo/2/mulaw_test.com.ok \ o/$(MODE)/third_party/cosmo/2/nanosleep_test.com.ok \ o/$(MODE)/third_party/cosmo/2/clock_nanosleep_test.com.ok \ o/$(MODE)/third_party/cosmo/2/palandprintf_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pshuf_test.com.ok \ o/$(MODE)/third_party/cosmo/2/popcnt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/kprintf_test.com.ok \ o/$(MODE)/third_party/cosmo/2/memmem_test.com.ok \ o/$(MODE)/third_party/cosmo/2/memcmp_test.com.ok \ o/$(MODE)/third_party/cosmo/2/memory_test.com.ok \ o/$(MODE)/third_party/cosmo/2/memrchr_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parsecidr_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parsecontentlength_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parseforwarded_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parsehoststxt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parsehttpdatetime_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parsehttpmessage_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parsehttprange_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parseip_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parseresolvconf_test.com.ok \ o/$(MODE)/third_party/cosmo/2/parseurl_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pascalifydnsname_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pcmpstr_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pingpong_test.com.ok \ o/$(MODE)/third_party/cosmo/2/prototxt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/rand64_test.com.ok \ o/$(MODE)/third_party/cosmo/2/qsort_test.com.ok \ o/$(MODE)/third_party/cosmo/2/regex_test.com.ok \ o/$(MODE)/third_party/cosmo/2/renameat_test.com.ok \ o/$(MODE)/third_party/cosmo/2/atoi_test.com.ok \ o/$(MODE)/third_party/cosmo/2/resolvehostsreverse_test.com.ok \ o/$(MODE)/third_party/cosmo/2/resolvehoststxt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/reverse_test.com.ok \ o/$(MODE)/third_party/cosmo/2/rgb2ansi_test.com.ok \ o/$(MODE)/third_party/cosmo/2/rngset_test.com.ok \ o/$(MODE)/third_party/cosmo/2/round_test.com.ok \ o/$(MODE)/third_party/cosmo/2/roundup2log_test.com.ok \ o/$(MODE)/third_party/cosmo/2/roundup2pow_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sad16x8n_test.com.ok \ o/$(MODE)/third_party/cosmo/2/scalevolume_test.com.ok \ o/$(MODE)/third_party/cosmo/2/secp384r1_test.com.ok \ o/$(MODE)/third_party/cosmo/2/putenv_test.com.ok \ o/$(MODE)/third_party/cosmo/2/note_test.com.ok \ o/$(MODE)/third_party/cosmo/2/mu_test.com.ok \ o/$(MODE)/third_party/cosmo/2/servicestxt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/setitimer_test.com.ok \ o/$(MODE)/third_party/cosmo/2/setlocale_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sincos_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sinh_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sizetol_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sleb128_test.com.ok \ o/$(MODE)/third_party/cosmo/2/snprintf_test.com.ok \ o/$(MODE)/third_party/cosmo/2/alu_test.com.ok \ o/$(MODE)/third_party/cosmo/2/bsu_test.com.ok \ o/$(MODE)/third_party/cosmo/2/divmul_test.com.ok \ o/$(MODE)/third_party/cosmo/2/test_suite_ecp.com.ok \ o/$(MODE)/third_party/cosmo/2/dll_test.com.ok \ o/$(MODE)/third_party/cosmo/2/asmdown_test.com.ok \ o/$(MODE)/third_party/cosmo/2/asin_test.com.ok \ o/$(MODE)/third_party/cosmo/2/atan2_test.com.ok \ o/$(MODE)/third_party/cosmo/2/argon2_test.com.ok \ o/$(MODE)/third_party/cosmo/2/counter_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pthread_detach_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pthread_mutex_lock_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pthread_mutex_lock2_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pthread_spin_lock_test.com.ok \ o/$(MODE)/third_party/cosmo/2/cescapec_test.com.ok \ o/$(MODE)/third_party/cosmo/2/clock_gettime_test.com.ok \ o/$(MODE)/third_party/cosmo/2/cas_test.com.ok \ o/$(MODE)/third_party/cosmo/2/bilinearscale_test.com.ok \ o/$(MODE)/third_party/cosmo/2/access_test.com.ok \ o/$(MODE)/third_party/cosmo/2/a64l_test.com.ok \ o/$(MODE)/third_party/cosmo/2/_timespec_test.com.ok \ o/$(MODE)/third_party/cosmo/2/zleb64_test.com.ok \ o/$(MODE)/third_party/cosmo/2/xslurp_test.com.ok \ o/$(MODE)/third_party/cosmo/2/chdir_test.com.ok \ o/$(MODE)/third_party/cosmo/2/mkdir_test.com.ok \ o/$(MODE)/third_party/cosmo/2/unlinkat_test.com.ok \ o/$(MODE)/third_party/cosmo/2/makedirs_test.com.ok \ o/$(MODE)/third_party/cosmo/2/dirstream_test.com.ok \ o/$(MODE)/third_party/cosmo/2/bitscan_test.com.ok \ o/$(MODE)/third_party/cosmo/2/commandv_test.com.ok \ o/$(MODE)/third_party/cosmo/2/closefrom_test.com.ok \ o/$(MODE)/third_party/cosmo/2/ecvt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/division_test.com.ok \ o/$(MODE)/third_party/cosmo/2/test_suite_aes.cbc.com.ok \ o/$(MODE)/third_party/cosmo/2/test_suite_cipher.gcm.com.ok \ o/$(MODE)/third_party/cosmo/2/test_suite_ctr_drbg.com.ok \ o/$(MODE)/third_party/cosmo/2/test_suite_entropy.com.ok \ o/$(MODE)/third_party/cosmo/2/test_suite_mpi.com.ok \ o/$(MODE)/third_party/cosmo/2/test_suite_md.com.ok \ o/$(MODE)/third_party/cosmo/2/crc32_test.com.ok \ o/$(MODE)/third_party/cosmo/2/crc32c_test.com.ok \ o/$(MODE)/third_party/cosmo/2/crc32z_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sigsetjmp_test.com.ok \ o/$(MODE)/third_party/cosmo/2/escapehtml_test.com.ok \ o/$(MODE)/third_party/cosmo/2/escapeurlparam_test.com.ok \ o/$(MODE)/third_party/cosmo/2/escapejsstringliteral_test.com.ok \ o/$(MODE)/third_party/cosmo/2/erf_test.com.ok \ o/$(MODE)/third_party/cosmo/2/encodebase64_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fabs_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fgets_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fileexists_test.com.ok \ o/$(MODE)/third_party/cosmo/2/floor_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fmemopen_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fmt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fputc_test.com.ok \ o/$(MODE)/third_party/cosmo/2/gamma_test.com.ok \ o/$(MODE)/third_party/cosmo/2/tgamma_test.com.ok \ o/$(MODE)/third_party/cosmo/2/gclongjmp_test.com.ok \ o/$(MODE)/third_party/cosmo/2/getcwd_test.com.ok \ o/$(MODE)/third_party/cosmo/2/gz_test.com.ok \ o/$(MODE)/third_party/cosmo/2/ilogb_test.com.ok \ o/$(MODE)/third_party/cosmo/2/imaxdiv_test.com.ok \ o/$(MODE)/third_party/cosmo/2/inv3_test.com.ok \ o/$(MODE)/third_party/cosmo/2/iso8601_test.com.ok \ o/$(MODE)/third_party/cosmo/2/itsatrap_test.com.ok \ o/$(MODE)/third_party/cosmo/2/mu_starvation_test.com.ok \ o/$(MODE)/third_party/cosmo/2/open_test.com.ok \ o/$(MODE)/third_party/cosmo/2/stat_test.com.ok \ o/$(MODE)/third_party/cosmo/2/stackrwx_test.com.ok \ o/$(MODE)/third_party/cosmo/2/clone_test.com.ok \ o/$(MODE)/third_party/cosmo/2/cv_test.com.ok \ o/$(MODE)/third_party/cosmo/4/writev_test.com.ok \ o/$(MODE)/third_party/cosmo/3/sqlite_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sched_yield_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pwrite_test.com.ok \ o/$(MODE)/third_party/cosmo/2/read_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pread_test.com.ok \ o/$(MODE)/third_party/cosmo/2/preadv_test.com.ok \ o/$(MODE)/third_party/cosmo/2/nsync_test.com.ok \ o/$(MODE)/third_party/cosmo/2/mt19937_test.com.ok \ o/$(MODE)/third_party/cosmo/2/modrm_test.com.ok \ o/$(MODE)/third_party/cosmo/2/measureentropy_test.com.ok \ o/$(MODE)/third_party/cosmo/2/malloc_test.com.ok \ o/$(MODE)/third_party/cosmo/2/ftell_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fseeko_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fputs_test.com.ok \ o/$(MODE)/third_party/cosmo/5/pipe_test.com.ok \ o/$(MODE)/third_party/cosmo/2/arena_test.com.ok \ o/$(MODE)/third_party/cosmo/2/acos_test.com.ok \ o/$(MODE)/third_party/cosmo/2/getintegercoefficients8_test.com.ok \ o/$(MODE)/third_party/cosmo/2/atan_test.com.ok \ o/$(MODE)/third_party/cosmo/2/bextra_test.com.ok \ o/$(MODE)/third_party/cosmo/2/cbrt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/clock_getres_test.com.ok \ o/$(MODE)/third_party/cosmo/2/copysign_test.com.ok \ o/$(MODE)/third_party/cosmo/2/cos_test.com.ok \ o/$(MODE)/third_party/cosmo/2/cosh_test.com.ok \ o/$(MODE)/third_party/cosmo/2/complex_test.com.ok \ o/$(MODE)/third_party/cosmo/2/countbits_test.com.ok \ o/$(MODE)/third_party/cosmo/2/cv_wait_example_test.com.ok \ o/$(MODE)/third_party/cosmo/2/expm1_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fgetln_test.com.ok \ o/$(MODE)/third_party/cosmo/2/getcontext_test.com.ok \ o/$(MODE)/third_party/cosmo/2/getenv_test.com.ok \ o/$(MODE)/third_party/cosmo/8/ftruncate_test.com.ok \ o/$(MODE)/third_party/cosmo/2/tmpfile_test.com.ok \ o/$(MODE)/third_party/cosmo/2/select_test.com.ok \ o/$(MODE)/third_party/cosmo/7/utimensat_test.com.ok \ o/$(MODE)/third_party/cosmo/2/readlinkat_test.com.ok \ o/$(MODE)/third_party/cosmo/2/signal_test.com.ok \ o/$(MODE)/third_party/cosmo/2/tkill_test.com.ok \ o/$(MODE)/third_party/cosmo/2/getdelim_test.com.ok \ o/$(MODE)/third_party/cosmo/2/getgroups_test.com.ok \ o/$(MODE)/third_party/cosmo/2/dup_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sem_timedwait_test.com.ok \ o/$(MODE)/third_party/cosmo/2/lockipc_test.com.ok \ o/$(MODE)/third_party/cosmo/2/socket_test.com.ok \ o/$(MODE)/third_party/cosmo/5/unix_test.com.ok \ o/$(MODE)/third_party/cosmo/2/daemon_test.com.ok \ o/$(MODE)/third_party/cosmo/2/execve_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sigpending_test.com.ok \ o/$(MODE)/third_party/cosmo/2/fork_test.com.ok \ o/$(MODE)/third_party/cosmo/2/setsockopt_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sigsuspend_test.com.ok \ o/$(MODE)/third_party/cosmo/2/lock2_test.com.ok \ o/$(MODE)/third_party/cosmo/2/lock_test.com.ok \ o/$(MODE)/third_party/cosmo/5/sigaction_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pthread_create_test.com.ok \ o/$(MODE)/third_party/cosmo/2/pthread_exit_test.com.ok \ o/$(MODE)/third_party/cosmo/2/readansi_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sendrecvmsg_test.com.ok \ o/$(MODE)/third_party/cosmo/2/lseek_test.com.ok \ o/$(MODE)/third_party/cosmo/2/mmap_test.com.ok # munmap_test triggers SIGSEGV on purpose, making it fail on asan # TODO(jart): Make this work on asan ifneq ($(MODE), asan) COSMO_TESTS += o/$(MODE)/third_party/cosmo/7/munmap_test.com.ok endif # write_test is broken on Cygwin due to RLIMIT_FSIZE # TODO(jart): Why do the other ones flake on Cygwin? ifneq ($(HOST_OS), Cygwin) COSMO_TESTS += \ o/$(MODE)/third_party/cosmo/4/dtoa_test.com.ok \ o/$(MODE)/third_party/cosmo/2/write_test.com.ok \ o/$(MODE)/third_party/cosmo/2/once_test.com.ok endif o/$(MODE)/third_party/cosmo: $(COSMO_TESTS) @mkdir -p $(@D) @touch $@ PROBLEMATIC_TESTS = \ o/$(MODE)/third_party/cosmo/2/sem_open_test.com.ok \ o/$(MODE)/third_party/cosmo/2/sigprocmask_test.com.ok DARWIN_PROBLEMATIC_TESTS = \ o/$(MODE)/third_party/cosmo/2/sched_getaffinity_test.com.ok \ o/$(MODE)/third_party/cosmo/2/backtrace_test.com.ok o/$(MODE)/third_party/cosmo/emulates: \ o/$(MODE)/aarch64/third_party/cosmo/8/intrin_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/palandprintf_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/divmul_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/test_suite_ecp.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/lockscale_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/palignr_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/pmulhrsw_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/pshuf_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/alu_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/bsu_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/pthread_mutex_lock2_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/pthread_mutex_lock_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/pthread_spin_lock_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/sincos_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/round_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/kprintf_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/snprintf_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/once_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/mu_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/note_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/counter_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/dll_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/secp384r1_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/parsehttpmessage_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/parseurl_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/parseip_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/parsehttprange_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/pcmpstr_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/rand64_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/cescapec_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/clock_gettime_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/cas_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/bilinearscale_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/access_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/a64l_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/_timespec_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/zleb64_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/xslurp_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/chdir_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/mkdir_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/unlinkat_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/makedirs_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/dirstream_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/bitscan_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/commandv_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/closefrom_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/ecvt_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/division_test.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/test_suite_aes.cbc.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/test_suite_cipher.gcm.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/test_suite_ctr_drbg.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/test_suite_entropy.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/test_suite_md.com.emulates \ o/$(MODE)/aarch64/third_party/cosmo/2/execve_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/8/intrin_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/palandprintf_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/divmul_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/lockscale_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/palignr_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/pmulhrsw_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/pshuf_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/pthread_mutex_lock2_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/pthread_mutex_lock_test.com.emulates \ o/$(MODE)/mips64el/third_party/cosmo/2/pthread_spin_lock_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/8/intrin_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/palandprintf_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/divmul_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/lockscale_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/palignr_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/pmulhrsw_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/pshuf_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/pthread_mutex_lock2_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/pthread_mutex_lock_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/pthread_spin_lock_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/sincos_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/round_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/kprintf_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/snprintf_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/once_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/note_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/counter_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/dll_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/secp384r1_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/parsehttpmessage_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/parseurl_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/parseip_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/parsehttprange_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/pcmpstr_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/rand64_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/cescapec_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/clock_gettime_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/cas_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/bilinearscale_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/access_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/a64l_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/_timespec_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/zleb64_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/xslurp_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/chdir_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/mkdir_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/unlinkat_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/makedirs_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/dirstream_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/bitscan_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/commandv_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/closefrom_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/ecvt_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/division_test.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/test_suite_aes.cbc.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/test_suite_cipher.gcm.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/test_suite_ctr_drbg.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/test_suite_entropy.com.emulates \ o/$(MODE)/s390x/third_party/cosmo/2/test_suite_md.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/8/intrin_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/palandprintf_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/divmul_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/lockscale_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/palignr_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/pmulhrsw_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/pshuf_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/pthread_mutex_lock2_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/pthread_mutex_lock_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/pthread_spin_lock_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/sincos_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/round_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/kprintf_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/snprintf_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/once_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/note_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/counter_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/dll_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/secp384r1_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/parsehttpmessage_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/parseurl_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/parseip_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/parsehttprange_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/pcmpstr_test.com.emulates \ o/$(MODE)/powerpc64le/third_party/cosmo/2/rand64_test.com.emulates @mkdir -p $(@D) @touch $@ ================================================ FILE: third_party/elks/README ================================================ DESCRIPTION ELKS distribution images ORIGIN fd1440.img ELKS v0.6.0 floppy image https://github.com/jbruchon/elks Built using blink16.config GPL v2 License ================================================ FILE: third_party/freedos/README ================================================ DESCRIPTION FreeDOS distribution images ORIGIN freedos13.img FreeDOS v1.3 floppy image https://www.freedos.org/download/ FD13-FloppyEdition.zip GPL v2 License ================================================ FILE: third_party/gameoflife/README.md ================================================ # Game Of Life This is an implementation of Conway's game of life that runs in x86_64 bare metal freestanding environment. ### Origin ### Author [Amey Narkhede](https://github.com/glitzflitz) ### License GPL v2.0 ================================================ FILE: third_party/games/README ================================================ DESCRIPTION Various boot sector games ORIGIN basic.bin BootBASIC https://github.com/nanochess/bootBASIC/basic.img BSD-2-Clause License fbird.bin F-Bird https://github.com/nanochess/fbird ntetros.bin TetrOS https://github.com/daniel-e/tetros/tree/master/tetros.img MIT License ================================================ FILE: third_party/gcc/2/x86_64-linux-musl__mips64-linux-musl__g++-9.4.0.tar.xz.sha256 ================================================ bc9b58b9e466a7cb32acaf09cc8af482667a6539ea5f91d2b846a04d67328077 *third_party/gcc/2/x86_64-linux-musl__mips64-linux-musl__g++-9.4.0.tar.xz ================================================ FILE: third_party/gcc/2/x86_64-linux-musl__powerpc64le-linux-musl__g++-9.2.0.tar.xz.sha256 ================================================ fcd0a7d73d441451ac7aee9231b515bc571a895603391f8f92099c9a41090676 *third_party/gcc/2/x86_64-linux-musl__powerpc64le-linux-musl__g++-9.2.0.tar.xz ================================================ FILE: third_party/gcc/gcc.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ third_party/gcc/%.xz: third_party/gcc/%.xz.sha256 o/tool/sha256sum curl -so $@ https://justine.storage.googleapis.com/compilers/$(subst third_party/gcc/,,$@) o/tool/sha256sum -c $< o/$(MODE)/i486/%.o: %.c o/third_party/gcc/i486/bin/i486-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/i486/bin/i486-linux-musl-gcc -static -Werror $(filter-out -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/i486/%.o: %.s o/third_party/gcc/i486/bin/i486-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/i486/bin/i486-linux-musl-as -o $@ $< o/$(MODE)/i486/%.o: %.S o/third_party/gcc/i486/bin/i486-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/i486/bin/i486-linux-musl-gcc $(CPPFLAGS) $(CPPFLAGS_STATIC) -c -o $@ $< o/$(MODE)/x86_64/%.o: %.c o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc -static -Werror $(filter-out -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/x86_64/%.o: %.s o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/x86_64/bin/x86_64-linux-musl-as -o $@ $< o/$(MODE)/x86_64/%.o: %.S o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc $(CPPFLAGS) $(CPPFLAGS_STATIC) -c -o $@ $< o/$(MODE)/x86_64-gcc48/%.o: %.c o/third_party/gcc/x86_64-gcc48/bin/x86_64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/x86_64-gcc48/bin/x86_64-linux-musl-gcc -static -Werror $(filter-out -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/x86_64-gcc48/%.o: %.S o/third_party/gcc/x86_64-gcc48/bin/x86_64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/x86_64-gcc48/bin/x86_64-linux-musl-gcc $(CPPFLAGS) $(CPPFLAGS_STATIC) -c -o $@ $< o/$(MODE)/x86_64-gcc49/%.o: %.c o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc -static -Werror $(filter-out -fcf-protection=%,$(CFLAGS)) -Wno-unused-value $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/x86_64-gcc49/%.o: %.S o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc $(CPPFLAGS) $(CPPFLAGS_STATIC) -c -o $@ $< o/$(MODE)/m68k/%.o: %.c o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/arm/%.o: %.c o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/aarch64/%.o: %.c o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc -static -Werror $(filter-out -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/riscv64/%.o: %.c o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/mips/%.o: %.c o/third_party/gcc/mips/bin/mips-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/mips/bin/mips-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/mipsel/%.o: %.c o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/mips64/%.o: %.c o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/mips64el/%.o: %.c o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/s390x/%.o: %.c o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/microblaze/%.o: %.c o/third_party/gcc/microblaze/bin/microblaze-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/microblaze/bin/microblaze-linux-musl-gcc -static -Werror $(filter-out -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/powerpc/%.o: %.c o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/$(MODE)/powerpc64le/%.o: %.c o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc $(VM) @mkdir -p $(@D) $(VM) o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc -static -Werror $(filter-out -mtune=generic -fcf-protection=%,$(CFLAGS)) $(CPPFLAGS) $(CPPFLAGS_STATIC) $(TARGET_ARCH) -c -o $@ $< o/third_party/gcc/i486/bin/i486-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__i486-linux-musl__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/i486 tar -C o/third_party/gcc/i486 -xJf $< touch $@ o/third_party/gcc/m68k/bin/m68k-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__m68k-linux-musl__gcc-5.3.0.tar.xz mkdir -p o/third_party/gcc/m68k tar -C o/third_party/gcc/m68k -xJf $< touch $@ o/third_party/gcc/x86_64/bin/x86_64-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/x86_64 tar -C o/third_party/gcc/x86_64 -xJf $< touch $@ o/third_party/gcc/x86_64-gcc48/bin/x86_64-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__gcc-4.8.5.tar.xz mkdir -p o/third_party/gcc/x86_64-gcc48 tar -C o/third_party/gcc/x86_64-gcc48 -xJf $< touch $@ o/third_party/gcc/x86_64-gcc49/bin/x86_64-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__g++-4.9.4.tar.xz mkdir -p o/third_party/gcc/x86_64-gcc49 tar -C o/third_party/gcc/x86_64-gcc49 -xJf $< touch $@ o/third_party/gcc/arm/bin/arm-linux-musleabi-gcc: \ third_party/gcc/x86_64-linux-musl__arm-linux-musleabi__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/arm tar -C o/third_party/gcc/arm -xJf $< touch $@ o/third_party/gcc/aarch64/bin/aarch64-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__aarch64-linux-musl__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/aarch64 tar -C o/third_party/gcc/aarch64 -xJf $< touch $@ o/third_party/gcc/riscv64/bin/riscv64-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__riscv64-linux-musl__gcc-9.2.0.tar.xz mkdir -p o/third_party/gcc/riscv64 tar -C o/third_party/gcc/riscv64 -xJf $< touch $@ o/third_party/gcc/mips/bin/mips-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__mips-linux-musl__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/mips tar -C o/third_party/gcc/mips -xJf $< touch $@ o/third_party/gcc/mipsel/bin/mipsel-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__mipsel-linux-musl__g++-9.2.0.tar.xz mkdir -p o/third_party/gcc/mipsel tar -C o/third_party/gcc/mipsel -xJf $< touch $@ o/third_party/gcc/mips64/bin/mips64-linux-musl-gcc: \ third_party/gcc/2/x86_64-linux-musl__mips64-linux-musl__g++-9.4.0.tar.xz mkdir -p o/third_party/gcc/mips64 tar -C o/third_party/gcc/mips64 -xJf $< touch $@ o/third_party/gcc/mips64el/bin/mips64el-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__mips64el-linux-musl__gcc-5.3.0.tar.xz mkdir -p o/third_party/gcc/mips64el tar -C o/third_party/gcc/mips64el -xJf $< touch $@ o/third_party/gcc/s390x/bin/s390x-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__s390x-linux-musl__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/s390x tar -C o/third_party/gcc/s390x -xJf $< touch $@ o/third_party/gcc/microblaze/bin/microblaze-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__microblaze-linux-musl__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/microblaze tar -C o/third_party/gcc/microblaze -xJf $< touch $@ o/third_party/gcc/powerpc/bin/powerpc-linux-musl-gcc: \ third_party/gcc/x86_64-linux-musl__powerpc-linux-musl__g++-7.2.0.tar.xz mkdir -p o/third_party/gcc/powerpc tar -C o/third_party/gcc/powerpc -xJf $< touch $@ o/third_party/gcc/powerpc64le/bin/powerpc64le-linux-musl-gcc: \ third_party/gcc/2/x86_64-linux-musl__powerpc64le-linux-musl__g++-9.2.0.tar.xz mkdir -p o/third_party/gcc/powerpc64le tar -C o/third_party/gcc/powerpc64le -xJf $< touch $@ ================================================ FILE: third_party/gcc/x86_64-linux-musl__aarch64-linux-musl__g++-7.2.0.tar.xz.sha256 ================================================ 45add9649925052c42ad5dfe4234658e520f16aa365dfb27ccb4af4e4bb1bfe4 *third_party/gcc/x86_64-linux-musl__aarch64-linux-musl__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__arm-linux-musleabi__g++-7.2.0.tar.xz.sha256 ================================================ 9c753bee6c8dce961607bcdb507944b332d5d20a4b063de31acc519c2f5178de *third_party/gcc/x86_64-linux-musl__arm-linux-musleabi__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__i486-linux-musl__g++-7.2.0.tar.xz.sha256 ================================================ 95a30473064b3bdd0cd01249c6075691b4690646d491feaccc075415f8093129 *third_party/gcc/x86_64-linux-musl__i486-linux-musl__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__m68k-linux-musl__gcc-5.3.0.tar.xz.sha256 ================================================ c77795ed7b415411f92f74fa461ddff89809c8854a661bad6e2513117c613361 *third_party/gcc/x86_64-linux-musl__m68k-linux-musl__gcc-5.3.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__microblaze-linux-musl__g++-7.2.0.tar.xz.sha256 ================================================ 9cf57f5c8cb54550898cb395d8936124a99502770fbc080904b4bb4914993231 *third_party/gcc/x86_64-linux-musl__microblaze-linux-musl__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__mips-linux-musl__g++-7.2.0.tar.xz.sha256 ================================================ ed53952cd68d5330ff3fb976488235901c380df6047ecadc99487b725b337dd1 *third_party/gcc/x86_64-linux-musl__mips-linux-musl__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__mips64el-linux-musl__gcc-5.3.0.tar.xz.sha256 ================================================ 525dbdd0d12005f9c37c27fb34374e4a37cc71ac85d6760853ba8c3b088051d2 *third_party/gcc/x86_64-linux-musl__mips64el-linux-musl__gcc-5.3.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__mipsel-linux-musl__g++-9.2.0.tar.xz.sha256 ================================================ 3284617b33dc2ea43b32b07a393dba0d74ac48c30aa11c585cf06ee82070b420 *third_party/gcc/x86_64-linux-musl__mipsel-linux-musl__g++-9.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__powerpc-linux-musl__g++-7.2.0.tar.xz.sha256 ================================================ 7b0c9baf87eac2329fe4b83d18a53a3eb537c8d91a627404db39e7e697c5ec10 *third_party/gcc/x86_64-linux-musl__powerpc-linux-musl__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__riscv64-linux-musl__gcc-9.2.0.tar.xz.sha256 ================================================ 93dbe95dd459fe7be6a2e37f6cdcc8c27b0458762a2257dccdb23b263a869a93 *third_party/gcc/x86_64-linux-musl__riscv64-linux-musl__gcc-9.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__s390x-linux-musl__g++-7.2.0.tar.xz.sha256 ================================================ 8f2ca5c7917d699d075359c2be8bbc758e596f5085f1c15a80656e646398d4cf *third_party/gcc/x86_64-linux-musl__s390x-linux-musl__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__g++-4.9.4.tar.xz.sha256 ================================================ 6600f139ec0caeb6d27aad87ebc7347e60c85d224779fcb8901528d12972a51d *third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__g++-4.9.4.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__g++-7.2.0.tar.xz.sha256 ================================================ 4a2a724c5ea3ca44423578dbb62c1e3bf729090fd0185490f9ce861c65a56b1b *third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__g++-7.2.0.tar.xz ================================================ FILE: third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__gcc-4.8.5.tar.xz.sha256 ================================================ 95ca17d949180404d70df436dde698bd2d8148f1e7d3d08461b4f5b2be0a1c7e *third_party/gcc/x86_64-linux-musl__x86_64-linux-musl__gcc-4.8.5.tar.xz ================================================ FILE: third_party/libc-test/README.md ================================================ # Libc Test Project This folder downloads prebuilt binaries from the [Libc Test Project](https://github.com/jart/libc-test). This is Musl Libc's test suite collection. ## Origin git://repo.or.cz/libc-test ## Changes See link above to our GitHub fork. ## Build The binaries were compiled on Alpine Linux using: ``` export CC="cc -fno-omit-frame-pointer -Wl,-z,common-page-size=65536,-z,max-page-size=65536" make -j16 make install ``` ## Deploy Our operations team them uses [deploy-libc-test](deploy-libc-test) to deploy individual test programs to Google Cloud Storage once they've been confirmed to work. ================================================ FILE: third_party/libc-test/bin/2/functional/argv.elf.gz.sha256 ================================================ 6c5a7e17d7af78fd9b8ee71d305fce179320a2623989276f8333f27194e6b76c *third_party/libc-test/bin/2/functional/argv.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/basename.elf.gz.sha256 ================================================ a00ed4d780761f1041385200e8acc0baabd3273362643c5e721112975bfb3c8a *third_party/libc-test/bin/2/functional/basename.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/clocale_mbfuncs.elf.gz.sha256 ================================================ 0457a1757b9f7bf0be9e3cbf41aacabbb8bd58f1a17d7925add122490142b9e7 *third_party/libc-test/bin/2/functional/clocale_mbfuncs.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/clock_gettime.elf.gz.sha256 ================================================ c0e91258cc020dd0adb4c368da14838c5af9b522064218b99d57fd9013f019b1 *third_party/libc-test/bin/2/functional/clock_gettime.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/crypt.elf.gz.sha256 ================================================ dca6b8da2612fe55172f7d1c2559cbb58a2695ffa2c3cc6b4d453d21a333ff19 *third_party/libc-test/bin/2/functional/crypt.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/dirname.elf.gz.sha256 ================================================ 64de17f04659bc20a98bf3578b92d90a8bc0ce98cd114e985f3bc20025e652b6 *third_party/libc-test/bin/2/functional/dirname.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/env.elf.gz.sha256 ================================================ e5e3fa8cb2176e6783c7119ba5b3ea31872ac338f7e39134694845b3c24ea4e3 *third_party/libc-test/bin/2/functional/env.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/fcntl.elf.gz.sha256 ================================================ ebf27102a931d647b56a603f3241da59296fdb8222533be6f4c1a377ea805d63 *third_party/libc-test/bin/2/functional/fcntl.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/fdopen.elf.gz.sha256 ================================================ 5699f34f8519b84bd03cd02dc280bd8da2ba239cf317eccbcfaa92305bf8a79c *third_party/libc-test/bin/2/functional/fdopen.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/fnmatch.elf.gz.sha256 ================================================ f8919500315400ce85eb830b6860e748a4872108862b6122734593a46ecf326a *third_party/libc-test/bin/2/functional/fnmatch.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/fscanf.elf.gz.sha256 ================================================ 959963623ef55dc72029e7df67a3dab3c26119e3839ebf843d47569a4fa81765 *third_party/libc-test/bin/2/functional/fscanf.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/fwscanf.elf.gz.sha256 ================================================ f496349f5171a0ac824412c88ad7f58806f47975ea690a139650e452e29bd92e *third_party/libc-test/bin/2/functional/fwscanf.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/iconv_open.elf.gz.sha256 ================================================ 96fae862e16fdb02684b09b3d8ae3372abb60e70aebea0fb2dd2362f4b737ae7 *third_party/libc-test/bin/2/functional/iconv_open.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/mbc.elf.gz.sha256 ================================================ dec082f97e78e5447df8a9069ef5f84509c28721d87654a4c03842dc8ca5ae5d *third_party/libc-test/bin/2/functional/mbc.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/memstream.elf.gz.sha256 ================================================ abc0b42a97e465a503327039c6a963e503041cfb1ca7cafe05f1ed28f65bfc5a *third_party/libc-test/bin/2/functional/memstream.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/pthread_cancel-points.elf.gz.sha256 ================================================ e6f495cf1f257ed8588f9aea2d81c1927ee0394385771bd66c0b9d3d05c125b0 *third_party/libc-test/bin/2/functional/pthread_cancel-points.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/pthread_cancel.elf.gz.sha256 ================================================ 20bd0d8d4ffa58c1a0912da924de106174c9d00e17e4cd06f3033bc4bf3a2a45 *third_party/libc-test/bin/2/functional/pthread_cancel.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/pthread_cond.elf.gz.sha256 ================================================ 51c08c63dc3f1a7b6663ee4f7ad01702185d980e5449a681befae5b71a9b809b *third_party/libc-test/bin/2/functional/pthread_cond.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/pthread_mutex.elf.gz.sha256 ================================================ 646203ae83655c57ed8b72eb2b47457be819e0f813c63d02ad6d91979c0cc423 *third_party/libc-test/bin/2/functional/pthread_mutex.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/pthread_tsd.elf.gz.sha256 ================================================ 980691eb0b4eb278137e752892efdc4496cbfbd3e7b77227cd10777afc22aa44 *third_party/libc-test/bin/2/functional/pthread_tsd.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/qsort.elf.gz.sha256 ================================================ 5eaf028fa92bea5647d9f74811be55f328c249405045bd4a92177e3a72dd8de8 *third_party/libc-test/bin/2/functional/qsort.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/random.elf.gz.sha256 ================================================ 68b34859732fd21a2d73a3084c39fd62639b23c66fb069c3576757e3582f538a *third_party/libc-test/bin/2/functional/random.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/search_hsearch.elf.gz.sha256 ================================================ f65d4b916cac73ffc74e093994de4b86b8688bb1c1435aeba3981a7c26fd48d6 *third_party/libc-test/bin/2/functional/search_hsearch.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/search_insque.elf.gz.sha256 ================================================ 79f5963c4e322467e6663428af4413575c6d0d3cdec9584671a6d1d168657b50 *third_party/libc-test/bin/2/functional/search_insque.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/search_lsearch.elf.gz.sha256 ================================================ 757a267713893091aa8784caef4f410d9ce2655cd07e93a86c6c9c90864159c1 *third_party/libc-test/bin/2/functional/search_lsearch.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/search_tsearch.elf.gz.sha256 ================================================ 69fa6e0c216874dd8172251b3ad664cff4b025545561cb00e0fb2c48441b048f *third_party/libc-test/bin/2/functional/search_tsearch.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/sem_init.elf.gz.sha256 ================================================ f3987edea50357959e8c4d9326ee15a4953123250584559dec640083b4ee1bed *third_party/libc-test/bin/2/functional/sem_init.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/sem_open.elf.gz.sha256 ================================================ 1ce184ab97f54cfd52d4d259488cd4f37d1c760a702d6c757ceaf4d7bd1db36f *third_party/libc-test/bin/2/functional/sem_open.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/setjmp.elf.gz.sha256 ================================================ 049f333318ab5b40e8465e35d6fd3ea552dbf77ea668e6cbf5a0c87ecdebbb70 *third_party/libc-test/bin/2/functional/setjmp.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/socket.elf.gz.sha256 ================================================ bef73da4846c25331810f54213b70aae597971f877691899b7657bfb8dbadc8a *third_party/libc-test/bin/2/functional/socket.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/sscanf_long.elf.gz.sha256 ================================================ d3a352eb2edd90bfe225d7f06d497657e73eaef17295722a84706e912cb6ba49 *third_party/libc-test/bin/2/functional/sscanf_long.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/stat.elf.gz.sha256 ================================================ a5df0a73371db51a102ef88a15b62e0b76a7e90291d4cf9356c4d6c67de53a19 *third_party/libc-test/bin/2/functional/stat.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/strftime.elf.gz.sha256 ================================================ 678036969e9b5eecdaf818b580e3d5659543bcdaa41bb4378aff2876a8a2cba4 *third_party/libc-test/bin/2/functional/strftime.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/string.elf.gz.sha256 ================================================ fd2e3f30bcdf3e04299d882791c2ea7b5dfea61f1c9970ecaaca96c247b58cf6 *third_party/libc-test/bin/2/functional/string.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/string_memcpy.elf.gz.sha256 ================================================ 25934595671d7fe461d8046f777a2b8eea6f1a05629b30e294fbf2e514149310 *third_party/libc-test/bin/2/functional/string_memcpy.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/string_memmem.elf.gz.sha256 ================================================ 7772d83252eabad720e912aa0d3208555372ed5c253f313c569275e35e899d85 *third_party/libc-test/bin/2/functional/string_memmem.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/string_memset.elf.gz.sha256 ================================================ 47b47d0502330d07dda57024ab0be280aa5852e764875264970f878681eaea09 *third_party/libc-test/bin/2/functional/string_memset.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/string_strchr.elf.gz.sha256 ================================================ fd12334206de0d277c886c1c2ca0d9b714cce4755e54c08604d7ff8100447843 *third_party/libc-test/bin/2/functional/string_strchr.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/string_strcspn.elf.gz.sha256 ================================================ 25f2f22ae5c022b580896dd85a722cccfc5eebfe377934e16a07135db3e88628 *third_party/libc-test/bin/2/functional/string_strcspn.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/string_strstr.elf.gz.sha256 ================================================ 582bb348defae513655f5b7c96495e94540a174fbe232ad66d6b42e4a8b85f26 *third_party/libc-test/bin/2/functional/string_strstr.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/strtol.elf.gz.sha256 ================================================ 2362e726cdde6bfb6afb2efb71d9fdfc49fb47e72a7c4675b48b2dfdd9248c94 *third_party/libc-test/bin/2/functional/strtol.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/strtold.elf.gz.sha256 ================================================ 23a660648a7fb03137f4acde79f7229337c0aff7393db1a52fea2c2b8967a997 *third_party/libc-test/bin/2/functional/strtold.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/tgmath.elf.gz.sha256 ================================================ a9b9d8cb498f0478f4e939f2905237a0b8b64d944a230bd433e450a3faee4ecf *third_party/libc-test/bin/2/functional/tgmath.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/time.elf.gz.sha256 ================================================ 7c6222d2465f37c2f95fa11228c7231d0fe85ba5ac91682455be9bcaaaa09253 *third_party/libc-test/bin/2/functional/time.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/tls_init.elf.gz.sha256 ================================================ 3ca0bfbb56e648dac86e8384ba00c2117be1ebdffa21acb3c6c2697c9f6591e4 *third_party/libc-test/bin/2/functional/tls_init.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/tls_local_exec.elf.gz.sha256 ================================================ 335fb181e774df65290380e59c51e5f8491b2ed9e08a223a42384bf57d80ada2 *third_party/libc-test/bin/2/functional/tls_local_exec.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/udiv.elf.gz.sha256 ================================================ 226b3fc4ac17f0daf251439afd639d7e1b381f6236793ee2edaa52eefc94223a *third_party/libc-test/bin/2/functional/udiv.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/ungetc.elf.gz.sha256 ================================================ f495d373482c40db966007987b3854e084236cebc3c5185733110702ad9d388b *third_party/libc-test/bin/2/functional/ungetc.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/utime.elf.gz.sha256 ================================================ e2b5ce5eccb7ad57e07de1921f8d5b020375231e1f08a0645700eced562f7037 *third_party/libc-test/bin/2/functional/utime.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/vfork.elf.gz.sha256 ================================================ e25a623cf465fa0bd7a0bb3dec87b1b14e7a81b56699dffb50edf45548f02988 *third_party/libc-test/bin/2/functional/vfork.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/wcsstr.elf.gz.sha256 ================================================ 1b7a90e7d974b1384fffbedacbf10c2c7c54cf797e7bef9a259fcfb549ac066c *third_party/libc-test/bin/2/functional/wcsstr.elf.gz ================================================ FILE: third_party/libc-test/bin/2/functional/wcstol.elf.gz.sha256 ================================================ d75905be54d2c85e2f641ec5fc1486626aba039e8255faa8c476bf953f66ec1f *third_party/libc-test/bin/2/functional/wcstol.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/dn_expand-empty.elf.gz.sha256 ================================================ f0819d2f3a1bf79b4082342bbbdebbffcf3d9615047c423dfb2fb618fdc7a642 *third_party/libc-test/bin/2/regression/dn_expand-empty.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/dn_expand-ptr-0.elf.gz.sha256 ================================================ 41bdc93b527d4f63828683ccc6807b1acc417232492dc143e0743c505b666c67 *third_party/libc-test/bin/2/regression/dn_expand-ptr-0.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/execle-env.elf.gz.sha256 ================================================ f254059cb0bb06f78a31299dbecf82cd961ae9684e5e7708edec2d0669b8ef16 *third_party/libc-test/bin/2/regression/execle-env.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/fflush-exit.elf.gz.sha256 ================================================ 9a0b7eda63084a38e3722c4aeb78e6d46d85b32a5200a1b79d4accbc498a9b0f *third_party/libc-test/bin/2/regression/fflush-exit.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/fgets-eof.elf.gz.sha256 ================================================ 0a033d91b434a27d16f6523a89e6be24e3deadacb89bd8e7704700f3ec8b67a8 *third_party/libc-test/bin/2/regression/fgets-eof.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/fgetwc-buffering.elf.gz.sha256 ================================================ 8e8553581c7890e3dccc20eb0a59f946a42e1d46469caf762b0f6fba28436a2a *third_party/libc-test/bin/2/regression/fgetwc-buffering.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/flockfile-list.elf.gz.sha256 ================================================ de2082e40e3ca8af5f9be0208f86af779ef0b3eb24adb2d88b6a36ac8640f7ff *third_party/libc-test/bin/2/regression/flockfile-list.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/ftello-unflushed-append.elf.gz.sha256 ================================================ 2fee13891f893b27e9b8641429344b6afba4dea2d9b845b733696ac7c9c2215b *third_party/libc-test/bin/2/regression/ftello-unflushed-append.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/getpwnam_r-crash.elf.gz.sha256 ================================================ c5f2de6784ada2ab93640072fbed132971baac6897bf7cff50e061a6143efb4b *third_party/libc-test/bin/2/regression/getpwnam_r-crash.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/getpwnam_r-errno.elf.gz.sha256 ================================================ 5a51a1c0fd16f3d49b1ffc0dec10722ecae0bfa2ad23de4b80d66d516e6cd55c *third_party/libc-test/bin/2/regression/getpwnam_r-errno.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/iconv-roundtrips.elf.gz.sha256 ================================================ 5f6f2107960f0d7b92f89223d02642bf6c14387cad5e0054774f12e0359efead *third_party/libc-test/bin/2/regression/iconv-roundtrips.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/inet_ntop-v4mapped.elf.gz.sha256 ================================================ 9ed0c856f7c76d661619c166dc0289264fe50dbf3894f81594ec5649e7e3b4d6 *third_party/libc-test/bin/2/regression/inet_ntop-v4mapped.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/inet_pton-empty-last-field.elf.gz.sha256 ================================================ 559e8450cd471d2742cc6bb6ed17948d928926cc62d7c4a1610f5f216533cb1f *third_party/libc-test/bin/2/regression/inet_pton-empty-last-field.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/iswspace-null.elf.gz.sha256 ================================================ 9ed15e2b7eb96be50a9e28af4c337c48162c58be0c1d60c1adc494e405405650 *third_party/libc-test/bin/2/regression/iswspace-null.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/lrand48-signextend.elf.gz.sha256 ================================================ 7683f60a0926cdf1e62022b25cc71f953090d9fa83611705a8aed5b47c699893 *third_party/libc-test/bin/2/regression/lrand48-signextend.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/lseek-large.elf.gz.sha256 ================================================ afaaa04480d004248b25972f160d0c2043593b13a862c45711fe268534c9a6fd *third_party/libc-test/bin/2/regression/lseek-large.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/malloc-0.elf.gz.sha256 ================================================ 811abdd56712150a8550cf915bd66f1f2782b162f385183837304fe90895ca16 *third_party/libc-test/bin/2/regression/malloc-0.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/mbsrtowcs-overflow.elf.gz.sha256 ================================================ 237436f0233aa1f78b8970ba4af19057e581f3909cbd611bf26b245e73f39a73 *third_party/libc-test/bin/2/regression/mbsrtowcs-overflow.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/memmem-oob-read.elf.gz.sha256 ================================================ 4bab0a1e9f7fe847cefc9d62f46c9f7c4051da321d55cbe469bafd8bd1995ec8 *third_party/libc-test/bin/2/regression/memmem-oob-read.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/memmem-oob.elf.gz.sha256 ================================================ f5b2811e56d5234ae2d3f71e33bb9a8be329760faff910492839b62d5220ae09 *third_party/libc-test/bin/2/regression/memmem-oob.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/mkdtemp-failure.elf.gz.sha256 ================================================ 0618bc9c9cc6afcb98d27348a7940252b5e8a60523a30aed4f5523e087f98f02 *third_party/libc-test/bin/2/regression/mkdtemp-failure.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/mkstemp-failure.elf.gz.sha256 ================================================ f9d8acb73b1a7f9219f968e08e05b9cd722bd063df82d80c44059fb03769cc30 *third_party/libc-test/bin/2/regression/mkstemp-failure.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/printf-fmt-g-round.elf.gz.sha256 ================================================ f0487cd33925d31db3b626456a68db9a02cfb4d01aa46365317a6e17569dc928 *third_party/libc-test/bin/2/regression/printf-fmt-g-round.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/printf-fmt-g-zeros.elf.gz.sha256 ================================================ f1da587e88cc8ca5641a1c0fbf9cf06d3cad8e4df9a97803d7d85013a8253d04 *third_party/libc-test/bin/2/regression/printf-fmt-g-zeros.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/printf-fmt-n.elf.gz.sha256 ================================================ 2b6e7fe7033949b0cab05fabe2e37775c347910dc414e1fc0d7aa0b9af21344e *third_party/libc-test/bin/2/regression/printf-fmt-n.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread-robust-detach.elf.gz.sha256 ================================================ 0e5a000295c51cdc5d4a3aa6e0bbe0b9dfc1ff820fb5df52fc724833fc72e5ec *third_party/libc-test/bin/2/regression/pthread-robust-detach.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_atfork-errno-clobber.elf.gz.sha256 ================================================ 0f13082785457de541bc6148e5aa8160ffbd6286241de4a5d040105203d679db *third_party/libc-test/bin/2/regression/pthread_atfork-errno-clobber.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_cancel-sem_wait.elf.gz.sha256 ================================================ 3cd44caaeb057aa9c0132683ee26dbef036219178a209d6aa4cdd1f4f20dc329 *third_party/libc-test/bin/2/regression/pthread_cancel-sem_wait.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_cond-smasher.elf.gz.sha256 ================================================ 3cf6046d677ad3ad2ad5efacd034de73394ccc97e62deb7071e13e35141c075f *third_party/libc-test/bin/2/regression/pthread_cond-smasher.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_condattr_setclock.elf.gz.sha256 ================================================ ffc72f4dbda6cf0d87d223ccbb9551a8f6a51040f6ebfd5bb29cd8a6844075a5 *third_party/libc-test/bin/2/regression/pthread_condattr_setclock.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_exit-cancel.elf.gz.sha256 ================================================ b3a1633a1fe83ce960f2999924c3373750337efee02149c81d461aca4333aedc *third_party/libc-test/bin/2/regression/pthread_exit-cancel.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_exit-dtor.elf.gz.sha256 ================================================ 57a69544be84dfad05ade5bef80648cf1cf73463f9632e689b6b71bedb1fb449 *third_party/libc-test/bin/2/regression/pthread_exit-dtor.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_once-deadlock.elf.gz.sha256 ================================================ a6b3d9824dd41c72b0098e30e9611dbf5340be0f895549e13f22d304f66bac77 *third_party/libc-test/bin/2/regression/pthread_once-deadlock.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/pthread_rwlock-ebusy.elf.gz.sha256 ================================================ e92d48948ff8b9d8e7f32c671fa687f32c85fc0c8b8245ac1788e4df2c9b5578 *third_party/libc-test/bin/2/regression/pthread_rwlock-ebusy.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/putenv-doublefree.elf.gz.sha256 ================================================ 26e55fc3293c6301ef6c0dd67b328f0b3eb1a624a5e152581b4d80922835ee27 *third_party/libc-test/bin/2/regression/putenv-doublefree.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/regex-backref-0.elf.gz.sha256 ================================================ bc507fc045b1c0b3e962521e8420808eff00e617c0347dcf46c5ba256c83b15b *third_party/libc-test/bin/2/regression/regex-backref-0.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/regex-bracket-icase.elf.gz.sha256 ================================================ 4f00208b2bd08a42adfbdc327e6770b56c0528643d6ba52668e6c08e6a7f5254 *third_party/libc-test/bin/2/regression/regex-bracket-icase.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/regex-ere-backref.elf.gz.sha256 ================================================ 4c0e5d57e852a665b945633b3640c1818f98db6b9ae7b74b07a734981b6030dc *third_party/libc-test/bin/2/regression/regex-ere-backref.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/regex-escaped-high-byte.elf.gz.sha256 ================================================ eb16385515cc44eb076a7b10ddce32e9b2875e81edae83e169a244bd8cc4ed6d *third_party/libc-test/bin/2/regression/regex-escaped-high-byte.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/regex-negated-range.elf.gz.sha256 ================================================ c11fbc73bd30d7f0ea8929ca218a6f3423c210d6779011745c1ca978d1ae8d80 *third_party/libc-test/bin/2/regression/regex-negated-range.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/regexec-nosub.elf.gz.sha256 ================================================ 3a2bb37a2e96b168cc3affbb46edc40f8e89174b4d2e40fc339c29a73e157c8c *third_party/libc-test/bin/2/regression/regexec-nosub.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/rewind-clear-error.elf.gz.sha256 ================================================ 960454a3ccddfdc63e7749e3ce3cd6d073fc3a3742820a7069e8bc74a6b194b4 *third_party/libc-test/bin/2/regression/rewind-clear-error.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/scanf-bytes-consumed.elf.gz.sha256 ================================================ d53a42b5de5f2a5240962bb6b17b3366fac5535af6f19d67f0f2e8df746ac2eb *third_party/libc-test/bin/2/regression/scanf-bytes-consumed.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/scanf-match-literal-eof.elf.gz.sha256 ================================================ 61555b752efc3e5a61a55ed8c9d93263dde7207f2e63eb9df39fbc9ef79cb511 *third_party/libc-test/bin/2/regression/scanf-match-literal-eof.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/scanf-nullbyte-char.elf.gz.sha256 ================================================ 95fb33c95e4a50231cc309788373211947fde65883c59a47cf667dbc5a7417a4 *third_party/libc-test/bin/2/regression/scanf-nullbyte-char.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/sem_close-unmap.elf.gz.sha256 ================================================ 1e97328608e42c61c103f097dddb5e2ae6589e2cd9c1f9c1a16a6d131406fa3c *third_party/libc-test/bin/2/regression/sem_close-unmap.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/setvbuf-unget.elf.gz.sha256 ================================================ 84634b459730d00f856f304312387945fc2482a7470473798e3b6fcffad5de19 *third_party/libc-test/bin/2/regression/setvbuf-unget.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/sigaltstack.elf.gz.sha256 ================================================ 2235ba6fc8efa4fbae40e3fdcebf22aa1c270ea9b0872cf000dd1d45835235eb *third_party/libc-test/bin/2/regression/sigaltstack.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/sigprocmask-internal.elf.gz.sha256 ================================================ c517a479ebc5df9b204602f48a8c88140f0283940744f2354d2ee805f7e4f10c *third_party/libc-test/bin/2/regression/sigprocmask-internal.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/sigreturn.elf.gz.sha256 ================================================ b276bdffe0ce33abe6afdac2c853cdd39808dc1fb0d77144c79a10dd30a8273b *third_party/libc-test/bin/2/regression/sigreturn.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/sscanf-eof.elf.gz.sha256 ================================================ 4011c8ca943b497cda52e612d456d18f9113916c8ece3d9ea8fd7f80476a9cba *third_party/libc-test/bin/2/regression/sscanf-eof.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/statvfs.elf.gz.sha256 ================================================ ff8b0d02538c1fd939f64300e541ce35f1e2fdc925df6fbfb049f1387286cdd0 *third_party/libc-test/bin/2/regression/statvfs.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/strverscmp.elf.gz.sha256 ================================================ 296253f0726d1d7db6d7bb9a018eb57bd29812cf38c4720c0e2855cec8c60610 *third_party/libc-test/bin/2/regression/strverscmp.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/syscall-sign-extend.elf.gz.sha256 ================================================ c19ac2172b64fff6ed7d64488fe20aefd19bc286988a50129a285feef45d1e94 *third_party/libc-test/bin/2/regression/syscall-sign-extend.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/uselocale-0.elf.gz.sha256 ================================================ 8ef0243fd02c5d88dcfe9b29e719bc9dc65589d74fe76febaf1a58200dd335e4 *third_party/libc-test/bin/2/regression/uselocale-0.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/wcsncpy-read-overflow.elf.gz.sha256 ================================================ 0943b5d0ac46ff5738335df6ef445d67b357dcf1db4c73d3658258e7c401c9c7 *third_party/libc-test/bin/2/regression/wcsncpy-read-overflow.elf.gz ================================================ FILE: third_party/libc-test/bin/2/regression/wcsstr-false-negative.elf.gz.sha256 ================================================ fd9ba0b79b0f49db322dc738058e1deb8e24bd5eecc312ca777eb353cb9f8709 *third_party/libc-test/bin/2/regression/wcsstr-false-negative.elf.gz ================================================ FILE: third_party/libc-test/bin/3/functional/inet_pton.elf.gz.sha256 ================================================ 57968f75356af5a6e11fa8b47e77f48326c70e4bf7a89059ed1c8895fdb4a7b5 *third_party/libc-test/bin/3/functional/inet_pton.elf.gz ================================================ FILE: third_party/libc-test/bin/3/functional/popen.elf.gz.sha256 ================================================ 7e3ee8f410dafcb22279fff06b5d598f2770d1a3d9aac051cc51926bd0f3685c *third_party/libc-test/bin/3/functional/popen.elf.gz ================================================ FILE: third_party/libc-test/bin/3/regression/daemon-failure.elf.gz.sha256 ================================================ fb5211bc9f10097b986bf284faae7c4c587c2193b99445d702b477f1b4dc4542 *third_party/libc-test/bin/3/regression/daemon-failure.elf.gz ================================================ FILE: third_party/libc-test/bin/3/regression/malloc-oom.elf.gz.sha256 ================================================ 8f9ee23f33eda286c118c97a772ef77a8f0db18d20cd7c1e76d91ec03c28ca99 *third_party/libc-test/bin/3/regression/malloc-oom.elf.gz ================================================ FILE: third_party/libc-test/bin/3/regression/pthread_create-oom.elf.gz.sha256 ================================================ 0e5765f5cfcd2980473980bdf5aadf6dac876f6ee062ae04bab7db03728eef84 *third_party/libc-test/bin/3/regression/pthread_create-oom.elf.gz ================================================ FILE: third_party/libc-test/bin/3/regression/setenv-oom.elf.gz.sha256 ================================================ 0bf7ecb7761b0e6130c0b0e61fbc74e036f16196a9819a617483c940ebf14180 *third_party/libc-test/bin/3/regression/setenv-oom.elf.gz ================================================ FILE: third_party/libc-test/deploy-libc-test ================================================ #!/bin/sh set -ex # e.g. deploy-libc-test regression/scanf-bytes-consumed T=/mnt/videos/website/justine.lol/libc-test/bin L=/home/jart/vendor/libc-test/src V=2 mkdir -p $T/$V for f; do if [ ! -f $L/$f.exe ]; then echo "not found: $L/$f" >&2 exit 1 fi mkdir -p $T/$V/${f%/*} mkdir -p ~/blink/third_party/libc-test/bin/$V/${f%/*} cp $L/$f.exe $T/$V/$f.elf rm -f $T/$V/$f.elf.gz gzip $T/$V/$f.elf sha256sum -b $T/$V/$f.elf.gz >$T/$V/$f.elf.gz.sha256 mkdir -p ~/blink/third_party/libc-test/bin/$V cp $T/$V/$f.elf.gz.sha256 ~/blink/third_party/libc-test/bin/$V/$f.elf.gz.sha256 sed -i -e 's!/mnt/videos/website/justine.lol/libc-test/bin!third_party/libc-test/bin!' \ ~/blink/third_party/libc-test/bin/$V/$f.elf.gz.sha256 ssh debian gsutil -m -h Cache-Control:public,max-age=31536000 cp -r -a public-read \ /mnt/videos/website/justine.lol/libc-test/bin/$V/$f.elf.gz \ gs://justine/libc-test/bin/$V/$f.elf.gz done syncweb ================================================ FILE: third_party/libc-test/libc-test.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ .PRECIOUS: third_party/libc-test/%.gz third_party/libc-test/%.gz: third_party/libc-test/%.gz.sha256 o/tool/sha256sum curl -so $@ https://justine.storage.googleapis.com/libc-test/$(subst third_party/libc-test/,,$@) o/tool/sha256sum -c $< .PRECIOUS: third_party/libc-test/bin/%.elf third_party/libc-test/bin/%.elf: third_party/libc-test/bin/%.elf.gz gzip -dc <$< >$@ chmod +x $@ o/$(MODE)/third_party/libc-test/bin/%.elf.ok: \ third_party/libc-test/bin/%.elf \ o/lib/ld-musl-x86_64.so.1 \ o/$(MODE)/blink/blink \ o/proc/cpuinfo \ o/proc/meminfo @mkdir -p $(@D) o/$(MODE)/blink/blink $< @touch $@ o/proc/%: third_party/libc-test/% @mkdir -p $(@D) cp -f $< $@ chmod +x $@ LIBC_TEST_TESTS = \ o/$(MODE)/third_party/libc-test/bin/2/functional/pthread_cancel.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/strtol.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/crypt.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/string_strstr.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/string_memcpy.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/clock_gettime.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/iconv_open.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/fdopen.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/argv.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/memstream.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/fcntl.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/random.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/mbc.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/search_insque.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/tgmath.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/pthread_tsd.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/socket.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/search_tsearch.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/udiv.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/string.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/basename.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/string_memmem.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/tls_local_exec.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/strftime.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/pthread_cond.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/string_memset.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/wcsstr.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/clocale_mbfuncs.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/setjmp.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/utime.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/env.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/sem_init.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/dirname.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/ungetc.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/wcstol.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/search_lsearch.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/strtold.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/fnmatch.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/fwscanf.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/qsort.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/string_strchr.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/time.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/search_hsearch.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/fscanf.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/sscanf_long.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/string_strcspn.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/printf-fmt-n.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/putenv-doublefree.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/memmem-oob.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/regex-ere-backref.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/iconv-roundtrips.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/malloc-0.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/regex-backref-0.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/regex-negated-range.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/sigreturn.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/rewind-clear-error.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/sigaltstack.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_condattr_setclock.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/fgets-eof.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/setvbuf-unget.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/ftello-unflushed-append.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/syscall-sign-extend.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/fflush-exit.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/lrand48-signextend.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_once-deadlock.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/printf-fmt-g-round.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_exit-cancel.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_rwlock-ebusy.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/printf-fmt-g-zeros.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/wcsncpy-read-overflow.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/mbsrtowcs-overflow.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/sscanf-eof.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/lseek-large.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/dn_expand-empty.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/inet_pton-empty-last-field.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/strverscmp.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/wcsstr-false-negative.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_exit-dtor.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/memmem-oob-read.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/regex-bracket-icase.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/iswspace-null.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/regexec-nosub.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/mkdtemp-failure.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/dn_expand-ptr-0.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/getpwnam_r-errno.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/fgetwc-buffering.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/pthread-robust-detach.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/scanf-nullbyte-char.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/flockfile-list.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/inet_ntop-v4mapped.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/regex-escaped-high-byte.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/mkstemp-failure.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/uselocale-0.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/sigprocmask-internal.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/statvfs.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/scanf-match-literal-eof.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/getpwnam_r-crash.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/scanf-bytes-consumed.elf.ok \ o/$(MODE)/third_party/libc-test/bin/3/regression/pthread_create-oom.elf.ok \ o/$(MODE)/third_party/libc-test/bin/3/regression/daemon-failure.elf.ok \ o/$(MODE)/third_party/libc-test/bin/3/functional/inet_pton.elf.ok # TODO(jart): This needs a longer timeout. # o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_cond-smasher.elf.ok ifneq ($(wildcard /dev/shm),) ifneq ($(HOST_SYSTEM), FreeBSD) LIBC_TEST_TESTS += \ o/$(MODE)/third_party/libc-test/bin/2/functional/sem_open.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/sem_close-unmap.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_cancel-sem_wait.elf.ok \ o/$(MODE)/third_party/libc-test/bin/2/functional/pthread_cancel-points.elf.ok endif endif # When creating files, Linux sets st_gid to getegid() but Darwin and # FreeBSD appear to always sets it to 0 (wheel). This test also just # seems to be flaky in general, printing errors like "st.st_atime<=t # failed: 1675987682 > 1675970318". # # ifneq ($(HOST_SYSTEM), Darwin) # ifneq ($(HOST_SYSTEM), FreeBSD) # LIBC_TEST_TESTS += o/$(MODE)/third_party/libc-test/bin/2/functional/stat.elf.ok # endif # endif # No RLIMIT_NPROC on Cygwin ifneq ($(HOST_OS), Cygwin) LIBC_TEST_TESTS += o/$(MODE)/third_party/libc-test/bin/2/regression/pthread_atfork-errno-clobber.elf.ok endif ifneq ($(HOST_SYSTEM), OpenBSD) LIBC_TEST_TESTS += \ o/$(MODE)/third_party/libc-test/bin/3/regression/malloc-oom.elf.ok \ o/$(MODE)/third_party/libc-test/bin/3/regression/setenv-oom.elf.ok endif ################################################################################ # FLAKY TESTS # This test execve()'s the system /bin/sh. GitHub Actions Linux # environment reports "sh: error while loading shared libraries: # libc.so.6: cannot stat shared object: No such file or directory". # # o/$(MODE)/third_party/libc-test/bin/2/regression/execle-env.elf.ok # This test also executes /bin/sh so it's failing on GitHub Actions. It # also fails for unexplained reasons on OpenBSD. # # o/$(MODE)/third_party/libc-test/bin/2/functional/vfork.elf.ok # These tests work fine but they launch /bin/sh so avoiding adding them # to `make check` until we find some way to detect GA environment. # # o/$(MODE)/third_party/libc-test/bin/3/functional/popen.elf.ok # o/$(MODE)/third_party/libc-test/bin/3/functional/spawn.elf.ok # Fails on GitHub Actions Linux with "SEGMENTATION FAULT AT ADDRESS 10" # and this hasn't happened in any other environment. # https://github.com/jart/blink/actions/runs/4131367559/jobs/7138932392 # # o/$(MODE)/third_party/libc-test/bin/2/functional/tls_init.elf.ok ################################################################################ o/$(MODE)/third_party/libc-test: $(LIBC_TEST_TESTS) @mkdir -p $(@D) @touch $@ ================================================ FILE: third_party/libz/LICENSE ================================================ Copyright notice: (C) 1995-2022 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu ================================================ FILE: third_party/libz/README.blink ================================================ DESCRIPTION zlib is a data compression library ORIGIN zlib 1.2.13 04f42ceca40f73e2978b50e93806c2a18c1281fc https://github.com/madler/zlib LICENSE The Zlib License LOCAL CHANGES - Add comments disabling clang-format - Made #include lines relative to repo root ================================================ FILE: third_party/libz/adler32.c ================================================ // clang-format off /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "third_party/libz/zutil.h" local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ # define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) # define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) # define MOD63(a) \ do { /* this assumes a is not negative */ \ z_off64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32_z(adler, buf, len) uLong adler; const Bytef *buf; z_size_t len; { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; { return adler32_z(adler, buf, len); } /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine(adler1, adler2, len2) uLong adler1; uLong adler2; z_off_t len2; { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { return adler32_combine_(adler1, adler2, len2); } ================================================ FILE: third_party/libz/compress.c ================================================ // clang-format off /* compress.c -- compress a memory buffer * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "third_party/libz/zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int ZEXPORT compress2(dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; int level; { z_stream stream; int err; const uInt max = (uInt)-1; uLong left; left = *destLen; *destLen = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; stream.next_out = dest; stream.avail_out = 0; stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; sourceLen -= stream.avail_in; } err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); } while (err == Z_OK); *destLen = stream.total_out; deflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== */ int ZEXPORT compress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong ZEXPORT compressBound(sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } ================================================ FILE: third_party/libz/crc32.c ================================================ // clang-format off /* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * This interleaved implementation of a CRC makes use of pipelined multiple * arithmetic-logic units, commonly found in modern CPU cores. It is due to * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). MAKECRCH can be #defined to write out crc32.h. A main() routine is also produced, so that this one source file can be compiled to an executable. */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "third_party/libz/zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ /* A CRC of a message is computed on N braids of words in the message, where each word consists of W bytes (4 or 8). If N is 3, for example, then three running sparse CRCs are calculated respectively on each braid, at these indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... This is done starting at a word boundary, and continues until as many blocks of N * W bytes as are available have been processed. The results are combined into a single CRC at the end. For this code, N must be in the range 1..6 and W must be 4 or 8. The upper limit on N can be increased if desired by adding more #if blocks, extending the patterns apparent in the code. In addition, crc32.h would need to be regenerated, if the maximum N value is increased. N and W are chosen empirically by benchmarking the execution time on a given processor. The choices for N and W below were based on testing on Intel Kaby Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 Octeon II processors. The Intel, AMD, and ARM processors were all fastest with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. They were all tested with either gcc or clang, all using the -O3 optimization level. Your mileage may vary. */ /* Define N */ #ifdef Z_TESTN # define N Z_TESTN #else # define N 5 #endif #if N < 1 || N > 6 # error N must be in 1..6 #endif /* z_crc_t must be at least 32 bits. z_word_t must be at least as long as z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and that bytes are eight bits. */ /* Define W and the associated z_word_t type. If W is not defined, then a braided calculation is not used, and the associated tables and code are not compiled. */ #ifdef Z_TESTW # if Z_TESTW-1 != -1 # define W Z_TESTW # endif #else # ifdef MAKECRCH # define W 8 /* required for MAKECRCH */ # else # if defined(__x86_64__) || defined(__aarch64__) # define W 8 # else # define W 4 # endif # endif #endif #ifdef W # if W == 8 && defined(Z_U8) typedef Z_U8 z_word_t; # elif defined(Z_U4) # undef W # define W 4 typedef Z_U4 z_word_t; # else # undef W # endif #endif /* If available, use the ARM processor CRC32 instruction. */ #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 # define ARMCRC32 #endif /* Local functions. */ local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) local z_word_t byte_swap OF((z_word_t word)); #endif #if defined(W) && !defined(ARMCRC32) local z_crc_t crc_word OF((z_word_t data)); local z_word_t crc_word_big OF((z_word_t data)); #endif #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) /* Swap the bytes in a z_word_t to convert between little and big endian. Any self-respecting compiler will optimize this to a single machine byte-swap instruction, if one is available. This assumes that word_t is either 32 bits or 64 bits. */ local z_word_t byte_swap(word) z_word_t word; { # if W == 8 return (word & 0xff00000000000000) >> 56 | (word & 0xff000000000000) >> 40 | (word & 0xff0000000000) >> 24 | (word & 0xff00000000) >> 8 | (word & 0xff000000) << 8 | (word & 0xff0000) << 24 | (word & 0xff00) << 40 | (word & 0xff) << 56; # else /* W == 4 */ return (word & 0xff000000) >> 24 | (word & 0xff0000) >> 8 | (word & 0xff00) << 8 | (word & 0xff) << 24; # endif } #endif /* CRC polynomial. */ #define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ #ifdef DYNAMIC_CRC_TABLE local z_crc_t FAR crc_table[256]; local z_crc_t FAR x2n_table[32]; local void make_crc_table OF((void)); #ifdef W local z_word_t FAR crc_big_table[256]; local z_crc_t FAR crc_braid_table[W][256]; local z_word_t FAR crc_braid_big_table[W][256]; local void braid OF((z_crc_t [][256], z_word_t [][256], int, int)); #endif #ifdef MAKECRCH local void write_table OF((FILE *, const z_crc_t FAR *, int)); local void write_table32hi OF((FILE *, const z_word_t FAR *, int)); local void write_table64 OF((FILE *, const z_word_t FAR *, int)); #endif /* MAKECRCH */ /* Define a once() function depending on the availability of atomics. If this is compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in multiple threads, and if atomics are not available, then get_crc_table() must be called to initialize the tables and must return before any threads are allowed to compute or combine CRCs. */ /* Definition of once functionality. */ typedef struct once_s once_t; local void once OF((once_t *, void (*)(void))); /* Check for the availability of atomics. */ #if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ !defined(__STDC_NO_ATOMICS__) #include /* Structure for once(), which must be initialized with ONCE_INIT. */ struct once_s { atomic_flag begun; atomic_int done; }; #define ONCE_INIT {ATOMIC_FLAG_INIT, 0} /* Run the provided init() function exactly once, even if multiple threads invoke once() at the same time. The state must be a once_t initialized with ONCE_INIT. */ local void once(state, init) once_t *state; void (*init)(void); { if (!atomic_load(&state->done)) { if (atomic_flag_test_and_set(&state->begun)) while (!atomic_load(&state->done)) ; else { init(); atomic_store(&state->done, 1); } } } #else /* no atomics */ /* Structure for once(), which must be initialized with ONCE_INIT. */ struct once_s { volatile int begun; volatile int done; }; #define ONCE_INIT {0, 0} /* Test and set. Alas, not atomic, but tries to minimize the period of vulnerability. */ local int test_and_set OF((int volatile *)); local int test_and_set(flag) int volatile *flag; { int was; was = *flag; *flag = 1; return was; } /* Run the provided init() function once. This is not thread-safe. */ local void once(state, init) once_t *state; void (*init)(void); { if (!state->done) { if (test_and_set(&state->begun)) while (!state->done) ; else { init(); state->done = 1; } } } #endif /* State for once(). */ local once_t made = ONCE_INIT; /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. */ local void make_crc_table() { unsigned i, j, n; z_crc_t p; /* initialize the CRC of bytes tables */ for (i = 0; i < 256; i++) { p = i; for (j = 0; j < 8; j++) p = p & 1 ? (p >> 1) ^ POLY : p >> 1; crc_table[i] = p; #ifdef W crc_big_table[i] = byte_swap(p); #endif } /* initialize the x^2^n mod p(x) table */ p = (z_crc_t)1 << 30; /* x^1 */ x2n_table[0] = p; for (n = 1; n < 32; n++) x2n_table[n] = p = multmodp(p, p); #ifdef W /* initialize the braiding tables -- needs x2n_table[] */ braid(crc_braid_table, crc_braid_big_table, N, W); #endif #ifdef MAKECRCH { /* The crc32.h header file contains tables for both 32-bit and 64-bit z_word_t's, and so requires a 64-bit type be available. In that case, z_word_t must be defined to be 64-bits. This code then also generates and writes out the tables for the case that z_word_t is 32 bits. */ #if !defined(W) || W != 8 # error Need a 64-bit integer type in order to generate crc32.h. #endif FILE *out; int k, n; z_crc_t ltl[8][256]; z_word_t big[8][256]; out = fopen("crc32.h", "w"); if (out == NULL) return; /* write out little-endian CRC table to crc32.h */ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n" " * Generated automatically by crc32.c\n */\n" "\n" "local const z_crc_t FAR crc_table[] = {\n" " "); write_table(out, crc_table, 256); fprintf(out, "};\n"); /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ fprintf(out, "\n" "#ifdef W\n" "\n" "#if W == 8\n" "\n" "local const z_word_t FAR crc_big_table[] = {\n" " "); write_table64(out, crc_big_table, 256); fprintf(out, "};\n"); /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ fprintf(out, "\n" "#else /* W == 4 */\n" "\n" "local const z_word_t FAR crc_big_table[] = {\n" " "); write_table32hi(out, crc_big_table, 256); fprintf(out, "};\n" "\n" "#endif\n"); /* write out braid tables for each value of N */ for (n = 1; n <= 6; n++) { fprintf(out, "\n" "#if N == %d\n", n); /* compute braid tables for this N and 64-bit word_t */ braid(ltl, big, n, 8); /* write out braid tables for 64-bit z_word_t to crc32.h */ fprintf(out, "\n" "#if W == 8\n" "\n" "local const z_crc_t FAR crc_braid_table[][256] = {\n"); for (k = 0; k < 8; k++) { fprintf(out, " {"); write_table(out, ltl[k], 256); fprintf(out, "}%s", k < 7 ? ",\n" : ""); } fprintf(out, "};\n" "\n" "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); for (k = 0; k < 8; k++) { fprintf(out, " {"); write_table64(out, big[k], 256); fprintf(out, "}%s", k < 7 ? ",\n" : ""); } fprintf(out, "};\n"); /* compute braid tables for this N and 32-bit word_t */ braid(ltl, big, n, 4); /* write out braid tables for 32-bit z_word_t to crc32.h */ fprintf(out, "\n" "#else /* W == 4 */\n" "\n" "local const z_crc_t FAR crc_braid_table[][256] = {\n"); for (k = 0; k < 4; k++) { fprintf(out, " {"); write_table(out, ltl[k], 256); fprintf(out, "}%s", k < 3 ? ",\n" : ""); } fprintf(out, "};\n" "\n" "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); for (k = 0; k < 4; k++) { fprintf(out, " {"); write_table32hi(out, big[k], 256); fprintf(out, "}%s", k < 3 ? ",\n" : ""); } fprintf(out, "};\n" "\n" "#endif\n" "\n" "#endif\n"); } fprintf(out, "\n" "#endif\n"); /* write out zeros operator table to crc32.h */ fprintf(out, "\n" "local const z_crc_t FAR x2n_table[] = {\n" " "); write_table(out, x2n_table, 32); fprintf(out, "};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH /* Write the 32-bit values in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ local void write_table(out, table, k) FILE *out; const z_crc_t FAR *table; int k; { int n; for (n = 0; n < k; n++) fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", (unsigned long)(table[n]), n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); } /* Write the high 32-bits of each value in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ local void write_table32hi(out, table, k) FILE *out; const z_word_t FAR *table; int k; { int n; for (n = 0; n < k; n++) fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", (unsigned long)(table[n] >> 32), n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); } /* Write the 64-bit values in table[0..k-1] to out, three per line in hexadecimal separated by commas. This assumes that if there is a 64-bit type, then there is also a long long integer type, and it is at least 64 bits. If not, then the type cast and format string can be adjusted accordingly. */ local void write_table64(out, table, k) FILE *out; const z_word_t FAR *table; int k; { int n; for (n = 0; n < k; n++) fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", (unsigned long long)(table[n]), n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); } /* Actually do the deed. */ int main() { make_crc_table(); return 0; } #endif /* MAKECRCH */ #ifdef W /* Generate the little and big-endian braid tables for the given n and z_word_t size w. Each array must have room for w blocks of 256 elements. */ local void braid(ltl, big, n, w) z_crc_t ltl[][256]; z_word_t big[][256]; int n; int w; { int k; z_crc_t i, p, q; for (k = 0; k < w; k++) { p = x2nmodp((n * w + 3 - k) << 3, 0); ltl[k][0] = 0; big[w - 1 - k][0] = 0; for (i = 1; i < 256; i++) { ltl[k][i] = q = multmodp(i << 24, p); big[w - 1 - k][i] = byte_swap(q); } } } #endif #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables for byte-wise and braided CRC-32 calculations, and a table of powers * of x for combining CRC-32s, all made by make_crc_table(). */ #include "third_party/libz/crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ======================================================================== * Routines used for CRC calculation. Some are also required for the table * generation above. */ /* Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, reflected. For speed, this requires that a not be zero. */ local z_crc_t multmodp(a, b) z_crc_t a; z_crc_t b; { z_crc_t m, p; m = (z_crc_t)1 << 31; p = 0; for (;;) { if (a & m) { p ^= b; if ((a & (m - 1)) == 0) break; } m >>= 1; b = b & 1 ? (b >> 1) ^ POLY : b >> 1; } return p; } /* Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been initialized. */ local z_crc_t x2nmodp(n, k) z_off64_t n; unsigned k; { z_crc_t p; p = (z_crc_t)1 << 31; /* x^0 == 1 */ while (n) { if (n & 1) p = multmodp(x2n_table[k & 31], p); n >>= 1; k++; } return p; } /* ========================================================================= * This function can be used by asm versions of crc32(), and to force the * generation of the CRC tables in a threaded application. */ const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= * Use ARM machine instructions if available. This will compute the CRC about * ten times faster than the braided calculation. This code does not check for * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will * only be defined if the compilation specifies an ARM processor architecture * that has the instructions. For example, compiling with -march=armv8.1-a or * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 * instructions. */ #ifdef ARMCRC32 /* Constants empirically determined to maximize speed. These values are from measurements on a Cortex-A57. Your mileage may vary. */ #define Z_BATCH 3990 /* number of words in a batch */ #define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ #define Z_BATCH_MIN 800 /* fewest words in a final batch */ unsigned long ZEXPORT crc32_z(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { z_crc_t val; z_word_t crc1, crc2; const z_word_t *word; z_word_t val0, val1, val2; z_size_t last, last2, i; z_size_t num; /* Return initial CRC, if requested. */ if (buf == Z_NULL) return 0; #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ crc = (~crc) & 0xffffffff; /* Compute the CRC up to a word boundary. */ while (len && ((z_size_t)buf & 7) != 0) { len--; val = *buf++; __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); } /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ word = (z_word_t const *)buf; num = len >> 3; len &= 7; /* Do three interleaved CRCs to realize the throughput of one crc32x instruction per cycle. Each CRC is calculated on Z_BATCH words. The three CRCs are combined into a single CRC after each set of batches. */ while (num >= 3 * Z_BATCH) { crc1 = 0; crc2 = 0; for (i = 0; i < Z_BATCH; i++) { val0 = word[i]; val1 = word[i + Z_BATCH]; val2 = word[i + 2 * Z_BATCH]; __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); } word += 3 * Z_BATCH; num -= 3 * Z_BATCH; crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; } /* Do one last smaller batch with the remaining words, if there are enough to pay for the combination of CRCs. */ last = num / 3; if (last >= Z_BATCH_MIN) { last2 = last << 1; crc1 = 0; crc2 = 0; for (i = 0; i < last; i++) { val0 = word[i]; val1 = word[i + last]; val2 = word[i + last2]; __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); } word += 3 * last; num -= 3 * last; val = x2nmodp(last, 6); crc = multmodp(val, crc) ^ crc1; crc = multmodp(val, crc) ^ crc2; } /* Compute the CRC on any remaining words. */ for (i = 0; i < num; i++) { val0 = word[i]; __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); } word += num; /* Complete the CRC on any remaining bytes. */ buf = (const unsigned char FAR *)word; while (len) { len--; val = *buf++; __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); } /* Return the CRC, post-conditioned. */ return crc ^ 0xffffffff; } #else #ifdef W /* Return the CRC of the W bytes in the word_t data, taking the least-significant byte of the word as the first byte of data, without any pre or post conditioning. This is used to combine the CRCs of each braid. */ local z_crc_t crc_word(data) z_word_t data; { int k; for (k = 0; k < W; k++) data = (data >> 8) ^ crc_table[data & 0xff]; return (z_crc_t)data; } local z_word_t crc_word_big(data) z_word_t data; { int k; for (k = 0; k < W; k++) data = (data << 8) ^ crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; return data; } #endif /* ========================================================================= */ unsigned long ZEXPORT crc32_z(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { /* Return initial CRC, if requested. */ if (buf == Z_NULL) return 0; #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ crc = (~crc) & 0xffffffff; #ifdef W /* If provided enough bytes, do a braided CRC calculation. */ if (len >= N * W + W - 1) { z_size_t blks; z_word_t const *words; unsigned endian; int k; /* Compute the CRC up to a z_word_t boundary. */ while (len && ((z_size_t)buf & (W - 1)) != 0) { len--; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } /* Compute the CRC on as many N z_word_t blocks as are available. */ blks = len / (N * W); len -= blks * N * W; words = (z_word_t const *)buf; /* Do endian check at execution time instead of compile time, since ARM processors can change the endianess at execution time. If the compiler knows what the endianess will be, it can optimize out the check and the unused branch. */ endian = 1; if (*(unsigned char *)&endian) { /* Little endian. */ z_crc_t crc0; z_word_t word0; #if N > 1 z_crc_t crc1; z_word_t word1; #if N > 2 z_crc_t crc2; z_word_t word2; #if N > 3 z_crc_t crc3; z_word_t word3; #if N > 4 z_crc_t crc4; z_word_t word4; #if N > 5 z_crc_t crc5; z_word_t word5; #endif #endif #endif #endif #endif /* Initialize the CRC for each braid. */ crc0 = crc; #if N > 1 crc1 = 0; #if N > 2 crc2 = 0; #if N > 3 crc3 = 0; #if N > 4 crc4 = 0; #if N > 5 crc5 = 0; #endif #endif #endif #endif #endif /* Process the first blks-1 blocks, computing the CRCs on each braid independently. */ while (--blks) { /* Load the word for each braid into registers. */ word0 = crc0 ^ words[0]; #if N > 1 word1 = crc1 ^ words[1]; #if N > 2 word2 = crc2 ^ words[2]; #if N > 3 word3 = crc3 ^ words[3]; #if N > 4 word4 = crc4 ^ words[4]; #if N > 5 word5 = crc5 ^ words[5]; #endif #endif #endif #endif #endif words += N; /* Compute and update the CRC for each word. The loop should get unrolled. */ crc0 = crc_braid_table[0][word0 & 0xff]; #if N > 1 crc1 = crc_braid_table[0][word1 & 0xff]; #if N > 2 crc2 = crc_braid_table[0][word2 & 0xff]; #if N > 3 crc3 = crc_braid_table[0][word3 & 0xff]; #if N > 4 crc4 = crc_braid_table[0][word4 & 0xff]; #if N > 5 crc5 = crc_braid_table[0][word5 & 0xff]; #endif #endif #endif #endif #endif for (k = 1; k < W; k++) { crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; #if N > 1 crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; #if N > 2 crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; #if N > 3 crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; #if N > 4 crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; #if N > 5 crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; #endif #endif #endif #endif #endif } } /* Process the last block, combining the CRCs of the N braids at the same time. */ crc = crc_word(crc0 ^ words[0]); #if N > 1 crc = crc_word(crc1 ^ words[1] ^ crc); #if N > 2 crc = crc_word(crc2 ^ words[2] ^ crc); #if N > 3 crc = crc_word(crc3 ^ words[3] ^ crc); #if N > 4 crc = crc_word(crc4 ^ words[4] ^ crc); #if N > 5 crc = crc_word(crc5 ^ words[5] ^ crc); #endif #endif #endif #endif #endif words += N; } else { /* Big endian. */ z_word_t crc0, word0, comb; #if N > 1 z_word_t crc1, word1; #if N > 2 z_word_t crc2, word2; #if N > 3 z_word_t crc3, word3; #if N > 4 z_word_t crc4, word4; #if N > 5 z_word_t crc5, word5; #endif #endif #endif #endif #endif /* Initialize the CRC for each braid. */ crc0 = byte_swap(crc); #if N > 1 crc1 = 0; #if N > 2 crc2 = 0; #if N > 3 crc3 = 0; #if N > 4 crc4 = 0; #if N > 5 crc5 = 0; #endif #endif #endif #endif #endif /* Process the first blks-1 blocks, computing the CRCs on each braid independently. */ while (--blks) { /* Load the word for each braid into registers. */ word0 = crc0 ^ words[0]; #if N > 1 word1 = crc1 ^ words[1]; #if N > 2 word2 = crc2 ^ words[2]; #if N > 3 word3 = crc3 ^ words[3]; #if N > 4 word4 = crc4 ^ words[4]; #if N > 5 word5 = crc5 ^ words[5]; #endif #endif #endif #endif #endif words += N; /* Compute and update the CRC for each word. The loop should get unrolled. */ crc0 = crc_braid_big_table[0][word0 & 0xff]; #if N > 1 crc1 = crc_braid_big_table[0][word1 & 0xff]; #if N > 2 crc2 = crc_braid_big_table[0][word2 & 0xff]; #if N > 3 crc3 = crc_braid_big_table[0][word3 & 0xff]; #if N > 4 crc4 = crc_braid_big_table[0][word4 & 0xff]; #if N > 5 crc5 = crc_braid_big_table[0][word5 & 0xff]; #endif #endif #endif #endif #endif for (k = 1; k < W; k++) { crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; #if N > 1 crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; #if N > 2 crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; #if N > 3 crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; #if N > 4 crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; #if N > 5 crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; #endif #endif #endif #endif #endif } } /* Process the last block, combining the CRCs of the N braids at the same time. */ comb = crc_word_big(crc0 ^ words[0]); #if N > 1 comb = crc_word_big(crc1 ^ words[1] ^ comb); #if N > 2 comb = crc_word_big(crc2 ^ words[2] ^ comb); #if N > 3 comb = crc_word_big(crc3 ^ words[3] ^ comb); #if N > 4 comb = crc_word_big(crc4 ^ words[4] ^ comb); #if N > 5 comb = crc_word_big(crc5 ^ words[5] ^ comb); #endif #endif #endif #endif #endif words += N; crc = byte_swap(comb); } /* Update the pointer to the remaining bytes to process. */ buf = (unsigned char const *)words; } #endif /* W */ /* Complete the computation of the CRC on any remaining bytes. */ while (len >= 8) { len -= 8; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } while (len) { len--; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } /* Return the CRC, post-conditioned. */ return crc ^ 0xffffffff; } #endif /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; uInt len; { return crc32_z(crc, buf, len); } /* ========================================================================= */ uLong ZEXPORT crc32_combine64(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); } /* ========================================================================= */ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc1; uLong crc2; z_off_t len2; { return crc32_combine64(crc1, crc2, (z_off64_t)len2); } /* ========================================================================= */ uLong ZEXPORT crc32_combine_gen64(len2) z_off64_t len2; { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ return x2nmodp(len2, 3); } /* ========================================================================= */ uLong ZEXPORT crc32_combine_gen(len2) z_off_t len2; { return crc32_combine_gen64((z_off64_t)len2); } /* ========================================================================= */ uLong ZEXPORT crc32_combine_op(crc1, crc2, op) uLong crc1; uLong crc2; uLong op; { return multmodp(op, crc1) ^ (crc2 & 0xffffffff); } ================================================ FILE: third_party/libz/crc32.h ================================================ // clang-format off /* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const z_crc_t FAR crc_table[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; #ifdef W #if W == 8 local const z_word_t FAR crc_big_table[] = { 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, 0x8def022d00000000}; #else /* W == 4 */ local const z_word_t FAR crc_big_table[] = { 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, 0x8def022d}; #endif #if N == 1 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6}, {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, 0x92364a30}, {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, 0xe4c4abcc}, {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, 0xca64c78c}, {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1}, {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed}, {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72}, {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, 0x8def022d00000000}, {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, 0x72fd249300000000}, {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, 0xed3498be00000000}, {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, 0xf10605de00000000}, {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, 0x8cc764ca00000000}, {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, 0xccabc4e400000000}, {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, 0x304a369200000000}, {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, 0xe6064b2600000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1}, {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed}, {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72}, {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, 0x8def022d}, {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, 0x72fd2493}, {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, 0xed3498be}, {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, 0xf10605de}}; #endif #endif #if N == 2 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, 0x0d7139d7}, {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, 0x1c53e98a}, {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, 0x3f88e851}, {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, 0x3dee8ca6}, {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, 0x36197165}, {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, 0x1a3b93aa}, {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, 0xe147d714}, {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, 0x494f0c4b}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, 0x4b0c4f4900000000}, {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, 0x14d747e100000000}, {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, 0xaa933b1a00000000}, {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, 0x6571193600000000}, {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, 0xa68cee3d00000000}, {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, 0x51e8883f00000000}, {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, 0x8ae9531c00000000}, {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, 0xd739710d00000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6}, {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, 0x92364a30}, {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, 0xe4c4abcc}, {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, 0xca64c78c}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, 0x8cc764ca}, {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, 0xccabc4e4}, {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, 0x304a3692}, {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, 0xe6064b26}}; #endif #endif #if N == 3 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, 0x09cd8551}, {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, 0x7bc97a0c}, {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, 0x7851a2ca}, {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, 0x566b6848}, {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, 0xd8ac6b35}, {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, 0xa140efa8}, {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, 0x917cd6a1}, {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, 0x18ba364e}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, 0x4e36ba1800000000}, {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, 0xa1d67c9100000000}, {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, 0xa8ef40a100000000}, {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, 0x356bacd800000000}, {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, 0x48686b5600000000}, {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, 0xcaa2517800000000}, {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, 0x0c7ac97b00000000}, {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, 0x5185cd0900000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, 0x36197165}, {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, 0x1a3b93aa}, {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, 0xe147d714}, {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, 0x494f0c4b}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, 0x4b0c4f49}, {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, 0x14d747e1}, {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, 0xaa933b1a}, {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, 0x65711936}}; #endif #endif #if N == 4 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, 0xe3c45916}, {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, 0xa7520488}, {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, 0x3522e9e4}, {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, 0x97411e28}, {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, 0x93c7a00b}, {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, 0xce5f968d}, {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, 0x3e721277}, {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, 0x1c65ace7}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, 0xe7ac651c00000000}, {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, 0x7712723e00000000}, {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, 0x8d965fce00000000}, {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, 0x0ba0c79300000000}, {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, 0x281e419700000000}, {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, 0xe4e9223500000000}, {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, 0x880452a700000000}, {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, 0x1659c4e300000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, 0x0d7139d7}, {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, 0x1c53e98a}, {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, 0x3f88e851}, {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, 0x3dee8ca6}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, 0xa68cee3d}, {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, 0x51e8883f}, {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, 0x8ae9531c}, {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, 0xd739710d}}; #endif #endif #if N == 5 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, 0xe9947565}, {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, 0xf7d05006}, {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, 0xb2075b94}, {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, 0xba50bcb9}, {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, 0x808abcf4}, {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, 0xefdb3f95}, {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, 0x0e2fbf43}, {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, 0xf4377108}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, 0x087137f400000000}, {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, 0x43bf2f0e00000000}, {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, 0x953fdbef00000000}, {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, 0xf4bc8a8000000000}, {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, 0xb9bc50ba00000000}, {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, 0x945b07b200000000}, {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, 0x0650d0f700000000}, {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, 0x657594e900000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, 0xd8ac6b35}, {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, 0xa140efa8}, {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, 0x917cd6a1}, {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, 0x18ba364e}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, 0x4e36ba18}, {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, 0xa1d67c91}, {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, 0xa8ef40a1}, {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, 0x356bacd8}}; #endif #endif #if N == 6 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, 0x8568a0a8}, {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, 0x0d907052}, {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, 0xfd1a6c8a}, {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, 0x7895f01a}, {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, 0x9239b848}, {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, 0xeb36d3cc}, {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, 0x38e5f3c5}, {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, 0x3d3101a2}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, 0xa201313d00000000}, {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, 0xc5f3e53800000000}, {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, 0xccd336eb00000000}, {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, 0x48b8399200000000}, {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, 0x1af0957800000000}, {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, 0x8a6c1afd00000000}, {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, 0x5270900d00000000}, {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, 0xa8a0688500000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, 0x09cd8551}, {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, 0x7bc97a0c}, {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, 0x7851a2ca}, {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, 0x566b6848}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, 0x48686b56}, {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, 0xcaa25178}, {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, 0x0c7ac97b}, {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, 0x5185cd09}}; #endif #endif #endif local const z_crc_t FAR x2n_table[] = { 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c}; ================================================ FILE: third_party/libz/deflate.c ================================================ // clang-format off /* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ /* @(#) $Id$ */ #include "third_party/libz/deflate.h" const char deflate_copyright[] = " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ local int deflateStateCheck OF((z_streamp strm)); local void slide_hash OF((deflate_state *s)); local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); #ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); #endif local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); local uInt longest_match OF((deflate_state *s, IPos cur_match)); #ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST local const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to UPDATE_HASH are made with consecutive input * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to INSERT_STRING are made with consecutive input * characters and the first MIN_MATCH bytes of str are valid (except for * the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ do { \ s->head[s->hash_size - 1] = NIL; \ zmemzero((Bytef *)s->head, \ (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ } while (0) /* =========================================================================== * Slide the hash table when sliding the window down (could be avoided with 32 * bit values at the expense of memory usage). We slide even when level == 0 to * keep the hash table consistent if we switch back to level > 0 later. */ local void slide_hash(s) deflate_state *s; { unsigned n, m; Posf *p; uInt wsize = s->w_size; n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m - wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m - wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif } /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; int level; const char *version; int stream_size; { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size) z_streamp strm; int level; int method; int windowBits; int memLevel; int strategy; const char *version; int stream_size; { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; if (windowBits < -15) return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; s->status = INIT_STATE; /* to pass state test in deflateReset() */ s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ /* We overlay pending_buf and sym_buf. This works since the average size * for length/distance pairs over any compressed block is assured to be 31 * bits or less. * * Analysis: The longest fixed codes are a length code of 8 bits plus 5 * extra bits, for lengths 131 to 257. The longest fixed distance codes are * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest * possible fixed-codes length/distance pair is then 31 bits total. * * sym_buf starts one-fourth of the way into pending_buf. So there are * three bytes in sym_buf for every four bytes in pending_buf. Each symbol * in sym_buf is three bytes -- two for the distance and one for the * literal/length. As each symbol is consumed, the pointer to the next * sym_buf value to read moves forward three bytes. From that symbol, up to * 31 bits are written to pending_buf. The closest the written pending_buf * bits gets to the next sym_buf symbol to read is just before the last * code is written. At that time, 31*(n - 2) bits have been written, just * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 * symbols are written.) The closest the writing gets to what is unread is * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and * can range from 128 to 32768. * * Therefore, at a minimum, there are 142 bits of space between what is * written and what is read in the overlain buffers, so the symbols cannot * be overwritten by the compressed data. That space is actually 139 bits, * due to the three-bit fixed-code block header. * * That covers the case where either Z_FIXED is specified, forcing fixed * codes, or when the use of fixed codes is chosen, because that choice * results in a smaller compressed block than dynamic codes. That latter * condition then assures that the above analysis also covers all dynamic * blocks. A dynamic-code block will only be chosen to be emitted if it has * fewer bits than a fixed-code block would for the same set of symbols. * Therefore its average symbol length is assured to be less than 31. So * the compressed data for a dynamic block also cannot overwrite the * symbols from which it is being constructed. */ s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4); s->pending_buf_size = (ulg)s->lit_bufsize * 4; if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->sym_buf = s->pending_buf + s->lit_bufsize; s->sym_end = (s->lit_bufsize - 1) * 3; /* We avoid equality with lit_bufsize*3 because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ local int deflateStateCheck(strm) z_streamp strm; { deflate_state *s; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; s = strm->state; if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && #ifdef GZIP s->status != GZIP_STATE && #endif s->status != EXTRA_STATE && s->status != NAME_STATE && s->status != COMMENT_STATE && s->status != HCRC_STATE && s->status != BUSY_STATE && s->status != FINISH_STATE)) return 1; return 0; } /* ========================================================================= */ int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { deflate_state *s; uInt str, n; int wrap; unsigned avail; z_const unsigned char *next; if (deflateStateCheck(strm) || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s->w_size) { if (wrap == 0) { /* already empty otherwise */ CLEAR_HASH(s); s->strstart = 0; s->block_start = 0L; s->insert = 0; } dictionary += dictLength - s->w_size; /* use the tail */ dictLength = s->w_size; } /* insert dictionary into window and hash */ avail = strm->avail_in; next = strm->next_in; strm->avail_in = dictLength; strm->next_in = (z_const Bytef *)dictionary; fill_window(s); while (s->lookahead >= MIN_MATCH) { str = s->strstart; n = s->lookahead - (MIN_MATCH-1); do { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; } while (--n); s->strstart = str; s->lookahead = MIN_MATCH-1; fill_window(s); } s->strstart += s->lookahead; s->block_start = (long)s->strstart; s->insert = s->lookahead; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; { deflate_state *s; uInt len; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; len = s->strstart + s->lookahead; if (len > s->w_size) len = s->w_size; if (dictionary != Z_NULL && len) zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); if (dictLength != Z_NULL) *dictLength = len; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateResetKeep(strm) z_streamp strm; { deflate_state *s; if (deflateStateCheck(strm)) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = #ifdef GZIP s->wrap == 2 ? GZIP_STATE : #endif INIT_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = -2; _tr_init(s); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateReset(strm) z_streamp strm; { int ret; ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ int ZEXPORT deflateSetHeader(strm, head) z_streamp strm; gz_headerp head; { if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePending(strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { deflate_state *s; int put; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; if (bits < 0 || bits > 16 || s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; if (put > bits) put = bits; s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; _tr_flush_bits(s); value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; int level; int strategy; { deflate_state *s; compress_func func; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && s->last_flush != -2) { /* Flush the last buffer: */ int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR) return err; if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) return Z_BUF_ERROR; } if (s->level != level) { if (s->level == 0 && s->matches != 0) { if (s->matches == 1) slide_hash(s); else CLEAR_HASH(s); s->matches = 0; } s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) z_streamp strm; int good_length; int max_lazy; int nice_length; int max_chain; { deflate_state *s; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; s->good_match = (uInt)good_length; s->max_lazy_match = (uInt)max_lazy; s->nice_match = nice_length; s->max_chain_length = (uInt)max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns a * close to exact, as well as small, upper bound on the compressed size. This * is an expansion of ~0.03%, plus a small constant. * * For any setting other than those defaults for windowBits and memLevel, one * of two worst case bounds is returned. This is at most an expansion of ~4% or * ~13%, plus a small constant. * * Both the 0.03% and 4% derive from the overhead of stored blocks. The first * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second * is for stored blocks of 127 bytes (the worst case memLevel == 1). The * expansion results from five bytes of header for each stored block. * * The larger expansion of 13% results from a window size less than or equal to * the symbols buffer size (windowBits <= memLevel + 7). In that case some of * the data being compressed may have slid out of the sliding window, impeding * a stored block from being emitted. Then the only choice is a fixed or * dynamic block, where a fixed block limits the maximum expansion to 9 bits * per 8-bit byte, plus 10 bits for every block. The smallest block size for * which this can occur is 255 (memLevel == 2). * * Shifts are used to approximate divisions, for speed. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; uLong fixedlen, storelen, wraplen; /* upper bound for fixed blocks with 9-bit literals and length 255 (memLevel == 2, which is the lowest that may not use stored blocks) -- ~13% overhead plus a small constant */ fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + (sourceLen >> 9) + 4; /* upper bound for stored blocks with length 127 (memLevel == 1) -- ~4% overhead plus a small constant */ storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + (sourceLen >> 11) + 7; /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; #ifdef GZIP case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ Bytef *str; if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; #endif default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen; /* default settings: return tight bound for that case -- ~0.03% overhead plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB(s, b) deflate_state *s; uInt b; { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output, except for * some deflate_stored() output, goes through this function so some * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; { unsigned len; deflate_state *s = strm->state; _tr_flush_bits(s); len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; s->pending_out += len; strm->total_out += len; strm->avail_out -= len; s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } /* =========================================================================== * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. */ #define HCRC_UPDATE(beg) \ do { \ if (s->gzhead->hcrc && s->pending > (beg)) \ strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ s->pending - (beg)); \ } while (0) /* ========================================================================= */ int ZEXPORT deflate(strm, flush) z_streamp strm; int flush; { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->avail_in != 0 && strm->next_in == Z_NULL) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); old_flush = s->last_flush; s->last_flush = flush; /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Write the header */ if (s->status == INIT_STATE && s->wrap == 0) s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } #ifdef GZIP if (s->status == GZIP_STATE) { /* gzip header */ strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; while (s->pending + left > s->pending_buf_size) { uInt copy = s->pending_buf_size - s->pending; zmemcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, copy); s->pending = s->pending_buf_size; HCRC_UPDATE(beg); s->gzindex += copy; flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; left -= copy; } zmemcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, left); s->pending += left; HCRC_UPDATE(beg); s->gzindex = 0; } s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); HCRC_UPDATE(beg); s->gzindex = 0; } s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); HCRC_UPDATE(beg); } s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) { flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); } s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } #endif /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->level == 0 ? deflate_stored(s, flush) : s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; s->insert = 0; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd(strm) z_streamp strm; { int status; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; status = strm->state->status; /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy(dest, source) z_streamp dest; z_streamp source; { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->sym_buf = ds->pending_buf + ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local unsigned read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, buf, len); } #endif strm->next_in += len; strm->total_in += len; return len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init(s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = (int)s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && *(ushf*)(scan += 2) == *(ushf*)(match += 2) && *(ushf*)(scan += 2) == *(ushf*)(match += 2) && *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window + strstart + 257 */ Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len - 1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan + best_len - 1); #else scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef ZLIB_DEBUG #define EQUAL 0 /* result of memcmp for equal strings */ /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match(s, start, match, length) deflate_state *s; IPos start, match; int length; { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* ZLIB_DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window(s) deflate_state *s; { unsigned n; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize + MAX_DIST(s)) { zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; if (s->insert > s->strstart) s->insert = s->strstart; slide_hash(s); more += wsize; } if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) { uInt str = s->strstart - s->insert; s->ins_h = s->window[str]; UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break; } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* Maximum stored block length in deflate format (not including header). */ #define MAX_STORED 65535 /* Minimum of a and b. */ #define MIN(a, b) ((a) > (b) ? (b) : (a)) /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * * In case deflateParams() is used to later switch to a non-zero compression * level, s->matches (otherwise unused when storing) keeps track of the number * of hash table slides to perform. If s->matches is 1, then one hash table * slide will be done when switching. If s->matches is 2, the maximum value * allowed here, then the hash table will be cleared, since two or more slides * is the same as a clear. * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which * maximizes the opportunities to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { /* Smallest worthy block size when not flushing or finishing. By default * this is 32K. This can be as small as 507 bytes for memLevel == 1. For * large input and output buffers, the stored block size will be larger. */ unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); /* Copy as many min_block or larger stored blocks directly to next_out as * possible. If flushing, copy the remaining available input to next_out as * stored blocks, if there is enough space. */ unsigned len, left, have, last = 0; unsigned used = s->strm->avail_in; do { /* Set len to the maximum size block that we can copy directly with the * available input data and output space. Set left to how much of that * would be copied from what's left in the window. */ len = MAX_STORED; /* maximum deflate stored block length */ have = (s->bi_valid + 42) >> 3; /* number of header bytes */ if (s->strm->avail_out < have) /* need room for header */ break; /* maximum stored block length that will fit in avail_out: */ have = s->strm->avail_out - have; left = s->strstart - s->block_start; /* bytes left in window */ if (len > (ulg)left + s->strm->avail_in) len = left + s->strm->avail_in; /* limit len to the input */ if (len > have) len = have; /* limit len to the output */ /* If the stored block would be less than min_block in length, or if * unable to copy all of the available input when flushing, then try * copying to the window and the pending buffer instead. Also don't * write an empty block when flushing -- deflate() does that. */ if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in)) break; /* Make a dummy stored block in pending to get the header bytes, * including any pending bits. This also updates the debugging counts. */ last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; _tr_stored_block(s, (char *)0, 0L, last); /* Replace the lengths in the dummy stored block with len. */ s->pending_buf[s->pending - 4] = len; s->pending_buf[s->pending - 3] = len >> 8; s->pending_buf[s->pending - 2] = ~len; s->pending_buf[s->pending - 1] = ~len >> 8; /* Write the stored block header bytes. */ flush_pending(s->strm); #ifdef ZLIB_DEBUG /* Update debugging counts for the data about to be copied. */ s->compressed_len += len << 3; s->bits_sent += len << 3; #endif /* Copy uncompressed bytes from the window to next_out. */ if (left) { if (left > len) left = len; zmemcpy(s->strm->next_out, s->window + s->block_start, left); s->strm->next_out += left; s->strm->avail_out -= left; s->strm->total_out += left; s->block_start += left; len -= left; } /* Copy uncompressed bytes directly from next_in to next_out, updating * the check value. */ if (len) { read_buf(s->strm, s->strm->next_out, len); s->strm->next_out += len; s->strm->avail_out -= len; s->strm->total_out += len; } } while (last == 0); /* Update the sliding window with the last s->w_size bytes of the copied * data, or append all of the copied data to the existing window if less * than s->w_size bytes were copied. Also update the number of bytes to * insert in the hash tables, in the event that deflateParams() switches to * a non-zero compression level. */ used -= s->strm->avail_in; /* number of input bytes directly copied */ if (used) { /* If any input was used, then no unused input remains in the window, * therefore s->block_start == s->strstart. */ if (used >= s->w_size) { /* supplant the previous history */ s->matches = 2; /* clear hash */ zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); s->strstart = s->w_size; s->insert = s->strstart; } else { if (s->window_size - s->strstart <= used) { /* Slide the window down. */ s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ if (s->insert > s->strstart) s->insert = s->strstart; } zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); s->strstart += used; s->insert += MIN(used, s->w_size - s->insert); } s->block_start = s->strstart; } if (s->high_water < s->strstart) s->high_water = s->strstart; /* If the last block was written to next_out, then done. */ if (last) return finish_done; /* If flushing and all input has been consumed, then done. */ if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (long)s->strstart == s->block_start) return block_done; /* Fill the window with any remaining input. */ have = s->window_size - s->strstart; if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { /* Slide the window down. */ s->block_start -= s->w_size; s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ have += s->w_size; /* more space now */ if (s->insert > s->strstart) s->insert = s->strstart; } if (have > s->strm->avail_in) have = s->strm->avail_in; if (have) { read_buf(s->strm, s->window + s->strstart, have); s->strstart += have; s->insert += MIN(have, s->w_size - s->insert); } if (s->high_water < s->strstart) s->high_water = s->strstart; /* There was not enough avail_out to write a complete worthy or flushed * stored block to next_out. Write a stored block to pending instead, if we * have enough input for a worthy block, or if flushing and there is enough * room for the remaining input as a stored block in the pending buffer. */ have = (s->bi_valid + 42) >> 3; /* number of header bytes */ /* maximum stored block length that will fit in pending: */ have = MIN(s->pending_buf_size - have, MAX_STORED); min_block = MIN(have, s->w_size); left = s->strstart - s->block_start; if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) { len = MIN(left, have); last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0; _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); s->block_start += len; flush_pending(s->strm); } /* We've done all we can with the available input and output. */ return last ? finish_started : need_more; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart - 1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart - 1])); _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart - 1])); _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest run, plus one for the unrolled loop. */ if (s->lookahead <= MAX_MATCH) { fill_window(s); if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (uInt)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } Assert(scan <= s->window + (uInt)(s->window_size - 1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } ================================================ FILE: third_party/libz/deflate.h ================================================ // clang-format off /* deflate.h -- internal compression state * Copyright (C) 1995-2018 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef DEFLATE_H #define DEFLATE_H #include "third_party/libz/zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define Buf_size 16 /* size of bit buffer in bi_buf */ #define INIT_STATE 42 /* zlib header -> BUSY_STATE */ #ifdef GZIP # define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ #endif #define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ #define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ #define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ #define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ #define BUSY_STATE 113 /* deflate -> FINISH_STATE */ #define FINISH_STATE 666 /* stream complete */ /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } FAR ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ const static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ ulg pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ ulg gzindex; /* where in extra, name, or comment */ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *sym_buf; /* buffer for distances and literals/lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt sym_next; /* running index in sym_buf */ uInt sym_end; /* symbol table full when sym_next reaches this */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ #ifdef ZLIB_DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef ZLIB_DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->sym_buf[s->sym_next++] = 0; \ s->sym_buf[s->sym_next++] = 0; \ s->sym_buf[s->sym_next++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->sym_next == s->sym_end); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ s->sym_buf[s->sym_next++] = (uch)dist; \ s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ s->sym_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->sym_next == s->sym_end); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ ================================================ FILE: third_party/libz/gzclose.c ================================================ // clang-format off /* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "third_party/libz/gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int ZEXPORT gzclose(file) gzFile file; { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); #else return gzclose_r(file); #endif } ================================================ FILE: third_party/libz/gzguts.h ================================================ // clang-format off /* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif # ifdef _FILE_OFFSET_BITS # undef _FILE_OFFSET_BITS # endif #endif #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include #include "third_party/libz/zlib.h" #ifdef STDC # include # include # include #endif #ifndef _POSIX_SOURCE # define _POSIX_SOURCE #endif #include #ifdef _WIN32 # include #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include #endif #if defined(_WIN32) # define WIDECHAR #endif #ifdef WINAPI_FAMILY # define open _open # define read _read # define write _write # define close _close #endif #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif #if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(__CYGWIN__) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #ifndef HAVE_VSNPRINTF # ifdef MSDOS /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), but for now we just assume it doesn't. */ # define NO_vsnprintf # endif # ifdef __TURBOC__ # define NO_vsnprintf # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ # if !defined(vsnprintf) && !defined(NO_vsnprintf) # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) # define vsnprintf _vsnprintf # endif # endif # endif # ifdef __SASC # define NO_vsnprintf # endif # ifdef VMS # define NO_vsnprintf # endif # ifdef __OS400__ # define NO_vsnprintf # endif # ifdef __MVS__ # define NO_vsnprintf # endif #endif /* unlike snprintf (which is required in C99), _snprintf does not guarantee null termination of the result -- however this is only used in gzlib.c where the result is assured to fit in the space provided */ #if defined(_MSC_VER) && _MSC_VER < 1900 # define snprintf _snprintf #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC extern voidp malloc OF((uInt size)); extern void free OF((voidpf ptr)); #endif /* get errno and strerror definition */ #if defined UNDER_CE # include # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else # ifndef NO_STRERROR # include # define zstrerror() strerror(errno) # else # define zstrerror() "stdio error (consult errno)" # endif #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif /* default memLevel */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 #define GZ_WRITE 31153 #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ /* values for gz_state how */ #define LOOK 0 /* look for a gzip header */ #define COPY 1 /* copy input directly */ #define GZIP 2 /* decompress a gzip stream */ /* internal gzip file state data structure */ typedef struct { /* exposed contents for gzgetc() macro */ struct gzFile_s x; /* "x" for exposed */ /* x.have: number of bytes available at x.next */ /* x.next: next output data to deliver or write */ /* x.pos: current position in uncompressed data */ /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer (double-sized when writing) */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ int reset; /* true if a reset is pending after a Z_FINISH */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state FAR *gz_statep; /* shared functions */ void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); #if defined UNDER_CE char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else unsigned ZLIB_INTERNAL gz_intmax OF((void)); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif ================================================ FILE: third_party/libz/gzlib.c ================================================ // clang-format off /* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include #include "third_party/libz/gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif #endif /* Local functions */ local void gz_reset OF((gz_statep)); local gzFile gz_open OF((const void *, int, const char *)); #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to gz_strwinerror The gz_strwinerror function does not change the current setting of GetLastError. */ char ZLIB_INTERNAL *gz_strwinerror(error) DWORD error; { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ local void gz_reset(state) gz_statep state; { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } else /* for writing ... */ state->reset = 0; /* no deflateReset pending */ state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open(path, fd, mode) const void *path; int fd; const char *mode; { gz_statep state; z_size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; #endif #ifdef O_EXCL int exclusive = 0; #endif /* check input */ if (path == NULL) return NULL; /* allocate gzFile structure to return */ state = (gz_statep)malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ state->want = GZBUFSIZE; /* requested buffer size */ state->msg = NULL; /* no error message yet */ /* interpret mode */ state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; else switch (*mode) { case 'r': state->mode = GZ_READ; break; #ifndef NO_GZCOMPRESS case 'w': state->mode = GZ_WRITE; break; case 'a': state->mode = GZ_APPEND; break; #endif case '+': /* can't read and write at the same time */ free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; #ifdef O_CLOEXEC case 'e': cloexec = 1; break; #endif #ifdef O_EXCL case 'x': exclusive = 1; break; #endif case 'f': state->strategy = Z_FILTERED; break; case 'h': state->strategy = Z_HUFFMAN_ONLY; break; case 'R': state->strategy = Z_RLE; break; case 'F': state->strategy = Z_FIXED; break; case 'T': state->direct = 1; break; default: /* could consider as an error, but just ignore */ ; } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { free(state); return NULL; } state->direct = 1; /* for empty file */ } /* save the path name for error messages */ #ifdef WIDECHAR if (fd == -2) { len = wcstombs(NULL, path, 0); if (len == (z_size_t)-1) len = 0; } else #endif len = strlen((const char *)path); state->path = (char *)malloc(len + 1); if (state->path == NULL) { free(state); return NULL; } #ifdef WIDECHAR if (fd == -2) if (len) wcstombs(state->path, path, len + 1); else *(state->path) = 0; else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(state->path, len + 1, "%s", (const char *)path); #else strcpy(state->path, path); #endif /* compute the flags for open() */ oflag = #ifdef O_LARGEFILE O_LARGEFILE | #endif #ifdef O_BINARY O_BINARY | #endif #ifdef O_CLOEXEC (cloexec ? O_CLOEXEC : 0) | #endif (state->mode == GZ_READ ? O_RDONLY : (O_WRONLY | O_CREAT | #ifdef O_EXCL (exclusive ? O_EXCL : 0) | #endif (state->mode == GZ_WRITE ? O_TRUNC : O_APPEND))); /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( #ifdef WIDECHAR fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); free(state); return NULL; } if (state->mode == GZ_APPEND) { LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ state->mode = GZ_WRITE; /* simplify later checks */ } /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { state->start = LSEEK(state->fd, 0, SEEK_CUR); if (state->start == -1) state->start = 0; } /* initialize stream */ gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen64(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzdopen(fd, mode) int fd; const char *mode; { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); #else sprintf(path, "", fd); /* for debugging */ #endif gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ #ifdef WIDECHAR gzFile ZEXPORT gzopen_w(path, mode) const wchar_t *path; const char *mode; { return gz_open(path, -2, mode); } #endif /* -- see zlib.h -- */ int ZEXPORT gzbuffer(file, size) gzFile file; unsigned size; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if ((size << 1) < size) return -1; /* need to be able to double it */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } /* -- see zlib.h -- */ int ZEXPORT gzrewind(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzseek64(file, offset, whence) gzFile file; z_off64_t offset; int whence; { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* check that there's no error */ if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* can only seek from start or relative to current position */ if (whence != SEEK_SET && whence != SEEK_CUR) return -1; /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) offset -= state->x.pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->x.pos += offset; return state->x.pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; offset -= n; } /* request skip (if not zero) */ if (offset) { state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzseek(file, offset, whence) gzFile file; z_off_t offset; int whence; { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gztell64(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t ZEXPORT gztell(file) gzFile file; { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzoffset64(file) gzFile file; { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzoffset(file) gzFile file; { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int ZEXPORT gzeof(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ const char * ZEXPORT gzerror(file, errnum) gzFile file; int *errnum; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ void ZEXPORT gzclearerr(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; /* clear error and end-of-file */ if (state->mode == GZ_READ) { state->eof = 0; state->past = 0; } gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void ZLIB_INTERNAL gz_error(state, err, msg) gz_statep state; int err; const char *msg; { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ if (err != Z_OK && err != Z_BUF_ERROR) state->x.have = 0; /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; /* for an out of memory error, return literal string when requested */ if (err == Z_MEM_ERROR) return; /* construct error message with path */ if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { state->err = Z_MEM_ERROR; return; } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif } #ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax() { unsigned p, q; p = 1; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; } #endif ================================================ FILE: third_party/libz/gzread.c ================================================ // clang-format off /* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include #include "third_party/libz/gzguts.h" /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ local int gz_load(state, buf, len, have) gz_statep state; unsigned char *buf; unsigned len; unsigned *have; { int ret; unsigned get, max = ((unsigned)-1 >> 2) + 1; *have = 0; do { get = len - *have; if (get > max) get = max; ret = read(state->fd, buf + *have, get); if (ret <= 0) break; *have += (unsigned)ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) state->eof = 1; return 0; } /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ local int gz_avail(state) gz_statep state; { unsigned got; z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { if (strm->avail_in) { /* copy what's there to the start */ unsigned char *p = state->in; unsigned const char *q = strm->next_in; unsigned n = strm->avail_in; do { *p++ = *q++; } while (--n); } if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) return -1; strm->avail_in += got; strm->next_in = state->in; } return 0; } /* Look for gzip header, set up for inflate or copy. state->x.have must be 0. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ local int gz_look(state) gz_statep state; { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } state->size = state->want; /* allocate inflate memory */ state->strm.zalloc = Z_NULL; state->strm.zfree = Z_NULL; state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ free(state->out); free(state->in); state->size = 0; gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* get at least the magic bytes in the input buffer */ if (strm->avail_in < 2) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } /* look for gzip magic bytes -- if there, do gzip decoding (note: there is a logical dilemma here when considering the case of a partially written gzip file, to wit, if a single 31 byte is written, then we cannot tell whether this is a single-byte file, or just a partially written gzip file -- for here we assume that if a gzip file is being written, then the header will be written in a single operation, so that reading a single byte is sufficient indication that it is not a gzip file) */ if (strm->avail_in > 1 && strm->next_in[0] == 31 && strm->next_in[1] == 139) { inflateReset(strm); state->how = GZIP; state->direct = 0; return 0; } /* no gzip header -- if we were decoding gzip before, then this is trailing garbage. Ignore the trailing garbage and finish. */ if (state->direct == 0) { strm->avail_in = 0; state->eof = 1; state->x.have = 0; return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in; strm->avail_in = 0; state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. On return, state->x.have and state->x.next point to the just decompressed data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ local int gz_decomp(state) gz_statep state; { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { /* get more input for inflate() */ if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { gz_error(state, Z_BUF_ERROR, "unexpected end of file"); break; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); /* update available output */ state->x.have = had - strm->avail_out; state->x.next = strm->next_out - state->x.have; /* if the gzip stream completed successfully, look for another */ if (ret == Z_STREAM_END) state->how = LOOK; /* good decompression */ return 0; } /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ local int gz_fetch(state) gz_statep state; { z_streamp strm = &(state->strm); do { switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; if (state->how == LOOK) return 0; break; case COPY: /* -> COPY */ if (gz_load(state, state->out, state->size << 1, &(state->x.have)) == -1) return -1; state->x.next = state->out; return 0; case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ strm->avail_out = state->size << 1; strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ local int gz_skip(state, len) gz_statep state; z_off64_t len; { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->x.have) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? (unsigned)len : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; len -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) break; /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; } return 0; } /* Read len bytes into buf from file, or less than len up to the end of the input. Return the number of bytes read. If zero is returned, either the end of file was reached, or there was an error. state->err must be consulted in that case to determine which. */ local z_size_t gz_read(state, buf, len) gz_statep state; voidp buf; z_size_t len; { z_size_t got; unsigned n; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return 0; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* set n to the maximum amount of len that fits in an unsigned int */ n = (unsigned)-1; if (n > len) n = (unsigned)len; /* first just try copying data from the output buffer */ if (state->x.have) { if (state->x.have < n) n = state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || n < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return 0; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ if (gz_load(state, (unsigned char *)buf, n, &n) == -1) return 0; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ state->strm.avail_out = n; state->strm.next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) return 0; n = state->x.have; state->x.have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; state->x.pos += n; } while (len); /* return number of bytes read into user buffer */ return got; } /* -- see zlib.h -- */ int ZEXPORT gzread(file, buf, len) gzFile file; voidp buf; unsigned len; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); return -1; } /* read len or fewer bytes to buf */ len = (unsigned)gz_read(state, buf, len); /* check for an error */ if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* return the number of bytes read (this is assured to fit in an int) */ return (int)len; } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfread(buf, size, nitems, file) voidp buf; z_size_t size; z_size_t nitems; gzFile file; { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return 0; /* compute bytes to read -- error on overflow */ len = nitems * size; if (size && len / size != nitems) { gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } /* read len or fewer bytes to buf, return the number of full items read */ return len ? gz_read(state, buf, len) / size : 0; } /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif int ZEXPORT gzgetc(file) gzFile file; { unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gz_read() */ return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; } int ZEXPORT gzgetc_(file) gzFile file; { return gzgetc(file); } /* -- see zlib.h -- */ int ZEXPORT gzungetc(c, file) int c; gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* can't push EOF */ if (c < 0) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* if no room, give up (must have already done a gzungetc()) */ if (state->x.have == (state->size << 1)) { gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ if (state->x.next == state->out) { unsigned char *src = state->out + state->x.have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; state->x.next = dest; } state->x.have++; state->x.next--; state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ char * ZEXPORT gzgets(file, buf, len) gzFile file; char *buf; int len; { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return NULL; } /* copy output bytes up to new line or len - 1, whichever comes first -- append a terminating zero to the string (we don't check for a zero in the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ if (state->x.have == 0 && gz_fetch(state) == -1) return NULL; /* error */ if (state->x.have == 0) { /* end of file */ state->past = 1; /* read past end */ break; /* return what we have */ } /* look for end-of-line in current output buffer */ n = state->x.have > left ? left : state->x.have; eol = (unsigned char *)memchr(state->x.next, '\n', n); if (eol != NULL) n = (unsigned)(eol - state->x.next) + 1; /* copy through end-of-line, or remainder if not found */ memcpy(buf, state->x.next, n); state->x.have -= n; state->x.next += n; state->x.pos += n; left -= n; buf += n; } while (left && eol == NULL); /* return terminated string, or if nothing, end of file */ if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ int ZEXPORT gzdirect(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int ZEXPORT gzclose_r(file) gzFile file; { int ret, err; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return Z_STREAM_ERROR; /* free memory and close file */ if (state->size) { inflateEnd(&(state->strm)); free(state->out); free(state->in); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); return ret ? Z_ERRNO : err; } ================================================ FILE: third_party/libz/gzwrite.c ================================================ // clang-format off /* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include #include "third_party/libz/gzguts.h" /* Local functions */ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on a memory allocation failure, or 0 on success. */ local int gz_init(state) gz_statep state; { int ret; z_streamp strm = &(state->strm); /* allocate input buffer (double size for gzprintf) */ state->in = (unsigned char *)malloc(state->want << 1); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* only need output buffer and deflate state if compressing */ if (!state->direct) { /* allocate output buffer */ state->out = (unsigned char *)malloc(state->want); if (state->out == NULL) { free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* allocate deflate memory, set up for gzip compression */ strm->zalloc = Z_NULL; strm->zfree = Z_NULL; strm->opaque = Z_NULL; ret = deflateInit2(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } strm->next_in = NULL; } /* mark state as initialized */ state->size = state->want; /* initialize write buffer if compressing */ if (!state->direct) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; } return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file or if gz_init() fails to allocate memory, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ local int gz_comp(state, flush) gz_statep state; int flush; { int ret, writ; unsigned have, put, max = ((unsigned)-1 >> 2) + 1; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; /* write directly if requested */ if (state->direct) { while (strm->avail_in) { put = strm->avail_in > max ? max : strm->avail_in; writ = write(state->fd, strm->next_in, put); if (writ < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } strm->avail_in -= (unsigned)writ; strm->next_in += writ; } return 0; } /* check for a pending reset */ if (state->reset) { /* don't start a new gzip member unless there is data to write */ if (strm->avail_in == 0) return 0; deflateReset(strm); state->reset = 0; } /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { while (strm->next_out > state->x.next) { put = strm->next_out - state->x.next > (int)max ? max : (unsigned)(strm->next_out - state->x.next); writ = write(state->fd, state->x.next, put); if (writ < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } state->x.next += writ; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = state->out; } } /* compress */ have = strm->avail_out; ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) state->reset = 1; /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on a write error or memory allocation failure by gz_comp(), or 0 on success. */ local int gz_zero(state, len) gz_statep state; z_off64_t len; { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; } strm->avail_in = n; strm->next_in = state->in; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; } return 0; } /* Write len bytes from buf to file. Return the number of bytes written. If the returned value is less than len, then there was an error. */ local z_size_t gz_write(state, buf, len) gz_statep state; voidpc buf; z_size_t len; { z_size_t put = len; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* for small len, copy to input buffer, otherwise compress directly */ if (len < state->size) { /* copy to input buffer, compress when full */ do { unsigned have, copy; if (state->strm.avail_in == 0) state->strm.next_in = state->in; have = (unsigned)((state->strm.next_in + state->strm.avail_in) - state->in); copy = state->size - have; if (copy > len) copy = (unsigned)len; memcpy(state->in + have, buf, copy); state->strm.avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ state->strm.next_in = (z_const Bytef *)buf; do { unsigned n = (unsigned)-1; if (n > len) n = (unsigned)len; state->strm.avail_in = n; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; len -= n; } while (len); } /* input was all buffered or compressed */ return put; } /* -- see zlib.h -- */ int ZEXPORT gzwrite(file, buf, len) gzFile file; voidpc buf; unsigned len; { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* write len bytes from buf (the return value will fit in an int) */ return (int)gz_write(state, buf, len); } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) voidpc buf; z_size_t size; z_size_t nitems; gzFile file; { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* compute bytes to read -- error on overflow */ len = nitems * size; if (size && len / size != nitems) { gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } /* write len bytes to buf, return the number of full items written */ return len ? gz_write(state, buf, len) / size : 0; } /* -- see zlib.h -- */ int ZEXPORT gzputc(file, c) gzFile file; int c; { unsigned have; unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ if (state->size) { if (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); if (have < state->size) { state->in[have] = (unsigned char)c; strm->avail_in++; state->x.pos++; return c & 0xff; } } /* no room in buffer or not initialized, use gz_write() */ buf[0] = (unsigned char)c; if (gz_write(state, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int ZEXPORT gzputs(file, s) gzFile file; const char *s; { z_size_t len, put; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* write string */ len = strlen(s); if ((int)len < 0 || (unsigned)len != len) { gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); return -1; } put = gz_write(state, s, len); return put < len ? -1 : (int)len; } #if defined(STDC) || defined(Z_HAVE_STDARG_H) #include /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int len; unsigned left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return state->err; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* do the printf() into the input buffer, put length in len -- the input buffer is double-sized just for this function, so there is guaranteed to be state->size bytes available after the current contents */ if (strm->avail_in == 0) strm->next_in = state->in; next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); next[state->size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf(next, format, va); for (len = 0; len < state->size; len++) if (next[len] == 0) break; # else len = vsprintf(next, format, va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf(next, state->size, format, va); len = strlen(next); # else len = vsnprintf(next, state->size, format, va); # endif #endif /* check that printf() results fit in buffer */ if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) return 0; /* update buffer and position, compress first half if past that */ strm->avail_in += (unsigned)len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memmove(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return len; } int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { va_list va; int ret; va_start(va, format); ret = gzvprintf(file, format, va); va_end(va); return ret; } #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { unsigned len, left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) return Z_STREAM_ERROR; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return state->error; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->error; } /* do the printf() into the input buffer, put length in len -- the input buffer is double-sized just for this function, so there is guaranteed to be state->size bytes available after the current contents */ if (strm->avail_in == 0) strm->next_in = state->in; next = (char *)(strm->next_in + strm->avail_in); next[state->size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) if (next[len] == 0) break; # else len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen(next); # else len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ if (len == 0 || len >= state->size || next[state->size - 1] != 0) return 0; /* update buffer and position, compress first half if past that */ strm->avail_in += len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memmove(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return (int)len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush(file, flush) gzFile file; int flush; { gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* check flush parameter */ if (flush < 0 || flush > Z_FINISH) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* compress remaining data with requested flush */ (void)gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int ZEXPORT gzsetparams(file, level, strategy) gzFile file; int level; int strategy; { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) return state->err; deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int ZEXPORT gzclose_w(file) gzFile file; { int ret = Z_OK; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) ret = state->err; } /* flush, free memory, and close file */ if (gz_comp(state, Z_FINISH) == -1) ret = state->err; if (state->size) { if (!state->direct) { (void)deflateEnd(&(state->strm)); free(state->out); } free(state->in); } gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; free(state); return ret; } ================================================ FILE: third_party/libz/infback.c ================================================ // clang-format off /* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* This code is largely copied from inflate.c. Normally either infback.o or inflate.o would be linked into an application--not both. The interface with inffast.c is retained so that optimized assembler-coded versions of inflate_fast() can be used with either inflate.c or infback.c. */ #include "third_party/libz/zutil.h" #include "third_party/libz/inftrees.h" #include "third_party/libz/inflate.h" #include "third_party/libz/inffast.h" /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) z_streamp strm; int windowBits; unsigned char FAR *window; const char *version; int stream_size; { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; state->sane = 1; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "third_party/libz/inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } /* Macros for inflateBack(): */ /* Load returned state from inflate_fast() */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Set state from registers for inflate_fast() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Assure that some input is available. If input is requested, but denied, then return a Z_BUF_ERROR from inflateBack(). */ #define PULL() \ do { \ if (have == 0) { \ have = in(in_desc, &next); \ if (have == 0) { \ next = Z_NULL; \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflateBack() with an error if there is no input available. */ #define PULLBYTE() \ do { \ PULL(); \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflateBack() with an error. */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Assure that some output space is available, by writing out the window if it's full. If the write fails, return from inflateBack() with a Z_BUF_ERROR. */ #define ROOM() \ do { \ if (left == 0) { \ put = state->window; \ left = state->wsize; \ state->whave = left; \ if (out(out_desc, put, left)) { \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* strm provides the memory allocation functions and window buffer on input, and provides information on the unused input on return. For Z_DATA_ERROR returns, strm will also provide an error message. in() and out() are the call-back input and output functions. When inflateBack() needs more input, it calls in(). When inflateBack() has filled the window with output, or when it completes with data in the window, it calls out() to write out the data. The application must not change the provided input until in() is called again or inflateBack() returns. The application must not change the window/output buffer until inflateBack() returns. in() and out() are called with a descriptor parameter provided in the inflateBack() call. This parameter can be a structure that provides the information required to do the read or write, as well as accumulated information on the input and output such as totals and check values. in() should return zero on failure. out() should return non-zero on failure. If either in() or out() fails, than inflateBack() returns a Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) z_streamp strm; in_func in; void FAR *in_desc; out_func out; void FAR *out_desc; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Check that the strm exists and that the state was initialized */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* Reset the state */ strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0; next = strm->next_in; have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0; put = state->window; left = state->wsize; /* Inflate until end of block marked as last */ for (;;) switch (state->mode) { case TYPE: /* determine and dispatch block type */ if (state->last) { BYTEBITS(); state->mode = DONE; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN; /* decode codes */ break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: /* get and verify stored block length */ BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); /* copy stored block from input to output */ while (state->length != 0) { copy = state->length; PULL(); ROOM(); if (copy > have) copy = have; if (copy > left) copy = left; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: /* get dynamic table entries descriptor */ NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); /* get code length code lengths (not a typo) */ state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); /* get length and distance code code lengths */ state->have = 0; while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; /* fallthrough */ case LEN: /* use inflate_fast() if we have enough input and output */ if (have >= 6 && left >= 258) { RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; inflate_fast(strm, state->wsize); LOAD(); break; } /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); state->length = (unsigned)here.val; /* process literal */ if (here.op == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); ROOM(); *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; } /* process end of block */ if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } /* invalid code */ if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } /* length code -- get extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); } Tracevv((stderr, "inflate: length %u\n", state->length)); /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; /* get distance extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); } if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } Tracevv((stderr, "inflate: distance %u\n", state->offset)); /* copy match from window to output */ do { ROOM(); copy = state->wsize - state->offset; if (copy < left) { from = put + copy; copy = left - copy; } else { from = put - state->offset; copy = left; } if (copy > state->length) copy = state->length; state->length -= copy; left -= copy; do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: /* inflate stream terminated properly */ ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; default: /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } /* Write leftover output and return unused input */ inf_leave: if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left) && ret == Z_STREAM_END) ret = Z_BUF_ERROR; } strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBackEnd(strm) z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } ================================================ FILE: third_party/libz/inffast.c ================================================ // clang-format off /* inffast.c -- fast decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "third_party/libz/zutil.h" #include "third_party/libz/inftrees.h" #include "third_party/libz/inflate.h" #include "third_party/libz/inffast.h" #ifdef ASMINF # pragma message("Assembler code may have bugs -- use at your own risk") #else /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code const *here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in; last = in + (strm->avail_in - 5); out = strm->next_out; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = lcode + (hold & lmask); dolen: op = (unsigned)(here->bits); hold >>= op; bits -= op; op = (unsigned)(here->op); if (op == 0) { /* literal */ Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here->val)); *out++ = (unsigned char)(here->val); } else if (op & 16) { /* length base */ len = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = dcode + (hold & dmask); dodist: op = (unsigned)(here->bits); hold >>= op; bits -= op; op = (unsigned)(here->op); if (op & 16) { /* distance base */ dist = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { *out++ = 0; } while (--len); continue; } len -= op - whave; do { *out++ = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { *out++ = *from++; } while (--len); continue; } #endif } from = window; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { *out++ = *from++; } while (--op); from = window; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } while (len > 2); if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode + here->val + (hold & ((1U << op) - 1)); goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode + here->val + (hold & ((1U << op) - 1)); goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in; strm->next_out = out; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ ================================================ FILE: third_party/libz/inffast.h ================================================ // clang-format off /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); ================================================ FILE: third_party/libz/inffixed.h ================================================ // clang-format off /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of this library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; ================================================ FILE: third_party/libz/inflate.c ================================================ // clang-format off /* inflate.c -- zlib decompression * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "third_party/libz/zutil.h" #include "third_party/libz/inftrees.h" #include "third_party/libz/inflate.h" #include "third_party/libz/inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local int inflateStateCheck OF((z_streamp strm)); local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); local int inflateStateCheck(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; state = (struct inflate_state FAR *)strm->state; if (state == Z_NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) return 1; return 0; } int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->flags = -1; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; { int wrap; struct inflate_state FAR *state; /* get the state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { if (windowBits < -15) return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; const char *version; int stream_size; { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->strm = strm; state->window = Z_NULL; state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(strm, version, stream_size) z_streamp strm; const char *version; int stream_size; { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += (unsigned)value << state->bits; state->bits += (uInt)bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "third_party/libz/inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(strm, end, copy) z_streamp strm; const Bytef *end; unsigned copy; { struct inflate_state FAR *state; unsigned dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE_CHECK(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(strm, flush) z_streamp strm; int flush; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (inflateStateCheck(strm) || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ if (state->wbits == 0) state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; state->flags = 0; /* indicate zlib header */ Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = TIME; /* fallthrough */ case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC4(state->check, hold); INITBITS(); state->mode = OS; /* fallthrough */ case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; /* fallthrough */ case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; /* fallthrough */ case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL && (len = state->head->extra_len - state->length) < state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; /* fallthrough */ case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; /* fallthrough */ case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; /* fallthrough */ case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if ((state->wrap & 4) && hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; /* fallthrough */ case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; /* fallthrough */ case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; /* fallthrough */ case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; /* fallthrough */ case COPY_: state->mode = COPY; /* fallthrough */ case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; /* fallthrough */ case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; /* fallthrough */ case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; /* fallthrough */ case LEN_: state->mode = LEN; /* fallthrough */ case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; /* fallthrough */ case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; /* fallthrough */ case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; /* fallthrough */ case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; /* fallthrough */ case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; /* fallthrough */ case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; /* fallthrough */ case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: /* fallthrough */ default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); } if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; unsigned long dictid; int ret; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary + dictLength, dictLength); if (ret) { state->mode = MEM; return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(strm, head) z_streamp strm; gz_headerp head; { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; const unsigned char FAR *buf; unsigned len; { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(strm) z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ int flags; /* temporary to save header status */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; if (state->flags == -1) state->wrap = 0; /* if no header yet, treat as raw */ else state->wrap &= ~4; /* no point in computing a check value now */ flags = state->flags; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->flags = flags; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(dest, source) z_streamp dest; z_streamp source; { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (inflateStateCheck(source) || dest == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(strm, subvert) z_streamp strm; int subvert; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR state->sane = !subvert; return Z_OK; #else (void)subvert; state->sane = 1; return Z_DATA_ERROR; #endif } int ZEXPORT inflateValidate(strm, check) z_streamp strm; int check; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (check && state->wrap) state->wrap |= 4; else state->wrap &= ~4; return Z_OK; } long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return -(1L << 16); state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } unsigned long ZEXPORT inflateCodesUsed(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; return (unsigned long)(state->next - state->codes); } ================================================ FILE: third_party/libz/inflate.h ================================================ // clang-format off /* inflate.h -- internal inflate state definition * Copyright (C) 1995-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD = 16180, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* State maintained between inflate() calls -- approximately 7K bytes, not including the allocated sliding window, which is up to 32K bytes. */ struct inflate_state { z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags, 0 if zlib, or -1 if raw or no header yet */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const FAR *lencode; /* starting table for length/literal codes */ code const FAR *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code FAR *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; ================================================ FILE: third_party/libz/inftrees.c ================================================ // clang-format off /* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "third_party/libz/zutil.h" #include "third_party/libz/inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ unsigned match; /* use base and extra for symbol >= match */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ match = 20; break; case LENS: base = lbase; extra = lext; match = 257; break; default: /* DISTS */ base = dbase; extra = dext; match = 0; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if (work[sym] + 1U < match) { here.op = (unsigned char)0; here.val = work[sym]; } else if (work[sym] >= match) { here.op = (unsigned char)(extra[work[sym] - match]); here.val = base[work[sym] - match]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; next[huff] = here; } /* set return parameters */ *table += used; *bits = root; return 0; } ================================================ FILE: third_party/libz/inftrees.h ================================================ // clang-format off /* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); ================================================ FILE: third_party/libz/trees.c ================================================ // clang-format off /* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2021 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ /* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "third_party/libz/deflate.h" #ifdef ZLIB_DEBUG # include #endif /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) || !defined(STDC) /* non ANSI compilers may not accept trees.h */ local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ local ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "third_party/libz/trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; local const static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local const static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local const static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ local void tr_static_init OF((void)); local void init_block OF((deflate_state *s)); local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); local void build_tree OF((deflate_state *s, tree_desc *desc)); local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes)); local void compress_block OF((deflate_state *s, const ct_data *ltree, const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned code, int len)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef ZLIB_DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* !ZLIB_DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef ZLIB_DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) deflate_state *s; int value; /* value to send */ int length; /* number of bits */ { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !ZLIB_DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = (int)value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* ZLIB_DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init() { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1 << extra_lbits[code]); n++) { _length_code[length++] = (uch)code; } } Assert (length == 256, "tr_static_init: length != 256"); /* Note that the length 255 (match length 258) can be represented * in two different ways: code 284 + 5 bits or code 285, so we * overwrite length_code[255] to use the best encoding: */ _length_code[length - 1] = (uch)code; /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1 << extra_dbits[code]); n++) { _dist_code[dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: dist != 256"); dist >>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width) - 1 ? ",\n" : ", ")) void gen_trees_header() { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init(s) deflate_state *s; { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ local void init_block(s) deflate_state *s; { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->sym_next = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap(s, tree, k) deflate_state *s; ct_data *tree; /* the tree to restore */ int k; /* node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } if (overflow == 0) return; Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes(tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ unsigned code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { code = (code + bl_count[bits - 1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, "inconsistent bit counts"); Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); for (n = 0; n <= max_code; n++) { int len = tree[n].Len; if (len == 0) continue; /* Now reverse the bits */ tree[n].Code = (ush)bi_reverse(next_code[len]++, len); Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); } } /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. * Update the total bit length for the current block. * IN assertion: the field freq is set for all tree elements. * OUT assertions: the fields len and code are set to the optimal bit length * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ local void build_tree(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree(s) deflate_state *s; { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except the * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees(s, lcodes, dcodes, blcodes) deflate_state *s; int lcodes, dcodes, blcodes; /* number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes - 1, 5); send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); if (stored_len) zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); s->pending += stored_len; #ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; s->bits_sent += stored_len << 3; #endif } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ void ZLIB_INTERNAL _tr_flush_bits(s) deflate_state *s; { bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ void ZLIB_INTERNAL _tr_align(s) deflate_state *s; { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef ZLIB_DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len + 3 + 7) >> 3; static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); #ifndef FORCE_STATIC if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) #endif opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); } else if (static_lenb == opt_lenb) { send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1) + last, 3); send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef ZLIB_DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally(s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */ { s->sym_buf[s->sym_next++] = (uch)dist; s->sym_buf[s->sym_next++] = (uch)(dist >> 8); s->sym_buf[s->sym_next++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } return (s->sym_next == s->sym_end); } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block(s, ltree, dtree) deflate_state *s; const ct_data *ltree; /* literal tree */ const ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned sx = 0; /* running index in sym_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->sym_next != 0) do { dist = s->sym_buf[sx++] & 0xff; dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; lc = s->sym_buf[sx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code + LITERALS + 1, ltree); /* send length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= (unsigned)base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and sym_buf is ok: */ Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); } while (sx < s->sym_next); send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "block list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type(s) deflate_state *s; { /* block_mask is the bit mask of block-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long block_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("block-listed") bytes. */ for (n = 0; n <= 31; n++, block_mask >>= 1) if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("allow-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "block-listed" or "allow-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush(s) deflate_state *s; { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG s->bits_sent = (s->bits_sent + 7) & ~7; #endif } ================================================ FILE: third_party/libz/trees.h ================================================ // clang-format off /* header created automatically with -DGEN_TREES_H */ local const ct_data static_ltree[L_CODES+2] = { {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} }; local const ct_data static_dtree[D_CODES] = { {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; local const int base_length[LENGTH_CODES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; local const int base_dist[D_CODES] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; ================================================ FILE: third_party/libz/uncompr.c ================================================ // clang-format off /* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "third_party/libz/zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. *sourceLen is the byte length of the source buffer. Upon entry, *destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, *destLen is the size of the decompressed data and *sourceLen is the number of source bytes consumed. Upon return, source + *sourceLen points to the first unused input byte. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ int ZEXPORT uncompress2(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong *sourceLen; { z_stream stream; int err; const uInt max = (uInt)-1; uLong len, left; Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ len = *sourceLen; if (*destLen) { left = *destLen; *destLen = 0; } else { left = 1; dest = buf; } stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = inflateInit(&stream); if (err != Z_OK) return err; stream.next_out = dest; stream.avail_out = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = len > (uLong)max ? max : (uInt)len; len -= stream.avail_in; } err = inflate(&stream, Z_NO_FLUSH); } while (err == Z_OK); *sourceLen -= len + stream.avail_in; if (dest != buf) *destLen = stream.total_out; else if (stream.total_out && err == Z_BUF_ERROR) left = 1; inflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err == Z_NEED_DICT ? Z_DATA_ERROR : err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : err; } int ZEXPORT uncompress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { return uncompress2(dest, destLen, source, &sourceLen); } ================================================ FILE: third_party/libz/zconf.h ================================================ // clang-format off /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET /* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_combine_gen z_crc32_combine_gen # define crc32_combine_gen64 z_crc32_combine_gen64 # define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit # define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # ifndef Z_SOLO # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzfread z_gzfread # define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # ifdef _WIN32 # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ # define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader # define inflateInit z_inflateInit # define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress # define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO # define zcalloc z_zcalloc # define zcfree z_zcfree # endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # ifndef Z_SOLO # define gzFile z_gzFile # endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO typedef unsigned long z_size_t; #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include typedef size_t z_size_t; # else typedef unsigned long z_size_t; # endif # undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) # include # if (UINT_MAX == 0xffffffffUL) # define Z_U4 unsigned # elif (ULONG_MAX == 0xffffffffUL) # define Z_U4 unsigned long # elif (USHRT_MAX == 0xffffffffUL) # define Z_U4 unsigned short # endif #endif #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include /* for off_t */ # endif #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO # include /* for va_list */ # endif #endif #ifdef _WIN32 # ifndef Z_SOLO # include /* for wchar_t */ # endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #ifndef Z_HAVE_UNISTD_H # ifdef __WATCOMC__ # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_HAVE_UNISTD_H # if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif # endif #endif #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 # define Z_LFS64 #endif #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) # define Z_LARGE64 #endif #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) # define Z_WANT64 #endif #if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ ================================================ FILE: third_party/libz/zlib.h ================================================ // clang-format off /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.13, October 13th, 2022 Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "third_party/libz/zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.13" #define ZLIB_VERNUM 0x12d0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 13 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip and raw deflate streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in the case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text for deflate, or the decoding state for inflate */ uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. In that case, zlib is thread-safe. When zalloc and zfree are Z_NULL on entry to the initialization function, they are set to internal routines that use the standard library functions malloc() and free(). On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use by the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field for deflate() */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary. Some output may be provided even if flush is zero. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed codes block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used in the first deflate call after deflateInit if all the compression is to be done in a single step. In order to complete in one call, avail_out must be at least the value returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. If not enough output space is provided, deflate will not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the Adler-32 checksum of all input read so far (that is, total_in bytes). If a gzip stream is being generated, then strm->adler will be the CRC-32 checksum of the input read so far. (See deflateInit2 below.) deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL or the state was inadvertently written over by the application), or Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. In the current version of inflate, the provided input is not read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression. Actual decompression will be done by inflate(). So next_in, and avail_in, next_out, and avail_out are unused and unchanged. The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), then next_in and avail_in are updated accordingly, and processing will resume at this point for the next call of inflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. If the caller of inflate() does not provide both available input and available output space, it is possible that there will be no progress made. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. To assist in this, on return inflate() always sets strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the stream completes, which reduces inflate's memory footprint. If the stream does not complete, either because not all of the stream is provided or not enough output space is provided, then a sliding window will be allocated and inflate() can be called again to continue the operation as if Z_NO_FLUSH had been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the effects of the flush parameter in this implementation are on the return value of inflate() as noted below, when inflate() returns early when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed Adler-32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained unless inflateGetHeader() is used. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output produced so far. The CRC-32 is checked against the gzip trailer, as is the uncompressed length, modulo 2^32. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value, in which case strm->msg points to a string with a more specific error), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL, or the state was inadvertently written over by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state was inconsistent. */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. For the current implementation of deflate(), a windowBits value of 8 (a window size of 256 bytes) is not supported. As a result, a request for 8 will result in 9 (a 512-byte window). In that case, providing 8 to inflateInit2() will result in an error when the zlib header with 9 is checked against the initialization of inflate(). The remedy is to not use 8 with deflateInit2() with this initialization, or at least in that case use 9 with inflateInit2(). windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute a check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to the appropriate value, if the operating system was determined at compile time. If a gzip stream is being written, strm->adler is a CRC-32 instead of an Adler-32. For raw deflate or gzip encoding, a request for a 256-byte window is rejected as invalid, since only the zlib header provides a means of transmitting the window size to the decompressor. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the Adler-32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up to 258 bytes less in that case, due to how zlib's implementation of deflate manages the sliding window and lookahead for matches, where matches can be up to 258 bytes long. If the application needs the last window-size bytes of input, then that would need to be saved by the application outside of zlib. deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been set unchanged. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression approach (which is a function of the level) or the strategy is changed, and if there have been any deflate() calls since the state was initialized or reset, then the input available so far is compressed with the old level and strategy using deflate(strm, Z_BLOCK). There are three approaches for the compression levels 0, 1..3, and 4..9 respectively. The new level and strategy will take effect at the next call of deflate(). If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does not have enough output space to complete, then the parameter change will not take effect. In this case, deflateParams() can be called again with the same parameters and more output space to try again. In order to assure a change in the parameters on the first try, the deflate stream should be flushed using deflate() with Z_BLOCK or other flush request until strm.avail_out is not zero, before calling deflateParams(). Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be applied to the the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if there was not enough output space to complete the compression of the available input data before a change in the strategy or approach. Note that in the case of a Z_BUF_ERROR, the parameters are not changed. A return value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be retried with more output space. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, unsigned *pending, int *bits)); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an Adler-32 or a CRC-32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see below), inflate() will *not* automatically decode concatenated gzip members. inflate() will return Z_STREAM_END at the end of the gzip member. The state would need to be reset to continue decoding a subsequent gzip member. This *must* be done if there is more data after a gzip member, in order for the decompression to be compliant with the gzip standard (RFC 1952). inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurrences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. If the window size is changed, then the memory allocated for the window is freed, and the window will be reallocated by inflate() if needed. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than inflate() for file i/o applications, in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. inflate() can be faster on modern CPUs when used with large buffers. inflateBack() trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the default behavior of inflate(), which expects a zlib header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero -- buf is ignored in that case -- and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: ZLIB_DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ #ifndef Z_SOLO /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress() is equivalent to compress2() with a level parameter of Z_DEFAULT_COMPRESSION. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen)); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of source bytes consumed. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Open the gzip (.gz) file at path for reading and decompressing, or compressing and writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. These functions, as well as gzip, will read and decode a sequence of gzip streams in a file. The append function of gzopen() can be used to create such a file. (Also see gzflush() for another way to do this.) When appending, gzopen does not test whether the file begins with a gzip stream, nor does it look for the end of the gzip streams to begin appending. gzopen will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. When reading, this will be detected automatically by looking for the magic two- byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* Associate a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions for file to size. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Three times that size in buffer space is allocated. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level and strategy for file. See the description of deflateInit2 for the meaning of these parameters. Previously provided data is flushed before applying the parameter changes. gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not opened for writing, Z_ERRNO if there is an error writing the flushed data, or Z_MEM_ERROR if there is a memory allocation error. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Read and decompress up to len uncompressed bytes from file into buf. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, that remaining trailing garbage is ignored (and no error is returned). gzread can be used to read a gzip file that is being concurrently written. Upon reaching the end of the input, gzread will return with the available data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then gzclearerr can be used to clear the end of file indicator in order to permit gzread to be tried again. Z_OK indicates that a gzip stream was completed on the last gzread. Z_BUF_ERROR indicates that the input file ended in the middle of a gzip stream. Note that gzread does not return -1 in the event of an incomplete gzip stream. This error is deferred until gzclose(), which will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip stream. Alternatively, gzerror can be used before gzclose to detect this case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. If len is too large to fit in an int, then nothing is read, -1 is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, gzFile file)); /* Read and decompress up to nitems items of size size from file into buf, otherwise operating as gzread() does. This duplicates the interface of stdio's fread(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfread() returns the number of full items read of size size, or zero if the end of the file was reached and a full item could not be read, or if there was an error. gzerror() must be consulted if zero is returned in order to determine if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is read, zero is returned, and the error state is set to Z_STREAM_ERROR. In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written file, resetting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Compress and write the len uncompressed bytes at buf to file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, z_size_t nitems, gzFile file)); /* Compress and write nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfwrite() returns the number of full items written of size size, or zero if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is written, zero is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Convert, format, compress, and write the arguments (...) to file under control of the string format, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or a negative zlib error code in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf(), because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Compress and write the given null-terminated string s to file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Read and decompress bytes from file into buf, until len-1 characters are read, or until a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len is one, the string is terminated with a null character. If no characters are read due to an end-of-file or len is less than one, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Compress and write c, converted to an unsigned char, into file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Read and decompress one byte from file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push c back onto the stream for file to be read as the first character on the next read. At least one character of push-back is always allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flush all pending output to file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatenated gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Set the starting position to offset relative to whence for the next gzread or gzwrite on file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewind file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Return the starting position for the next gzread or gzwrite on file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Return the current compressed (actual) read or write offset of file. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Return true (1) if the end-of-file indicator for file has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Return true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flush all pending output for file, if necessary, close file and deallocate the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Return the error message for the last error which occurred on file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clear the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. An Adler-32 value is in the range of a 32-bit unsigned integer. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, z_size_t len)); /* Same as adler32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ ZEXTERN uLong ZEXPORT crc32_z OF((uLong crc, const Bytef *buf, z_size_t len)); /* Same as crc32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2)); Return the operator corresponding to length len2, to be used with crc32_combine_op(). */ ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); /* Give the same result as crc32_combine(), using op in place of len2. op is is generated from len2 by crc32_combine_gen(). This will be faster than crc32_combine() if the generated op is used more than once. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define z_inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #else # define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #endif #ifndef Z_SOLO /* gzgetc() macro and its supporting function and exposed data structure. Note * that the real internal state is much larger than the exposed structure. * This abbreviated structure exposes just enough for the gzgetc() macro. The * user should not mess with these exposed elements, since their names or * behavior could change in the future, perhaps even capriciously. They can * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #else # define gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) # ifdef Z_PREFIX_SET # define z_gzopen z_gzopen64 # define z_gzseek z_gzseek64 # define z_gztell z_gztell64 # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 # define z_crc32_combine_gen z_crc32_combine_gen64 # else # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # define crc32_combine_gen crc32_combine_gen64 # endif # ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); #endif #else /* Z_SOLO */ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); #endif /* !Z_SOLO */ /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, const char *mode)); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, const char *format, va_list va)); # endif #endif #ifdef __cplusplus } #endif #endif /* ZLIB_H */ ================================================ FILE: third_party/libz/zlib.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ PKGS += ZLIB ZLIB ?= o/$(MODE)/third_party/libz/zlib.a ZLIB_FILES := $(wildcard third_party/libz/*) ZLIB_SRCS = $(filter %.c,$(ZLIB_FILES)) ZLIB_HDRS = $(filter %.h,$(ZLIB_FILES)) ZLIB_OBJS = $(ZLIB_SRCS:%.c=o/$(MODE)/%.o) ZLIB_CPPFLAGS = -isystem third_party/libz CPPFLAGS_STATIC += $(ZLIB_CPPFLAGS) ifneq ($(ZLIB), ) CPPFLAGS += $(ZLIB_CPPFLAGS) endif $(ZLIB_OBJS): private CFLAGS += -xc -w o/$(MODE)/third_party/libz/zlib.a: $(ZLIB_OBJS) o/$(MODE)/i486/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/i486/%.o) o/$(MODE)/m68k/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/m68k/%.o) o/$(MODE)/x86_64/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/x86_64/%.o) o/$(MODE)/x86_64-gcc49/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/x86_64-gcc49/%.o) o/$(MODE)/arm/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/arm/%.o) o/$(MODE)/aarch64/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/aarch64/%.o) o/$(MODE)/riscv64/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/riscv64/%.o) o/$(MODE)/mips/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/mips/%.o) o/$(MODE)/mipsel/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/mipsel/%.o) o/$(MODE)/mips64/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/mips64/%.o) o/$(MODE)/mips64el/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/mips64el/%.o) o/$(MODE)/s390x/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/s390x/%.o) o/$(MODE)/microblaze/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/microblaze/%.o) o/$(MODE)/powerpc/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/powerpc/%.o) o/$(MODE)/powerpc64le/third_party/libz/zlib.a: $(ZLIB_SRCS:%.c=o/$(MODE)/powerpc64le/%.o) o/$(MODE)/third_party/libz: \ o/$(MODE)/third_party/libz/zlib.a ================================================ FILE: third_party/libz/zutil.c ================================================ // clang-format off /* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2017 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "third_party/libz/zutil.h" #ifndef Z_SOLO # include "third_party/libz/gzguts.h" #endif z_const char * const z_errmsg[10] = { (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ (z_const char *)"stream end", /* Z_STREAM_END 1 */ (z_const char *)"", /* Z_OK 0 */ (z_const char *)"file error", /* Z_ERRNO (-1) */ (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ (z_const char *)"" }; const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags() { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef ZLIB_DEBUG flags += 1 << 8; #endif /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf flags += 1L << 25; # ifdef HAS_vsprintf_void flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void flags += 1L << 26; # endif # endif #else flags += 1L << 24; # ifdef NO_snprintf flags += 1L << 25; # ifdef HAS_sprintf_void flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void flags += 1L << 26; # endif # endif #endif return flags; } #ifdef ZLIB_DEBUG #include # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error(m) char *m; { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError(err) int err; { return ERR_MSG(err); } #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 /* The older Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy(dest, source, len) Bytef* dest; const Bytef* source; uInt len; { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp(s1, s2, len) const Bytef* s1; const Bytef* s2; uInt len; { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero(dest, len) Bytef* dest; uInt len; { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif #ifndef Z_SOLO #ifdef SYS16BIT #ifdef __TURBOC__ /* Turbo C in 16-bit mode */ # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes * and farmalloc(64K) returns a pointer with an offset of 8, so we * must fix the pointer. Warning: the pointer must be put back to its * original form in order to free it, use zcfree(). */ #define MAX_PTR 10 /* 10*64K = 640K */ local int next_ptr = 0; typedef struct ptr_table_s { voidpf org_ptr; voidpf new_ptr; } ptr_table; local ptr_table table[MAX_PTR]; /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; (void)opaque; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ if (bsize < 65520L) { buf = farmalloc(bsize); if (*(ush*)&buf != 0) return buf; } else { buf = farmalloc(bsize + 16L); } if (buf == NULL || next_ptr >= MAX_PTR) return NULL; table[next_ptr].org_ptr = buf; /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; (void)opaque; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; } /* Find the original pointer */ for (n = 0; n < next_ptr; n++) { if (ptr != table[n].new_ptr) continue; farfree(table[n].org_ptr); while (++n < next_ptr) { table[n-1] = table[n]; } next_ptr--; return; } Assert(0, "zcfree: ptr not found"); } #endif /* __TURBOC__ */ #ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif voidpf ZLIB_INTERNAL zcalloc(opaque, items, size) voidpf opaque; unsigned items; unsigned size; { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree(opaque, ptr) voidpf opaque; voidpf ptr; { (void)opaque; free(ptr); } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ ================================================ FILE: third_party/libz/zutil.h ================================================ // clang-format off /* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef ZUTIL_H #define ZUTIL_H #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include "third_party/libz/zlib.h" #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif # include # include #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; #if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) # include # if (ULONG_MAX == 0xffffffffffffffff) # define Z_U8 unsigned long # elif (ULLONG_MAX == 0xffffffffffffffff) # define Z_U8 unsigned long long # elif (UINT_MAX == 0xffffffffffffffff) # define Z_U8 unsigned # endif #endif extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # ifndef Z_SOLO # if defined(__TURBOC__) || defined(__BORLANDC__) # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) /* Allow compilation with ANSI keywords only enabled */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else # include # endif # else /* MSC or DJGPP */ # include # endif # endif #endif #ifdef AMIGA # define OS_CODE 1 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 2 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #ifdef __370__ # if __TARGET_LIB__ < 0x20000000 # define OS_CODE 4 # elif __TARGET_LIB__ < 0x40000000 # define OS_CODE 11 # else # define OS_CODE 8 # endif #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 5 #endif #ifdef OS2 # define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 7 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fdopen */ # else # ifndef fdopen # define fdopen(fd,mode) NULL /* No fdopen() */ # endif # endif # endif #endif #ifdef __acorn # define OS_CODE 13 #endif #if defined(WIN32) && !defined(__CYGWIN__) # define OS_CODE 10 #endif #ifdef _BEOS_ # define OS_CODE 16 #endif #ifdef __TOS_OS400__ # define OS_CODE 18 #endif #ifdef __APPLE__ # define OS_CODE 19 #endif #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ # else # define fdopen(fd,type) _fdopen(fd,type) # endif #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 3 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) # define HAVE_MEMCPY #endif #ifdef HAVE_MEMCPY # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ # define zmemcpy _fmemcpy # define zmemcmp _fmemcmp # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */ ================================================ FILE: third_party/ltp/README.md ================================================ # Linux Test Project This folder downloads prebuilt binaries from the [Linux Test Project](https://github.com/linux-test-project/ltp). ## Changes 1. Comment out the capability code in lib/tst_capability.c 2. Comment out the code that opens /proc/meminfo 3. Remove `clone()` + `O_PATH` test from `close_range02` 4. Remove `ifconfig lo up 127.0.0.1` code from sendmsg01 5. Remove last test case (msg_control efault) from sendmsg01 6. Fix readlink03 to work with Musl and not require root ## Build The binaries were compiled on Alpine Linux using: ``` ./configure CFLAGS="-Os -fno-omit-frame-pointer" \ LDFLAGS="-Wl,-z,common-page-size=65536,-z,max-page-size=65536" make -j16 make install ``` ## Deploy The above commands install to `/opt/ltp` by default. Our operations team them uses [deploy-ltp](deploy-ltp) to deploy individual test programs to Google Cloud Storage once they've been confirmed to work. ================================================ FILE: third_party/ltp/bin/1/accept01.elf.gz.sha256 ================================================ 8be297aac04898e802eff3a59dabf089f21b8e244240187667588ec43a0abbe1 *third_party/ltp/bin/1/accept01.elf.gz ================================================ FILE: third_party/ltp/bin/1/accept4_01.elf.gz.sha256 ================================================ 4298c541d8fe9236140640fbd01e36f49439b99b29a9ffc35300262ebd4d1cca *third_party/ltp/bin/1/accept4_01.elf.gz ================================================ FILE: third_party/ltp/bin/1/access01.elf.gz.sha256 ================================================ 1b2dd6ced61e14ca16a3b093990dab15dd7ca2b2d3eae45c1131c3630da570f2 *third_party/ltp/bin/1/access01.elf.gz ================================================ FILE: third_party/ltp/bin/1/access03.elf.gz.sha256 ================================================ efdf8705968d75ee29be6bb51849356851fd3cb884dde4830a91602f422052b7 *third_party/ltp/bin/1/access03.elf.gz ================================================ FILE: third_party/ltp/bin/1/alarm02.elf.gz.sha256 ================================================ 084c112cee6317841f8f4ccde65b171d7f374f0dd22a5718767e4f2af33db86a *third_party/ltp/bin/1/alarm02.elf.gz ================================================ FILE: third_party/ltp/bin/1/alarm03.elf.gz.sha256 ================================================ 1705faec22f30906c5c0acec673a5fb59b4f1bc35249dbbe1eb26812966041a9 *third_party/ltp/bin/1/alarm03.elf.gz ================================================ FILE: third_party/ltp/bin/1/alarm05.elf.gz.sha256 ================================================ 6aa3e65361ac20913accb491075a35629781cfb8feef1d4f865bb33d79df9d26 *third_party/ltp/bin/1/alarm05.elf.gz ================================================ FILE: third_party/ltp/bin/1/alarm06.elf.gz.sha256 ================================================ 477dd8cb87977b612b848f2a1a5745f3dca786fdc590214ff25d460e8cc053dd *third_party/ltp/bin/1/alarm06.elf.gz ================================================ FILE: third_party/ltp/bin/1/alarm07.elf.gz.sha256 ================================================ 9a26f2b216ed97c3e7f809a7baec9678f08b5f8a693d7ab40db3ecbcdc9e180f *third_party/ltp/bin/1/alarm07.elf.gz ================================================ FILE: third_party/ltp/bin/1/atof01.elf.gz.sha256 ================================================ bbdd6e440e7ed00422a571ff0526bc3b9a3b388854672c2111f30b42471b6832 *third_party/ltp/bin/1/atof01.elf.gz ================================================ FILE: third_party/ltp/bin/1/autogroup01.elf.gz.sha256 ================================================ 0f2e7b22e8205a6b138d9acd41780189053df87e8e908e32232423cd286b526f *third_party/ltp/bin/1/autogroup01.elf.gz ================================================ FILE: third_party/ltp/bin/1/bind01.elf.gz.sha256 ================================================ dd5d91d70ec7fc6817229eb2075a2a98a9b88aa809722a650693e25578c11772 *third_party/ltp/bin/1/bind01.elf.gz ================================================ FILE: third_party/ltp/bin/1/bind03.elf.gz.sha256 ================================================ 13cc3baf18a1cc26cf3d16acf0355a152045606a9f33883869200ed214b4890f *third_party/ltp/bin/1/bind03.elf.gz ================================================ FILE: third_party/ltp/bin/1/brk02.elf.gz.sha256 ================================================ a18a7545537a72b944debb1154def6090e69796fb71da0a97aaba9cf0130884a *third_party/ltp/bin/1/brk02.elf.gz ================================================ FILE: third_party/ltp/bin/1/chmod01.elf.gz.sha256 ================================================ 7d08068f43e0f4a543d76a86fb81d2b6f2cc9598aa26e7cef8a59819d0b4547c *third_party/ltp/bin/1/chmod01.elf.gz ================================================ FILE: third_party/ltp/bin/1/chmod07.elf.gz.sha256 ================================================ efe3d9b51a682d45af0196918cda079233d978341bae6c26aaaad9074b149710 *third_party/ltp/bin/1/chmod07.elf.gz ================================================ FILE: third_party/ltp/bin/1/chown01.elf.gz.sha256 ================================================ 7ebb1a680b65137bacb5b3eabc20e45fc631d1d791e93bcb9f72a9b4383be8b6 *third_party/ltp/bin/1/chown01.elf.gz ================================================ FILE: third_party/ltp/bin/1/chown02.elf.gz.sha256 ================================================ c05ceec3d671c95655c88f16f4f34ed8bd35f63c3b47ab02a0b85d52c6ee8de6 *third_party/ltp/bin/1/chown02.elf.gz ================================================ FILE: third_party/ltp/bin/1/chown05.elf.gz.sha256 ================================================ 9e1087977140d520c2050f9299fd4ed4bd5e8dc2cc6036884b2c0e372ef16c57 *third_party/ltp/bin/1/chown05.elf.gz ================================================ FILE: third_party/ltp/bin/1/clock_getres01.elf.gz.sha256 ================================================ 70b0d8ab83e8c0b95e1f04f0e710d734fa4857f402375b7aef7c2a69c7c08593 *third_party/ltp/bin/1/clock_getres01.elf.gz ================================================ FILE: third_party/ltp/bin/1/clock_gettime01.elf.gz.sha256 ================================================ 950a082264b3991fa86b90caa34f86e6980f79cce01c035c523ea15e0dd080e3 *third_party/ltp/bin/1/clock_gettime01.elf.gz ================================================ FILE: third_party/ltp/bin/1/clock_gettime04.elf.gz.sha256 ================================================ 78d3dc1a6026ebab9d8f0642845a243c64b9e61f218ab698efa4479db71f4479 *third_party/ltp/bin/1/clock_gettime04.elf.gz ================================================ FILE: third_party/ltp/bin/1/clock_nanosleep02.elf.gz.sha256 ================================================ 22688da9bf35eed2e16978ab97a55d3cca5e29d0e64e443dea987945db7901c5 *third_party/ltp/bin/1/clock_nanosleep02.elf.gz ================================================ FILE: third_party/ltp/bin/1/clock_nanosleep04.elf.gz.sha256 ================================================ 355b83af7d72cc06329ae52c3c9866e276f3e2f5df139815d53dfca35090d748 *third_party/ltp/bin/1/clock_nanosleep04.elf.gz ================================================ FILE: third_party/ltp/bin/1/close01.elf.gz.sha256 ================================================ 740b3669067d009ce873a57328f66556db81a5b4ba303c1a968e5aaa289d18b5 *third_party/ltp/bin/1/close01.elf.gz ================================================ FILE: third_party/ltp/bin/1/close02.elf.gz.sha256 ================================================ af019102260b3e0877e8a9e326bb144caa839311987f1617aba29390537848b7 *third_party/ltp/bin/1/close02.elf.gz ================================================ FILE: third_party/ltp/bin/1/close_range02.elf.gz.sha256 ================================================ a4f384affd1c3ead5c6e6d60ac535e509afe7f3338a7b43d10cc6c4487625628 *third_party/ltp/bin/1/close_range02.elf.gz ================================================ FILE: third_party/ltp/bin/1/confstr01.elf.gz.sha256 ================================================ 638aa1c54b881fcc4a83d25bcc4c59e100f3a8fcaef8222f45da1ddfbeec09df *third_party/ltp/bin/1/confstr01.elf.gz ================================================ FILE: third_party/ltp/bin/1/creat01.elf.gz.sha256 ================================================ 06aa90ba72b162c0067c20a90146f042ac675e5f1aadabc5f2015aa4319a4bb4 *third_party/ltp/bin/1/creat01.elf.gz ================================================ FILE: third_party/ltp/bin/1/creat03.elf.gz.sha256 ================================================ 796ddd79c19afb126cbcc9290a74a5fc22f45b6fcbff037ffa2bf05b366dcf60 *third_party/ltp/bin/1/creat03.elf.gz ================================================ FILE: third_party/ltp/bin/1/creat05.elf.gz.sha256 ================================================ 394d43d022f284e02e014890f89fa79c6a05831f31923b147fb65b6cb3129c0a *third_party/ltp/bin/1/creat05.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup01.elf.gz.sha256 ================================================ ab34c37bd989596be9cdc9fc5805a919695ed605432fd7e982ed14986344d700 *third_party/ltp/bin/1/dup01.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup02.elf.gz.sha256 ================================================ e78930aea6769b941ad10c9085296da1ece6969ece3fa46f7c292fefc6c4c6bc *third_party/ltp/bin/1/dup02.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup04.elf.gz.sha256 ================================================ d2e1329cf2a2ad36fcf0c4d332691df9f56a5b2c8a6b657534755de8dbe77e53 *third_party/ltp/bin/1/dup04.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup05.elf.gz.sha256 ================================================ 3e4b4c5ca82c5fca7fce88516565f3010a26a5124e2ddd2c87ab7618863bab92 *third_party/ltp/bin/1/dup05.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup07.elf.gz.sha256 ================================================ ea2eb8e010d90948bd82cbd69d48e4410e549da541467549ae49f6b46d7603b8 *third_party/ltp/bin/1/dup07.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup201.elf.gz.sha256 ================================================ 0bd811ba6e42d298e7ece94fa1d0334de4f706efef744965b4118e8433f67b22 *third_party/ltp/bin/1/dup201.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup202.elf.gz.sha256 ================================================ 848fbd203c32427755363f2fc534b51aba352f671593962b5389991b6bc32825 *third_party/ltp/bin/1/dup202.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup203.elf.gz.sha256 ================================================ 072b255d5d937555065a383ccc0ab7449fcb6100146f3c9ae74a7344337e701a *third_party/ltp/bin/1/dup203.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup204.elf.gz.sha256 ================================================ 7451ebc1f71fde791b8dc545e9a9aad09a974ec0caa109061215957517c326b2 *third_party/ltp/bin/1/dup204.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup206.elf.gz.sha256 ================================================ b040a0781d857f7a2284ff35640c3675063b3c2e17b537d627059099285010a1 *third_party/ltp/bin/1/dup206.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup207.elf.gz.sha256 ================================================ ae9760d8028c77861a02b864aef91ed624f2b2fb5afef04937ac8a76d0b70e28 *third_party/ltp/bin/1/dup207.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup3_01.elf.gz.sha256 ================================================ 70a3f8bea3406e1042aa2ce8ab0c6239db5ee55bfac9ff35572020669dfedfd7 *third_party/ltp/bin/1/dup3_01.elf.gz ================================================ FILE: third_party/ltp/bin/1/dup3_02.elf.gz.sha256 ================================================ 3b2d058d83cd655583a54b6864ff8aeeb09e8dfaf21a8d9cd18d66fe69744838 *third_party/ltp/bin/1/dup3_02.elf.gz ================================================ FILE: third_party/ltp/bin/1/exit01.elf.gz.sha256 ================================================ 5402cb31e0f7b44e20be3e90db7876aaa49bb45f872003366142b657a93d73a0 *third_party/ltp/bin/1/exit01.elf.gz ================================================ FILE: third_party/ltp/bin/1/exit02.elf.gz.sha256 ================================================ 87fe3a84d0e01fa8bbeaf9c04b49fa7a716034553977188d152ec13fff8ce9ee *third_party/ltp/bin/1/exit02.elf.gz ================================================ FILE: third_party/ltp/bin/1/exit_group01.elf.gz.sha256 ================================================ 78b017a90373f1ca99e68cedd790c2c91a30864f6fb07e1b9a2ac678fea1be0b *third_party/ltp/bin/1/exit_group01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchdir01.elf.gz.sha256 ================================================ bbf63ea543617807cf25c9829f7c872f20b2a8506642f7ceda3b3dc45de0c6c2 *third_party/ltp/bin/1/fchdir01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchdir02.elf.gz.sha256 ================================================ 4e3a89620777a97a9f8c1b2f1a6d962d719edf398bd852b6029d4711207eff53 *third_party/ltp/bin/1/fchdir02.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchmod01.elf.gz.sha256 ================================================ 368881273c24340c7d918e535fa2a7aa588e5c065faf1976fab5f0f5d23a10d0 *third_party/ltp/bin/1/fchmod01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchmod02.elf.gz.sha256 ================================================ 95f7d6a3b8d98b3e9c7d9e088e3e2f2e0e1ea771be0971c528c6d0e1a892173b *third_party/ltp/bin/1/fchmod02.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchmod04.elf.gz.sha256 ================================================ d0670a210185cf62b28c5a450caadc5957ce1c54dac19462d3a616250b22e136 *third_party/ltp/bin/1/fchmod04.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchown01.elf.gz.sha256 ================================================ b82b9a4adb364e528140952ddeff991a84188375fb1ef59fbc51ba87ab7358eb *third_party/ltp/bin/1/fchown01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchown02.elf.gz.sha256 ================================================ 53d4621f4c7f7ae4cf7a0df627a1935d827f6c3c3cd9a64af2bb7bbf2a8399a4 *third_party/ltp/bin/1/fchown02.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchown05.elf.gz.sha256 ================================================ db4cdccae551cf5bb4c4712561cea71317170992cd0f4114844040de8f0568ab *third_party/ltp/bin/1/fchown05.elf.gz ================================================ FILE: third_party/ltp/bin/1/fchownat01.elf.gz.sha256 ================================================ c05577ea1253f0f19ea628ebf84b9c5b9113a9f9fd3711ceeff5765cd915c2d2 *third_party/ltp/bin/1/fchownat01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl01.elf.gz.sha256 ================================================ 09f22692842ee24f473ff4cc61b831fb8799a19110e0cc9158137bec1daa7d8f *third_party/ltp/bin/1/fcntl01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl01_64.elf.gz.sha256 ================================================ 8dc9e54c488302bf2a8c32b368708bee978a52549d1a27c94a92c628bb562151 *third_party/ltp/bin/1/fcntl01_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl02.elf.gz.sha256 ================================================ 2b4d15750fe260d8ff5261b13167d8bfb6769b1266b4b3ffa1f60bbacb93b3b2 *third_party/ltp/bin/1/fcntl02.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl02_64.elf.gz.sha256 ================================================ 5f0eab69a639f11bba2407a1d9412e5a6ecdb361ce3bc55893f90564b44ed621 *third_party/ltp/bin/1/fcntl02_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl03.elf.gz.sha256 ================================================ 51afd73dd7413c5769c995d2858dd14781db969508c54aa45b7e24753dc74bc7 *third_party/ltp/bin/1/fcntl03.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl03_64.elf.gz.sha256 ================================================ 09807c43c483f7396045beab3437e4138a242bc58166de1b2340f0e43fe01834 *third_party/ltp/bin/1/fcntl03_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl04.elf.gz.sha256 ================================================ 097816716e5af5ab53c3a4d128f561cd5e7895a135f88ef3593ba5a12f8e679e *third_party/ltp/bin/1/fcntl04.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl04_64.elf.gz.sha256 ================================================ af6ed53c0d6ad6e2c687458edd54e5240cdb5ade06fef38e754e8eb1ba9ee776 *third_party/ltp/bin/1/fcntl04_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl08.elf.gz.sha256 ================================================ de2ddc59ebe8d21b543412ae688b3e04dd344c8bf2402f5d2e9ad544e1332ab5 *third_party/ltp/bin/1/fcntl08.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl08_64.elf.gz.sha256 ================================================ 19d1beb1950a931b82467deab065a7a0d6502f771208bca575c32aa1d8d1be71 *third_party/ltp/bin/1/fcntl08_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl09.elf.gz.sha256 ================================================ f6cca69c98a0b07f67808f4626fc4dd2ed82d416e830d46a585d2b6fbee7c7f4 *third_party/ltp/bin/1/fcntl09.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl09_64.elf.gz.sha256 ================================================ e5e918b6113c28c4f305c98ddbdfaa3dc90a93b76046058a049fe0a67f5a4a15 *third_party/ltp/bin/1/fcntl09_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl10.elf.gz.sha256 ================================================ fb11b9b1e92133f4ad9968deb82501a1af81790650f19b31a35d4f5ddbe02a81 *third_party/ltp/bin/1/fcntl10.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl10_64.elf.gz.sha256 ================================================ 393cdabc749afa5fc06c6d88879e349f7feb972bbf29e315b0bea13855ef1c60 *third_party/ltp/bin/1/fcntl10_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl11.elf.gz.sha256 ================================================ d0b1b8ba0d11d2374cbdeba62af83ad56898f2af4cb44ec5596ad4142983f7c6 *third_party/ltp/bin/1/fcntl11.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl11_64.elf.gz.sha256 ================================================ 9a3f730adf0f77a5801acad6f52ee673a58fa125a0f1cdf799f58e367b9c2848 *third_party/ltp/bin/1/fcntl11_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl14.elf.gz.sha256 ================================================ 1657bdde6f677d8abf6f37870743cdf2e058847a42820d92d630ad1f5d64fc75 *third_party/ltp/bin/1/fcntl14.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl14_64.elf.gz.sha256 ================================================ 175df03f43977a98f497f2a486dc3dd024bd37560b7a90fb21c459bf6c8d56f9 *third_party/ltp/bin/1/fcntl14_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl15.elf.gz.sha256 ================================================ 7f68ad245b0e5116d83946c494677a3de1808faf5a177a92044aa76f1fddfc98 *third_party/ltp/bin/1/fcntl15.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl15_64.elf.gz.sha256 ================================================ ad5bd350b9374461b3ff9666b20c0751cb90e1156892ec6c7bcdb18d15e5451e *third_party/ltp/bin/1/fcntl15_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl16.elf.gz.sha256 ================================================ 945443b33f8aee9dd418d19aade3900ba709f459241f85eca2a0e84d93c35a71 *third_party/ltp/bin/1/fcntl16.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl16_64.elf.gz.sha256 ================================================ c96ab7546fb9dc1309d5778499cfc58a9a47ac9ede03448d9c6df0d60d102b93 *third_party/ltp/bin/1/fcntl16_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl17.elf.gz.sha256 ================================================ 32d7623cfd68553be65d44cc11875741f0bd692b6b0f0313c259f083796aa2e5 *third_party/ltp/bin/1/fcntl17.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl17_64.elf.gz.sha256 ================================================ cea4fdd758c5ba7b87fa7785dfa16460bc8d6b4c0337d1eb8dc87cfaf4be48b5 *third_party/ltp/bin/1/fcntl17_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl19.elf.gz.sha256 ================================================ 9671f64ef747a47beebb34ae8e0811c07595452ec11459f4ded933ad5d9a22e4 *third_party/ltp/bin/1/fcntl19.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl19_64.elf.gz.sha256 ================================================ 8f0000ace04e6041c03878277beee8501849ac0f042b7ac6391bc11faaf53a32 *third_party/ltp/bin/1/fcntl19_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl20.elf.gz.sha256 ================================================ ee7e1cc1012778fcde900f8ca30aa38ae1a4045f3074c5f8b405e615e1d0642f *third_party/ltp/bin/1/fcntl20.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl20_64.elf.gz.sha256 ================================================ f1fa5b0d3f272929d0cc00bb06d161fd5133e653641a0f0d40f4255b495402d5 *third_party/ltp/bin/1/fcntl20_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl21.elf.gz.sha256 ================================================ ce829b80eda9ae119b82d966cc5ae908eafeb6ae51164bf9c64065f7947af29c *third_party/ltp/bin/1/fcntl21.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl21_64.elf.gz.sha256 ================================================ 1f909aec2c9c723479d22782ec6f0654e8fbc34450e6769cf2dbfb63c85877b8 *third_party/ltp/bin/1/fcntl21_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl22.elf.gz.sha256 ================================================ 29cd5f6d757480443f6cc41d10284cb319281ccad6be56b536c53507068ec8c9 *third_party/ltp/bin/1/fcntl22.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl22_64.elf.gz.sha256 ================================================ 90ebdc991791bd387639108fc98ce597665b8ce4511bf5376becf9a775265f34 *third_party/ltp/bin/1/fcntl22_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl27.elf.gz.sha256 ================================================ cbb879fbcedb8227e113a567d40da005d3db1433dd69bf8a0d79b246c1192aca *third_party/ltp/bin/1/fcntl27.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl27_64.elf.gz.sha256 ================================================ eaf116f11886cf8de8c62d1a298842a7103523e34c6d040f98deefa319b20cf4 *third_party/ltp/bin/1/fcntl27_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl28.elf.gz.sha256 ================================================ c41838a5633d4c6407da308ba37c927d3d2730a756c3f36928b14f323cc68e3e *third_party/ltp/bin/1/fcntl28.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl28_64.elf.gz.sha256 ================================================ c403dba04bb89c7c0e651a93d7839201d4f3c27b641a52230c3d00ce7b554d57 *third_party/ltp/bin/1/fcntl28_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl29.elf.gz.sha256 ================================================ 554d471ed7a7da9af63becd6a5d6366ccda8a32ec1f366c1a90f8070636a964e *third_party/ltp/bin/1/fcntl29.elf.gz ================================================ FILE: third_party/ltp/bin/1/fcntl29_64.elf.gz.sha256 ================================================ 3fef8b5e3700c33a9b478e5b9e1d49d094c7ae557d625e1ab608fc32ca0c7a3f *third_party/ltp/bin/1/fcntl29_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/fdatasync01.elf.gz.sha256 ================================================ 19035b4de2775803abf5d63feac2e23f72880d2c6521aef85b5f0dd1d2cdbb72 *third_party/ltp/bin/1/fdatasync01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fdatasync02.elf.gz.sha256 ================================================ f0d28ea4c7f12285ff068f1058dfb24f97eded8c09b0503cc1799642865137d6 *third_party/ltp/bin/1/fdatasync02.elf.gz ================================================ FILE: third_party/ltp/bin/1/flock01.elf.gz.sha256 ================================================ 997cd0e43b95396a3743410f8cc79ffa779660a319be340e845b7451fe645510 *third_party/ltp/bin/1/flock01.elf.gz ================================================ FILE: third_party/ltp/bin/1/flock02.elf.gz.sha256 ================================================ 3da2c168fdf3d406aea42dc5db5cfd11b90a3ba69e069bc4073163e6264999be *third_party/ltp/bin/1/flock02.elf.gz ================================================ FILE: third_party/ltp/bin/1/flock03.elf.gz.sha256 ================================================ 4dbfb6d65d191f16271a33795d2beafcd4b87f687f5f8bde594760f39b52d48a *third_party/ltp/bin/1/flock03.elf.gz ================================================ FILE: third_party/ltp/bin/1/flock04.elf.gz.sha256 ================================================ 37c0cf648faa4e7bfee8c2c2ec814d69f6099083fbca163e6215b87ada5f807e *third_party/ltp/bin/1/flock04.elf.gz ================================================ FILE: third_party/ltp/bin/1/flock06.elf.gz.sha256 ================================================ d0f43b4e4c4b4331a2df751579e7292873f379136594086c5bd3e1fac27eb1f5 *third_party/ltp/bin/1/flock06.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork01.elf.gz.sha256 ================================================ 5477be68eee3e82e1c61eaee8b0bad80e7ad1e5bd1b2fb82b263b28ffbbfe98a *third_party/ltp/bin/1/fork01.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork03.elf.gz.sha256 ================================================ 564b2cd7a593011e784a3b3dae28c916f91768654d89102538bdb66baee06890 *third_party/ltp/bin/1/fork03.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork04.elf.gz.sha256 ================================================ 65b22f25cf86b1e5cf5e06ee2f6e84aac391821adfe5e605c661f7254d332859 *third_party/ltp/bin/1/fork04.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork05.elf.gz.sha256 ================================================ 2a35455fb1d9a3611d312f0744acca05a9f20c120eeab33f1308f74d89ca2a2e *third_party/ltp/bin/1/fork05.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork06.elf.gz.sha256 ================================================ e509b64486b0805a1a4261af80a7c2cd651f7fac9e24462789fa459acbcae17f *third_party/ltp/bin/1/fork06.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork07.elf.gz.sha256 ================================================ 2f283551ce16491e8765621eb69e456c51dadf1c735d5d5c5e3cbfa10539a8b2 *third_party/ltp/bin/1/fork07.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork08.elf.gz.sha256 ================================================ ae8923f64dcd55c98f0258576e5ae9d5a2b89b44d6ff1262ec23b13db5c421ba *third_party/ltp/bin/1/fork08.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork09.elf.gz.sha256 ================================================ 2c4fbf7dbf4b0522b7865490a505119c3243318feb3a84b6a6f986d57d5e3ee3 *third_party/ltp/bin/1/fork09.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork10.elf.gz.sha256 ================================================ 2d1b4854e75c001bafaf8f23e5cff8aa3ddd7fcfebee5e599d3c55ccf4269460 *third_party/ltp/bin/1/fork10.elf.gz ================================================ FILE: third_party/ltp/bin/1/fork11.elf.gz.sha256 ================================================ 04fb3f2f1aedd2656adab52cb48ad818e003c9c1a37db6973b6b3474187842a7 *third_party/ltp/bin/1/fork11.elf.gz ================================================ FILE: third_party/ltp/bin/1/fstat02.elf.gz.sha256 ================================================ 6dd97e653f3c247bccf93d288ac211b6b5f578db0fc497ea5b3cf2767ebdd432 *third_party/ltp/bin/1/fstat02.elf.gz ================================================ FILE: third_party/ltp/bin/1/fsync02.elf.gz.sha256 ================================================ 08a13ddc919b7f16222df0ec437710cdd6a38a3039452ed8a26bcc0d664ecbd1 *third_party/ltp/bin/1/fsync02.elf.gz ================================================ FILE: third_party/ltp/bin/1/fsync03.elf.gz.sha256 ================================================ 2bcf35c4167845690cf91406fe0dc920513b3e9a5b52636b3b0b626851b39914 *third_party/ltp/bin/1/fsync03.elf.gz ================================================ FILE: third_party/ltp/bin/1/ftruncate01.elf.gz.sha256 ================================================ 682580f6365afb2cdcad497d03525280686c4fa5848a79e5259fdcc14a22e344 *third_party/ltp/bin/1/ftruncate01.elf.gz ================================================ FILE: third_party/ltp/bin/1/ftruncate01_64.elf.gz.sha256 ================================================ 2c402e75d8b909054da02b02535943e7f78cac73e267166febdb9d79d9aac9bb *third_party/ltp/bin/1/ftruncate01_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/ftruncate03.elf.gz.sha256 ================================================ ba812430672cf0173d503b3905793fd1741fe2b5c84488c9c8c3257316a5b977 *third_party/ltp/bin/1/ftruncate03.elf.gz ================================================ FILE: third_party/ltp/bin/1/ftruncate03_64.elf.gz.sha256 ================================================ 4b1084c19c2fc914e5a86947c307530f26074a9ff49feb09ad366a14c3d1788e *third_party/ltp/bin/1/ftruncate03_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/futex_wait01.elf.gz.sha256 ================================================ c9235da2c4c5de63a72c74a36fbda638c1bef2a4df0fd08a183d504ea9f81311 *third_party/ltp/bin/1/futex_wait01.elf.gz ================================================ FILE: third_party/ltp/bin/1/futex_wait02.elf.gz.sha256 ================================================ 18565f8dd16395a085b6c894a9213b31f418b60370b214777b56c8a2f795024f *third_party/ltp/bin/1/futex_wait02.elf.gz ================================================ FILE: third_party/ltp/bin/1/futex_wait04.elf.gz.sha256 ================================================ 2e1e8f1ed6b92a6f3fbb98d6f5c07b299ba4d82ece38a1a42b969d6cd10fd56c *third_party/ltp/bin/1/futex_wait04.elf.gz ================================================ FILE: third_party/ltp/bin/1/futex_wait05.elf.gz.sha256 ================================================ 3dd5f2518f22602646e4ced98c45d2eba8dd8e37a5b4146600a069f290f46ded *third_party/ltp/bin/1/futex_wait05.elf.gz ================================================ FILE: third_party/ltp/bin/1/futex_wake01.elf.gz.sha256 ================================================ bace142aab8bae74c4388e57d0e12e5152bdd8e995f0ba0dc019f6294eef71ba *third_party/ltp/bin/1/futex_wake01.elf.gz ================================================ FILE: third_party/ltp/bin/1/futex_wake04.elf.gz.sha256 ================================================ 88dd31b660ff1fe1fc1f6f7af4549afb03395096cf0a780186b485646698d4fc *third_party/ltp/bin/1/futex_wake04.elf.gz ================================================ FILE: third_party/ltp/bin/1/getcwd02.elf.gz.sha256 ================================================ 8bc18661f65b9a8dc1578cde9a07240870a99ab925a7f0a55091d4c97ba1bb3f *third_party/ltp/bin/1/getcwd02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getcwd03.elf.gz.sha256 ================================================ 58fdd9525c7aa7a8a89c0aa70b6108aa70a3f57e2b64881355703977199255a8 *third_party/ltp/bin/1/getcwd03.elf.gz ================================================ FILE: third_party/ltp/bin/1/getcwd04.elf.gz.sha256 ================================================ 1df242ad97b20d6fee49394e51bc5fea699aa0cc51d10159723b291f4bb60760 *third_party/ltp/bin/1/getcwd04.elf.gz ================================================ FILE: third_party/ltp/bin/1/getdents01.elf.gz.sha256 ================================================ 300786f1f462fb0eb5fbf2d6baaf7050f02a165d5fc20c5cab0f0f3e2114b29f *third_party/ltp/bin/1/getdents01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getdomainname01.elf.gz.sha256 ================================================ 5426855ec456873e72622436e30000e4a8c28005dcc7e38e96ed846c6c0d1f6b *third_party/ltp/bin/1/getdomainname01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getegid01.elf.gz.sha256 ================================================ f22444b80db6c7ba5914de096eb8ab4b53d0830dfac0e59b999c6b4f1e274d9a *third_party/ltp/bin/1/getegid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getegid02.elf.gz.sha256 ================================================ b74ddea5184a2c36b51dd805184b00b1025d4855f3f4bd0d56f0f688f7f46c9d *third_party/ltp/bin/1/getegid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/geteuid01.elf.gz.sha256 ================================================ ef215995e4096d9b840a2848c98db22bcfcada481b05e3e87fa4c5099314d3a2 *third_party/ltp/bin/1/geteuid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/geteuid02.elf.gz.sha256 ================================================ c39cc88e1cc37b4b9f34d3fa1b60e5f5f2e17fe91dc644a3cd8c127116c8222d *third_party/ltp/bin/1/geteuid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getgid01.elf.gz.sha256 ================================================ 595a4c8adb76a83e2fac3ae335577017d92bc3938b2eeaf9cfbb0065a94cca21 *third_party/ltp/bin/1/getgid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getgid03.elf.gz.sha256 ================================================ 456c5252cab241d94fd9ba7cd3dd4a972de0c2f036e551080968c0ef9a9931c1 *third_party/ltp/bin/1/getgid03.elf.gz ================================================ FILE: third_party/ltp/bin/1/getgroups03.elf.gz.sha256 ================================================ 9cf7085236f7808c3253a63ecd018c94df7ae1c03fe1a0a42ab45e25b77e1ae3 *third_party/ltp/bin/1/getgroups03.elf.gz ================================================ FILE: third_party/ltp/bin/1/gethostname01.elf.gz.sha256 ================================================ c5b299bd1fcdd8ed1eccd9059156cea86a4f5a79f9780f5b1180350841ee0d18 *third_party/ltp/bin/1/gethostname01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getitimer01.elf.gz.sha256 ================================================ dcf974e6927fd6cf594a974517e85490b6161b4f118b5358d19cbb2e61748641 *third_party/ltp/bin/1/getitimer01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getpagesize01.elf.gz.sha256 ================================================ 1b10f68c094dd732a530624ae8987747c0b9661f90288589371758c6261b36e8 *third_party/ltp/bin/1/getpagesize01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getpgid01.elf.gz.sha256 ================================================ 5e4501d06f36acf2cdd8c154c792ef4fc68a5d39ec39f6a685cf1871c548afff *third_party/ltp/bin/1/getpgid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getpgid02.elf.gz.sha256 ================================================ 34442a9fe3dbfe251ac5c5dc27d2fa9fd3818e1125d88a05f6dbc9e5ba06a97d *third_party/ltp/bin/1/getpgid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getpgrp01.elf.gz.sha256 ================================================ 53d857be1d935758dc4506c15e038b06159326a5f385218410459099f58a7791 *third_party/ltp/bin/1/getpgrp01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getpid01.elf.gz.sha256 ================================================ 02609d2e939c67054847e73c8139c05d3881460c21d8f39f481ab87fceaf90ec *third_party/ltp/bin/1/getpid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getpid02.elf.gz.sha256 ================================================ 9a013299b2aa6594c78679565ba13a0d0328eb4b653309d12c79d1106fd36653 *third_party/ltp/bin/1/getpid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getppid01.elf.gz.sha256 ================================================ 6fe5b617de4314af42841172725bb1d6c1e7d0da93fc34f0050734975e70a368 *third_party/ltp/bin/1/getppid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getppid02.elf.gz.sha256 ================================================ 102f3fa6b84aa8169897c3dad81a7e0dc42699fbcdc1b686abed77763f69a0b8 *third_party/ltp/bin/1/getppid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getpriority02.elf.gz.sha256 ================================================ 868d0e61ed6e71c968e0e9cb6cd96d741d105bbc15b9d6d6c4059056c5d61330 *third_party/ltp/bin/1/getpriority02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getrandom02.elf.gz.sha256 ================================================ 787875bcfd619c58e3a2e2388cc67b9192a88a252d7b09ebc40a9bb546e284f4 *third_party/ltp/bin/1/getrandom02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getrandom03.elf.gz.sha256 ================================================ b1ba2d5ec5e4b1000093fc027ad1a6a2710aed038384b822174194a131ba3cb1 *third_party/ltp/bin/1/getrandom03.elf.gz ================================================ FILE: third_party/ltp/bin/1/getrandom04.elf.gz.sha256 ================================================ d150112c5d509a1ed27d49c8677ef315ea136a6d19a0dccf5e4d2cdc40c61fc9 *third_party/ltp/bin/1/getrandom04.elf.gz ================================================ FILE: third_party/ltp/bin/1/getrlimit01.elf.gz.sha256 ================================================ df74c75e2668563ed4eadbd12766f396b33c115177f8dff0a6e1c26b5f9555f9 *third_party/ltp/bin/1/getrlimit01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getrlimit02.elf.gz.sha256 ================================================ 7b8538a1df3996ce686632b8ddbf905f1aa9149b541c3fd2fc2aeb51a10699f6 *third_party/ltp/bin/1/getrlimit02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getrlimit03.elf.gz.sha256 ================================================ 73baf6abf9d4b7ae864c90da0e7c23dc2cef907c7f365e2ac4d6e8f9dac75d35 *third_party/ltp/bin/1/getrlimit03.elf.gz ================================================ FILE: third_party/ltp/bin/1/getrusage01.elf.gz.sha256 ================================================ 74100647c6d47569fb7fa1155bdb57b580d9542cbdc7f082db25dca4a81802f0 *third_party/ltp/bin/1/getrusage01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getsid01.elf.gz.sha256 ================================================ 32aeb85fd9fca70354e97f1ddb2b86a8e2657aa7713ebbefd2553b1fe0205a1d *third_party/ltp/bin/1/getsid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getsid02.elf.gz.sha256 ================================================ 67748e64e03b8356fdb6c79f0ee72e9208a8b806665f72612a87ab592064209e *third_party/ltp/bin/1/getsid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/gettid01.elf.gz.sha256 ================================================ e7f964678c8b55e90d1a2653867a28b8316d05f73ff9106c6786deca7a99d38e *third_party/ltp/bin/1/gettid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/gettimeofday01.elf.gz.sha256 ================================================ 9c749c6feacfb986118c2be8edaeee672cf0ec16b6605459bbd6b501eec6fe86 *third_party/ltp/bin/1/gettimeofday01.elf.gz ================================================ FILE: third_party/ltp/bin/1/gettimeofday02.elf.gz.sha256 ================================================ c4f3d667506d325ecd638848ca7e92102cbb824c53d5fe28da69a1b2af8d7c6f *third_party/ltp/bin/1/gettimeofday02.elf.gz ================================================ FILE: third_party/ltp/bin/1/getuid01.elf.gz.sha256 ================================================ caf95d8ebabe3013f69e090e4a88e893268b0a01ed01cb403ea127bec0da30e0 *third_party/ltp/bin/1/getuid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/getuid03.elf.gz.sha256 ================================================ 8094c8254ec6bcfcb2d632d28357cc8e41b4298b239fae1b3e0c65793c09e52b *third_party/ltp/bin/1/getuid03.elf.gz ================================================ FILE: third_party/ltp/bin/1/growfiles.elf.gz.sha256 ================================================ 8c03c7f0ea872e28fe3ae4a530a49b8ba8c565cd5005234187f939c1560b65ea *third_party/ltp/bin/1/growfiles.elf.gz ================================================ FILE: third_party/ltp/bin/1/hackbench.elf.gz.sha256 ================================================ 8d24a5411ea08f171cb92e6d92da85d220bf49c07ef5d7608410f8018538bf39 *third_party/ltp/bin/1/hackbench.elf.gz ================================================ FILE: third_party/ltp/bin/1/hugemmap06.elf.gz.sha256 ================================================ 7d4c5b7371a630fe7467a58b962aff14d6c8d7e23ff8712a45f6ff124f33d0f4 *third_party/ltp/bin/1/hugemmap06.elf.gz ================================================ FILE: third_party/ltp/bin/1/in6_01.elf.gz.sha256 ================================================ 870f8045255618e6e80169c54a9fc12a2b610919f3452d6686f9a477b6d28fec *third_party/ltp/bin/1/in6_01.elf.gz ================================================ FILE: third_party/ltp/bin/1/inode01.elf.gz.sha256 ================================================ 592c1e57029cf801980f1e7926cf679d5e10f74fb69610da1bcdc87136362108 *third_party/ltp/bin/1/inode01.elf.gz ================================================ FILE: third_party/ltp/bin/1/inode02.elf.gz.sha256 ================================================ a0f7cd8e90a7c6ab6ef995870147493f60f2e31105f92067e06f011a2fe13896 *third_party/ltp/bin/1/inode02.elf.gz ================================================ FILE: third_party/ltp/bin/1/kill02.elf.gz.sha256 ================================================ 5dd7518e70ec897317073595fca2e21bd0da16fca626e86d1e7e432b70129619 *third_party/ltp/bin/1/kill02.elf.gz ================================================ FILE: third_party/ltp/bin/1/kill03.elf.gz.sha256 ================================================ eb1621ad8cd414750f9c5fb2db874ada6aadc1ac9aeda53133773dbfebf8ec4b *third_party/ltp/bin/1/kill03.elf.gz ================================================ FILE: third_party/ltp/bin/1/kill06.elf.gz.sha256 ================================================ e4161cee47be47043984f6d77ec0439dc0c01af85f65f27ae8367d8c0a6fef90 *third_party/ltp/bin/1/kill06.elf.gz ================================================ FILE: third_party/ltp/bin/1/kill08.elf.gz.sha256 ================================================ 4dad7568238887ede7a96c8ad76df6a24d0a22113ce592d85eed6eb91479b1b1 *third_party/ltp/bin/1/kill08.elf.gz ================================================ FILE: third_party/ltp/bin/1/kill09.elf.gz.sha256 ================================================ 7ad95b410c5415ff9966f63fa8a49c6437a1ca2b2703f08a3a59a35eca0aad63 *third_party/ltp/bin/1/kill09.elf.gz ================================================ FILE: third_party/ltp/bin/1/link02.elf.gz.sha256 ================================================ b98765d904531196e421b1e6719a3721ad2d6c21c3ad1dd0b915e473699ee4b1 *third_party/ltp/bin/1/link02.elf.gz ================================================ FILE: third_party/ltp/bin/1/link03.elf.gz.sha256 ================================================ 195cda95093c0b6ba4e7ace1b72416b7e0359cbd5271b80c2bc1bceb2b24e285 *third_party/ltp/bin/1/link03.elf.gz ================================================ FILE: third_party/ltp/bin/1/link05.elf.gz.sha256 ================================================ 416fd1baf3f4018c8c0a52745f1dd6aa4653c762fd455b8368f36c8bb8528659 *third_party/ltp/bin/1/link05.elf.gz ================================================ FILE: third_party/ltp/bin/1/linkat01.elf.gz.sha256 ================================================ 28c6d5041f7cf3c7211af02a98dc62ab4b3ab3420e3ab4d1f8ea1bac0bc59556 *third_party/ltp/bin/1/linkat01.elf.gz ================================================ FILE: third_party/ltp/bin/1/listen01.elf.gz.sha256 ================================================ 0394528e7cb651ac719c17b2d7608ac060f0ec3770f40bf924d2154f43c3c64c *third_party/ltp/bin/1/listen01.elf.gz ================================================ FILE: third_party/ltp/bin/1/llseek01.elf.gz.sha256 ================================================ 418b433c47e5f9546e9bad51cc562127e05ea035852b956c40a8dec90878aa48 *third_party/ltp/bin/1/llseek01.elf.gz ================================================ FILE: third_party/ltp/bin/1/llseek02.elf.gz.sha256 ================================================ 040efb8fc8b1655f2c8b26766294f29e2ed9339501f89fb9ad7cfafcbe6da398 *third_party/ltp/bin/1/llseek02.elf.gz ================================================ FILE: third_party/ltp/bin/1/llseek03.elf.gz.sha256 ================================================ a0ebac43922529a0fbc6d01a25788e8334c059b5da239c425b52639f4bb0db40 *third_party/ltp/bin/1/llseek03.elf.gz ================================================ FILE: third_party/ltp/bin/1/locktests.elf.gz.sha256 ================================================ 4f9d5a58a86c019b036ba93c5a8143cf7d46bd2811cf0ca8412ae3c3c28100ce *third_party/ltp/bin/1/locktests.elf.gz ================================================ FILE: third_party/ltp/bin/1/lseek01.elf.gz.sha256 ================================================ 3c71ccd178c7df973d9a0e15e04dda547e60c6b9ae59b2e51548d3f53d6ed72f *third_party/ltp/bin/1/lseek01.elf.gz ================================================ FILE: third_party/ltp/bin/1/lseek02.elf.gz.sha256 ================================================ 417156dc71fb0452d208f1812beab018340870e97f156e78bf4f1daddd8ae83e *third_party/ltp/bin/1/lseek02.elf.gz ================================================ FILE: third_party/ltp/bin/1/lseek07.elf.gz.sha256 ================================================ ee1747bdf558435cc12664f663509c07329f25676cac4951b56df4a870e16190 *third_party/ltp/bin/1/lseek07.elf.gz ================================================ FILE: third_party/ltp/bin/1/mkdir05.elf.gz.sha256 ================================================ cc5eaaa8d08ddd857f43c692f2775a33c53a81075f4a94d165c569a370fbdae8 *third_party/ltp/bin/1/mkdir05.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap-corruption01.elf.gz.sha256 ================================================ 014915878570853de3c6271a3089d1f8b59dc1f6bc8edc6cf3dc9168bf678a54 *third_party/ltp/bin/1/mmap-corruption01.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap001.elf.gz.sha256 ================================================ f2e9521f0b91fd320abfe427d5f8a376c3360e9549f54e1b3324ca097f38cf87 *third_party/ltp/bin/1/mmap001.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap01.elf.gz.sha256 ================================================ 2ac88ff6d2fe9427eda950091002a01c7b3316a01f628475a3ffaf3337e050ca *third_party/ltp/bin/1/mmap01.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap02.elf.gz.sha256 ================================================ 88f95306e64572baa6bdda9aa68bb36556a051460f25b1e50812c8c19d5eaec6 *third_party/ltp/bin/1/mmap02.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap03.elf.gz.sha256 ================================================ f3a004bf6077f718d1f92ce748efbb4097be05165c22ef66ede987fd10d2a8ce *third_party/ltp/bin/1/mmap03.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap04.elf.gz.sha256 ================================================ f0d956f7483b10d18fc16cb450b19cd3f54c11d98a7da887c1aa3fa4fa6d8993 *third_party/ltp/bin/1/mmap04.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap05.elf.gz.sha256 ================================================ e62bef67c05ebe2c520c93d401f0ea38371b2ef11536afd8ce75143f199b46fa *third_party/ltp/bin/1/mmap05.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap06.elf.gz.sha256 ================================================ 8f01e2e8bbb5afbebf8cccba189634f68142571a071c59a1ac113132b7f94659 *third_party/ltp/bin/1/mmap06.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap07.elf.gz.sha256 ================================================ b2601237a7122478500d378edb57658613ca96723ed2000953ca4d46488d5db4 *third_party/ltp/bin/1/mmap07.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap08.elf.gz.sha256 ================================================ 1a69d969e57b00410fcc0adeefbdaae4e83b25cbc08be3b972ea6931a9e84ae6 *third_party/ltp/bin/1/mmap08.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap09.elf.gz.sha256 ================================================ 22b1fe8bf5120d123786a25d7ebc4b6b47a346a06e7d70a5589388a3da5af599 *third_party/ltp/bin/1/mmap09.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap10.elf.gz.sha256 ================================================ 740e73ea5956984197773da0c7879de7fcc6e1920f38ccab83acc32cb1808f15 *third_party/ltp/bin/1/mmap10.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap11.elf.gz.sha256 ================================================ fdc9232bda153aa9591170adfe1b015997892fc28c1e073404282ef445603f6e *third_party/ltp/bin/1/mmap11.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap12.elf.gz.sha256 ================================================ 0d20d755f7dc2ffae3545da6ea6075db0ea07b32b0b1e8caccd8d7b5afa8caa8 *third_party/ltp/bin/1/mmap12.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmap19.elf.gz.sha256 ================================================ 39500e89a3248f7b300b0d41d7562efdce61a0e7813d884df8e5717e3d673c2d *third_party/ltp/bin/1/mmap19.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmapstress01.elf.gz.sha256 ================================================ a55e338b4ad0ad1530215a79538c1d2d9e0615d5b4e8f20dc0e24f72515a0594 *third_party/ltp/bin/1/mmapstress01.elf.gz ================================================ FILE: third_party/ltp/bin/1/mmapstress04.elf.gz.sha256 ================================================ 2a4645c0d3431a776ea163deef9dfcb2f506d8c26bb2d7affd4130fa3f9d79ed *third_party/ltp/bin/1/mmapstress04.elf.gz ================================================ FILE: third_party/ltp/bin/1/mprotect02.elf.gz.sha256 ================================================ ca741a3c4347a3d6ca6b04f8d34ce8e857f22ccecbfd1484ce13a6db460012ef *third_party/ltp/bin/1/mprotect02.elf.gz ================================================ FILE: third_party/ltp/bin/1/mprotect03.elf.gz.sha256 ================================================ adbe22b176dca1ad5933eb50f839a8150b05d05eeab5d10224676142c502d998 *third_party/ltp/bin/1/mprotect03.elf.gz ================================================ FILE: third_party/ltp/bin/1/msync01.elf.gz.sha256 ================================================ 1b897961089537a1a97597594ca001ffa642378959bfc1fbd31096dcc9efda98 *third_party/ltp/bin/1/msync01.elf.gz ================================================ FILE: third_party/ltp/bin/1/msync02.elf.gz.sha256 ================================================ 0a4e6a25bb2fb549a868b5427ad07a4e278ec73ab1c5f577bc51c90190d17442 *third_party/ltp/bin/1/msync02.elf.gz ================================================ FILE: third_party/ltp/bin/1/munmap01.elf.gz.sha256 ================================================ e322c26d1f9b3bf0f90fd77ebdeb734f4acaacdca6b7cc2c6cc93c9194f28487 *third_party/ltp/bin/1/munmap01.elf.gz ================================================ FILE: third_party/ltp/bin/1/munmap02.elf.gz.sha256 ================================================ bf01f1e504f08a7632fc84960133f42afed0f3a5565a8ba81354ae74343c5686 *third_party/ltp/bin/1/munmap02.elf.gz ================================================ FILE: third_party/ltp/bin/1/munmap03.elf.gz.sha256 ================================================ 5a276dceec248d0cccb084d00df4f1767c983d8ddc7a274328f3eebc9a9b8c30 *third_party/ltp/bin/1/munmap03.elf.gz ================================================ FILE: third_party/ltp/bin/1/nanosleep01.elf.gz.sha256 ================================================ 06f00ff8c739a0ce4acbb3e4509158dd25d783b3010d5bdb5b9d258b9f1306c9 *third_party/ltp/bin/1/nanosleep01.elf.gz ================================================ FILE: third_party/ltp/bin/1/nanosleep02.elf.gz.sha256 ================================================ d07f4546e0e46ab70e950b18140d7ea150ca4fa82f714b3843f8467c2cae9d54 *third_party/ltp/bin/1/nanosleep02.elf.gz ================================================ FILE: third_party/ltp/bin/1/nanosleep04.elf.gz.sha256 ================================================ dbbd60eb4d8b1c23c8645b49e54de15cac0b115e33055a30113b4dd458635de4 *third_party/ltp/bin/1/nanosleep04.elf.gz ================================================ FILE: third_party/ltp/bin/1/nice04.elf.gz.sha256 ================================================ 769b42883f1b13b22ca4e5f34342c51d88fa93cac4c8b20e126b13831433b8ef *third_party/ltp/bin/1/nice04.elf.gz ================================================ FILE: third_party/ltp/bin/1/open01.elf.gz.sha256 ================================================ b31fca912159b0a99525e19384406f795b59c80badf221d7e01f8eac4a4c54ac *third_party/ltp/bin/1/open01.elf.gz ================================================ FILE: third_party/ltp/bin/1/open03.elf.gz.sha256 ================================================ 09b8341b422624d7b1d3950d539fbef0ab111d1530f8efc283b38445e710d094 *third_party/ltp/bin/1/open03.elf.gz ================================================ FILE: third_party/ltp/bin/1/open04.elf.gz.sha256 ================================================ d81143cbbcf3801d3b5e73cf861473fc86f3fd3cdb5290489b87b52bd5b1bea9 *third_party/ltp/bin/1/open04.elf.gz ================================================ FILE: third_party/ltp/bin/1/open06.elf.gz.sha256 ================================================ e26997671b0e8b7f05f1ad4305e202788fecfd7e9bf4a87a6a6345f6e5492aba *third_party/ltp/bin/1/open06.elf.gz ================================================ FILE: third_party/ltp/bin/1/open09.elf.gz.sha256 ================================================ a250953d56b1f0dfc82142bc61c6a6ce6d07e9234446fcccb1e8e99ca722e511 *third_party/ltp/bin/1/open09.elf.gz ================================================ FILE: third_party/ltp/bin/1/open11.elf.gz.sha256 ================================================ 3648a047b316250630689b4c00f0c48c56e40cef33c1c75bf4f73af4264c29e1 *third_party/ltp/bin/1/open11.elf.gz ================================================ FILE: third_party/ltp/bin/1/open14.elf.gz.sha256 ================================================ 0fb8de5191ca259a19ed84ffa5a4df6b19ae5ed433a17637c30a2f168428ca08 *third_party/ltp/bin/1/open14.elf.gz ================================================ FILE: third_party/ltp/bin/1/openat03.elf.gz.sha256 ================================================ 4947a512eb005803409bd2e3d01f35d424d93fdf074f64420ee1a0d1621671b8 *third_party/ltp/bin/1/openat03.elf.gz ================================================ FILE: third_party/ltp/bin/1/pause01.elf.gz.sha256 ================================================ e268cb5284fca775edbf8aa95f6b896bcd1dc3f5335b12414446e2971d877c3e *third_party/ltp/bin/1/pause01.elf.gz ================================================ FILE: third_party/ltp/bin/1/pause02.elf.gz.sha256 ================================================ bea9da1959066fe0e4a6bdd3e83ba00477f3270359926f8bb9be4d4074d3a75a *third_party/ltp/bin/1/pause02.elf.gz ================================================ FILE: third_party/ltp/bin/1/pause03.elf.gz.sha256 ================================================ e78b20292b20cc58fe74a67e6ca7dacb42841820648e090dd60a5f35c35a40ff *third_party/ltp/bin/1/pause03.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe01.elf.gz.sha256 ================================================ 21681ba03b3811ac626f32cd1c8531d347f754f90bfe59071734abec7954fb80 *third_party/ltp/bin/1/pipe01.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe02.elf.gz.sha256 ================================================ f4f1e32188a174d5c346102355bf65a0f3367bd10caeaeaca5e56cacb141426d *third_party/ltp/bin/1/pipe02.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe03.elf.gz.sha256 ================================================ 8299ba2566f7e07364f39243b85ecf4c7cd14331558b251bd3248daca95407e4 *third_party/ltp/bin/1/pipe03.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe04.elf.gz.sha256 ================================================ 121381ad75936770b6a4ee0b8202d7cf0f0ad490c6c7d26c5f7b7ba5acbbe31f *third_party/ltp/bin/1/pipe04.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe06.elf.gz.sha256 ================================================ c1bff6d82fb71383dfcf87f3890c0308f2ac697f731956a856b326193bd09ffd *third_party/ltp/bin/1/pipe06.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe07.elf.gz.sha256 ================================================ 7fcc23914bc884afea92ace5b2206ba9e6f501ad45e37e75632ff9cd7e6ca7f3 *third_party/ltp/bin/1/pipe07.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe08.elf.gz.sha256 ================================================ 9f35c887772144d180fb37bacbcedd60905b45ca372025d099e090c869fc7de5 *third_party/ltp/bin/1/pipe08.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe09.elf.gz.sha256 ================================================ 2f33e0fa69da950f3d1dba574252dcf5bc44ab12e500a607f768953d76a7a391 *third_party/ltp/bin/1/pipe09.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe10.elf.gz.sha256 ================================================ 51fb550c891654f5a12bf66673acf5522e7c28633f4ee6a4ef36927c22d29fca *third_party/ltp/bin/1/pipe10.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe11.elf.gz.sha256 ================================================ da084f81a3ee615c824786fdcca7214598a856c368d0a8c9ff28bd6e68c6a012 *third_party/ltp/bin/1/pipe11.elf.gz ================================================ FILE: third_party/ltp/bin/1/pipe13.elf.gz.sha256 ================================================ b1ed3088eade525609e2593b13b6b2e1dd67fd27395d735706426e981f8968c0 *third_party/ltp/bin/1/pipe13.elf.gz ================================================ FILE: third_party/ltp/bin/1/poll01.elf.gz.sha256 ================================================ dbf72c32fed35dd081d164752e5a082c8cdbbfff25d7a2fe5331b471b432000e *third_party/ltp/bin/1/poll01.elf.gz ================================================ FILE: third_party/ltp/bin/1/poll02.elf.gz.sha256 ================================================ 93a873fd84076c55c4d8b7fcf04603395bc9f0582fc20c8ef79567b902bc1823 *third_party/ltp/bin/1/poll02.elf.gz ================================================ FILE: third_party/ltp/bin/1/pread01.elf.gz.sha256 ================================================ 7042380746ac89df2813979de12a05dba2aaff845ff29bbf3b5b2989dbbd8087 *third_party/ltp/bin/1/pread01.elf.gz ================================================ FILE: third_party/ltp/bin/1/pread01_64.elf.gz.sha256 ================================================ 58a552a0ec34dc38645be19c99ed729e9f1340829d64197b44eba42576f7bb5a *third_party/ltp/bin/1/pread01_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pread02.elf.gz.sha256 ================================================ fa11ee195ffe4a00829b01ab9accb4ec986b54a9a2c6af75bb20b5e7f74c2e66 *third_party/ltp/bin/1/pread02.elf.gz ================================================ FILE: third_party/ltp/bin/1/pread02_64.elf.gz.sha256 ================================================ 45aea3fb8a5a627f60fff94da4f5ba508c47972c5fe932ef1d9c80d5e7526fee *third_party/ltp/bin/1/pread02_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/preadv01.elf.gz.sha256 ================================================ 02aeca903f6cd92946dbc39352f7f4ab48682c392178601a588425e0da47f4f0 *third_party/ltp/bin/1/preadv01.elf.gz ================================================ FILE: third_party/ltp/bin/1/preadv01_64.elf.gz.sha256 ================================================ d0d7e905516756a692dc3ab4e37fefc2849a5f70171dfdae407d1cd27c4a5f44 *third_party/ltp/bin/1/preadv01_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pselect02.elf.gz.sha256 ================================================ 3638423affdb93f0849da45a3e621c5180f2350ea42c17b9297b995a9db7dd1c *third_party/ltp/bin/1/pselect02.elf.gz ================================================ FILE: third_party/ltp/bin/1/pselect02_64.elf.gz.sha256 ================================================ 82cb9b8b6d96690ad8c677688425b9968521b85f89a0dc1a9a4490f79a88463a *third_party/ltp/bin/1/pselect02_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pselect03.elf.gz.sha256 ================================================ 3a72874442ae9cd33039bfd2a27cf529eb6d39b01fd39a7e838087dbaeec9c28 *third_party/ltp/bin/1/pselect03.elf.gz ================================================ FILE: third_party/ltp/bin/1/pselect03_64.elf.gz.sha256 ================================================ fb0fa986770b7a9f83834858a8119ccc7abb385ad4290b41a3fc971509fcadfc *third_party/ltp/bin/1/pselect03_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pty06.elf.gz.sha256 ================================================ 4c9c2882f36bfab3ac4097136030837f72222b30bc460dcd0a9b8b9f1056c2c2 *third_party/ltp/bin/1/pty06.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwrite01_64.elf.gz.sha256 ================================================ b913600fe7b9324ee6e380b0c6f50b97a78007902394f664f216a95ffe549b66 *third_party/ltp/bin/1/pwrite01_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwrite02.elf.gz.sha256 ================================================ b64f0ffea3a0856a5690ab3b4ece8204159d828b5a96e466141b9c6e44cb1c9e *third_party/ltp/bin/1/pwrite02.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwrite02_64.elf.gz.sha256 ================================================ 8ff1db19280f2bf7f1d8954ecc16d499ace3b175ed7e9a7d83237ba8d2c689d9 *third_party/ltp/bin/1/pwrite02_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwrite03.elf.gz.sha256 ================================================ ebced3744c2071d2847eb58712314cce880cdabff42a38be5130a88be7f3ac64 *third_party/ltp/bin/1/pwrite03.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwrite03_64.elf.gz.sha256 ================================================ 8c9e8bb322933a397eaa02ffb5d9a3cab76847b92b56964230c5a65d6fd5fe02 *third_party/ltp/bin/1/pwrite03_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwrite04.elf.gz.sha256 ================================================ abc5becf429df58a85064a6b1172784215d7880f6b2367f0916eeaa1de198ef6 *third_party/ltp/bin/1/pwrite04.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwrite04_64.elf.gz.sha256 ================================================ 942550b0a88e9446f89ea5bc1d38627d6882e311b64ed4ab7914df269661956b *third_party/ltp/bin/1/pwrite04_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwritev01.elf.gz.sha256 ================================================ 86f58c0c80e38e875d1713bd393179b0e4e9e1950694205324dbf31b8c5d89e7 *third_party/ltp/bin/1/pwritev01.elf.gz ================================================ FILE: third_party/ltp/bin/1/pwritev01_64.elf.gz.sha256 ================================================ 5afae7e0378b2030d9a18da16c8e2701f0fbb1f59673294106f2439dcc1c2501 *third_party/ltp/bin/1/pwritev01_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/read01.elf.gz.sha256 ================================================ 65542951cf0909e5d468ceff0e2de96947faeaf1c44f8088beb3fbb378131026 *third_party/ltp/bin/1/read01.elf.gz ================================================ FILE: third_party/ltp/bin/1/read03.elf.gz.sha256 ================================================ 5ec2e33296157424f9c2e19be3258aeaeb012709bfda083bcb0ff4823f8ed303 *third_party/ltp/bin/1/read03.elf.gz ================================================ FILE: third_party/ltp/bin/1/read04.elf.gz.sha256 ================================================ d05c8cde47f3404844317e130d17b378549d77e49bbae757360c31b7aff99848 *third_party/ltp/bin/1/read04.elf.gz ================================================ FILE: third_party/ltp/bin/1/readdir01.elf.gz.sha256 ================================================ 2a6d3c39ba60c1155fb253804b895dff3a5eadc25a433c89ef8cfaea22848706 *third_party/ltp/bin/1/readdir01.elf.gz ================================================ FILE: third_party/ltp/bin/1/readlink01.elf.gz.sha256 ================================================ f358605ca4385f53bf96a92fe697f3bd5367608c33e045365a70afa4b89c3dfa *third_party/ltp/bin/1/readlink01.elf.gz ================================================ FILE: third_party/ltp/bin/1/readv01.elf.gz.sha256 ================================================ 0c6d1e63495fd8ac78db765922a80ed6319c8ae96338be62f8a9192b2ae35e46 *third_party/ltp/bin/1/readv01.elf.gz ================================================ FILE: third_party/ltp/bin/1/recvmsg02.elf.gz.sha256 ================================================ 831eed3db116df2d4f9e7851156d8c64b8433e89d4fefe7df8e8127c417b677d *third_party/ltp/bin/1/recvmsg02.elf.gz ================================================ FILE: third_party/ltp/bin/1/rename09.elf.gz.sha256 ================================================ c53212eca0e8a21fc4f4de8cf4117961d343e5fc3d8f39aaf2ae074629783b05 *third_party/ltp/bin/1/rename09.elf.gz ================================================ FILE: third_party/ltp/bin/1/rename14.elf.gz.sha256 ================================================ 02fa3a4b6c2cc65a1046489bdf2ae4a90ff6eac5d136f7a0bfc0162851de7884 *third_party/ltp/bin/1/rename14.elf.gz ================================================ FILE: third_party/ltp/bin/1/rmdir01.elf.gz.sha256 ================================================ 0bc718218998bfc10791a227603593985e6923e92cde446ddaa45321429d68eb *third_party/ltp/bin/1/rmdir01.elf.gz ================================================ FILE: third_party/ltp/bin/1/sbrk02.elf.gz.sha256 ================================================ e9acf385a169d98858ba49c5546ed1f154c9c467f0c547ecba27ab5b77c4301e *third_party/ltp/bin/1/sbrk02.elf.gz ================================================ FILE: third_party/ltp/bin/1/sendto01.elf.gz.sha256 ================================================ 2954400919c7eeb9b06833cdf9007ed800074835c830c0810d48b9d63e8e0fb0 *third_party/ltp/bin/1/sendto01.elf.gz ================================================ FILE: third_party/ltp/bin/1/set_robust_list01.elf.gz.sha256 ================================================ 5b28043519629b8cfd33f1870b5c7a9bde3d23a4954b2d2a5d4ee47632822bf2 *third_party/ltp/bin/1/set_robust_list01.elf.gz ================================================ FILE: third_party/ltp/bin/1/set_tid_address01.elf.gz.sha256 ================================================ f1df4c36b54930fa95fb6568b3c657adcd454e07e2757359356635449b9892b1 *third_party/ltp/bin/1/set_tid_address01.elf.gz ================================================ FILE: third_party/ltp/bin/1/setegid02.elf.gz.sha256 ================================================ 6ca2790f5eb1012cb3d95731e2c953147da9b3e4b162d173643524d8e7ec4919 *third_party/ltp/bin/1/setegid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/setgroups01.elf.gz.sha256 ================================================ ac3968766d412aeab81b059c8ff5c39ad762c1070a9c6f11b2182ccb36d4eda9 *third_party/ltp/bin/1/setgroups01.elf.gz ================================================ FILE: third_party/ltp/bin/1/setgroups02.elf.gz.sha256 ================================================ 6a22b183a2b4efa4bcd53bab3269e0082e4b1bd46facb5a8c3e64420c57b6e3f *third_party/ltp/bin/1/setgroups02.elf.gz ================================================ FILE: third_party/ltp/bin/1/setgroups04.elf.gz.sha256 ================================================ 6038f53502a887529397ddfaec1c01e1833b18450f97686d32b83225d71e45b5 *third_party/ltp/bin/1/setgroups04.elf.gz ================================================ FILE: third_party/ltp/bin/1/setitimer02.elf.gz.sha256 ================================================ 8e76702d9f6a77a861a40b8e8c78dad1cc3d56a6a9b9118567c7712e311f354d *third_party/ltp/bin/1/setitimer02.elf.gz ================================================ FILE: third_party/ltp/bin/1/setpgid01.elf.gz.sha256 ================================================ 0d076705f91735d912bcc86d3ae43b5baae5f84d2afc30415fabd01ae7a11f4e *third_party/ltp/bin/1/setpgid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/setpgid02.elf.gz.sha256 ================================================ 7149e13e06a56e913b9705bba46f914fdfd1fefebc9a267a41439f317ee828e7 *third_party/ltp/bin/1/setpgid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/setpgrp01.elf.gz.sha256 ================================================ 164591fb99436aec3b5effed6665787acb463a804ceae2556abdec64bd594783 *third_party/ltp/bin/1/setpgrp01.elf.gz ================================================ FILE: third_party/ltp/bin/1/setpgrp02.elf.gz.sha256 ================================================ c42c931e20e6365b55ccba56b1f637faf5278c3fcbd65b98cf4066afde4f2e7b *third_party/ltp/bin/1/setpgrp02.elf.gz ================================================ FILE: third_party/ltp/bin/1/setpriority02.elf.gz.sha256 ================================================ af131a00f22eed43cd895814ed834d99564002374b1c9c52683b07445bbb7bd8 *third_party/ltp/bin/1/setpriority02.elf.gz ================================================ FILE: third_party/ltp/bin/1/setrlimit03.elf.gz.sha256 ================================================ ae4c9ebfc97a42a71f444029f1b9f4687702538ba46d1f5def3671bcc65936e7 *third_party/ltp/bin/1/setrlimit03.elf.gz ================================================ FILE: third_party/ltp/bin/1/setsid01.elf.gz.sha256 ================================================ c90414499a5eb6d29771eb56c5f471c30133eaff19a795780ba998a8c40389d0 *third_party/ltp/bin/1/setsid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/setsockopt03.elf.gz.sha256 ================================================ a27b861248014aff915e32c000b81fa168473ef40ba29f35e79a9731649f0885 *third_party/ltp/bin/1/setsockopt03.elf.gz ================================================ FILE: third_party/ltp/bin/1/sigaction02.elf.gz.sha256 ================================================ 64b78a817c0058052b4160d47c6aef147318d977175daa5ef037a5cf63f87a50 *third_party/ltp/bin/1/sigaction02.elf.gz ================================================ FILE: third_party/ltp/bin/1/sigaltstack01.elf.gz.sha256 ================================================ 1a36e1e84133725f402025b5af620b7b5ab346bdd969e2989762f4b0c23d4641 *third_party/ltp/bin/1/sigaltstack01.elf.gz ================================================ FILE: third_party/ltp/bin/1/sigaltstack02.elf.gz.sha256 ================================================ d38033619add02d9f8d7779bb757eacc894e352e3b6bc977a06003a19377fe5d *third_party/ltp/bin/1/sigaltstack02.elf.gz ================================================ FILE: third_party/ltp/bin/1/signal01.elf.gz.sha256 ================================================ c0a181b5eb7005f0f71621345a9fa14cc1a491b1617329ea32c10bd1018d7144 *third_party/ltp/bin/1/signal01.elf.gz ================================================ FILE: third_party/ltp/bin/1/signal02.elf.gz.sha256 ================================================ 56e417b2db416f6a8c167a8861b77c2293c05cd29e35ee948b2bfaa8d631bded *third_party/ltp/bin/1/signal02.elf.gz ================================================ FILE: third_party/ltp/bin/1/signal04.elf.gz.sha256 ================================================ 5e7a8fb01c3145bb83dc60d86c5dd577a08341e8bd6d94401950aff95e385871 *third_party/ltp/bin/1/signal04.elf.gz ================================================ FILE: third_party/ltp/bin/1/signal06.elf.gz.sha256 ================================================ 12fa72017075bf4d6dc312adef7f8406a176a96572feb343c1af245a154d3c65 *third_party/ltp/bin/1/signal06.elf.gz ================================================ FILE: third_party/ltp/bin/1/sigprocmask01.elf.gz.sha256 ================================================ 1de80efa5a2f21ade69acdd3004150b82bf935d9360dc6adfe3a293ba3f700ca *third_party/ltp/bin/1/sigprocmask01.elf.gz ================================================ FILE: third_party/ltp/bin/1/socket02.elf.gz.sha256 ================================================ 70f0fc9a44b9cc7156c296069e83d468d5a61622e185a4a4c0c0bb75417e84e0 *third_party/ltp/bin/1/socket02.elf.gz ================================================ FILE: third_party/ltp/bin/1/socketpair02.elf.gz.sha256 ================================================ 5765497c9558fa8961c5858ccce0624c47f3fe8dfeac6e879985921e3a7bdff7 *third_party/ltp/bin/1/socketpair02.elf.gz ================================================ FILE: third_party/ltp/bin/1/stat01.elf.gz.sha256 ================================================ 13c6b9ff1896587ac4c29d926c7121b376ec0680bb6ca1053f38d8327ec2156a *third_party/ltp/bin/1/stat01.elf.gz ================================================ FILE: third_party/ltp/bin/1/stat01_64.elf.gz.sha256 ================================================ ccc8f4bf9c35477a11530d3047480293e5ec16c59a28d2b9dfcfb9e74b6106f5 *third_party/ltp/bin/1/stat01_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/stat02.elf.gz.sha256 ================================================ acc4241f08a5babe083492ba382a1796e8e6530a0c34c134ad9f48d765cdc617 *third_party/ltp/bin/1/stat02.elf.gz ================================================ FILE: third_party/ltp/bin/1/stat02_64.elf.gz.sha256 ================================================ 11cec60f48f61a56b6ba8888053281ccb89dccb8f7bf0684b52f4ef4cedd7783 *third_party/ltp/bin/1/stat02_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/symlink01.elf.gz.sha256 ================================================ dce1982979e6e83a3df53a193be057094182bf8e650b911f5bc83187b306145e *third_party/ltp/bin/1/symlink01.elf.gz ================================================ FILE: third_party/ltp/bin/1/symlink02.elf.gz.sha256 ================================================ 5fb24c797609f400c143bc69b60a8f437f40ab701c9b92eb6ae336dd1c6bf021 *third_party/ltp/bin/1/symlink02.elf.gz ================================================ FILE: third_party/ltp/bin/1/symlink04.elf.gz.sha256 ================================================ ea03a48b5c600459424036e3a46292aeeef8453eeed49aa8d4f622d044638b7d *third_party/ltp/bin/1/symlink04.elf.gz ================================================ FILE: third_party/ltp/bin/1/symlinkat01.elf.gz.sha256 ================================================ e52b143e4a64b35864c552d3f764835a2e2880ec38514a7587d5a79500dae631 *third_party/ltp/bin/1/symlinkat01.elf.gz ================================================ FILE: third_party/ltp/bin/1/tkill01.elf.gz.sha256 ================================================ eb4e15a8f29ea32f2a97250cbf15cb213fdb7ecad15d6bf2ffed560c4e97f428 *third_party/ltp/bin/1/tkill01.elf.gz ================================================ FILE: third_party/ltp/bin/1/tkill02.elf.gz.sha256 ================================================ 82bbe34d40233f60172f9496f3293b178dc7b47d5f855e511b74d10de0324193 *third_party/ltp/bin/1/tkill02.elf.gz ================================================ FILE: third_party/ltp/bin/1/truncate02.elf.gz.sha256 ================================================ 46d32c84cc020f326328124c49b4b5a2a8e4b81c7eb6273567420cbdaea5a14f *third_party/ltp/bin/1/truncate02.elf.gz ================================================ FILE: third_party/ltp/bin/1/truncate02_64.elf.gz.sha256 ================================================ 63eac26bd0a45df2597004189cf694a7a564507e9746e4adf63089075ce0cf38 *third_party/ltp/bin/1/truncate02_64.elf.gz ================================================ FILE: third_party/ltp/bin/1/unlink05.elf.gz.sha256 ================================================ 834910d2f9085c7d1ce7a4a4667cb7b0af2a21253064df37d8ebf710d9a1e9f6 *third_party/ltp/bin/1/unlink05.elf.gz ================================================ FILE: third_party/ltp/bin/1/unlink08.elf.gz.sha256 ================================================ 08eedbb4bf61861219cf96ee11699c93809ba832c87146fa01681c5c65472b40 *third_party/ltp/bin/1/unlink08.elf.gz ================================================ FILE: third_party/ltp/bin/1/wait01.elf.gz.sha256 ================================================ cf49c0184638388f915d000b8aa859f73a933b85a6fe5497e90dca6701161aec *third_party/ltp/bin/1/wait01.elf.gz ================================================ FILE: third_party/ltp/bin/1/wait02.elf.gz.sha256 ================================================ 6f159e2243a448201a047297f89846bc4abe6023767455dce440573f1b632ff7 *third_party/ltp/bin/1/wait02.elf.gz ================================================ FILE: third_party/ltp/bin/1/wait401.elf.gz.sha256 ================================================ ae331a2c396b826680340ea58c527224bebf1c678b11e4ba39b30d127d98c713 *third_party/ltp/bin/1/wait401.elf.gz ================================================ FILE: third_party/ltp/bin/1/wait402.elf.gz.sha256 ================================================ e351aa3622f3b04443378b365acbcbaa3dffdaa0c7a84097da225115788ef6ec *third_party/ltp/bin/1/wait402.elf.gz ================================================ FILE: third_party/ltp/bin/1/wait403.elf.gz.sha256 ================================================ a9b9882e4b0de38bd6f5415d8c781a5bc278e9b56a50b3b82f6a6e1a85f9b0ce *third_party/ltp/bin/1/wait403.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid01.elf.gz.sha256 ================================================ 63c02350568536aceb56fce92f4785183db1b698616bac201ea30463def428c2 *third_party/ltp/bin/1/waitpid01.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid02.elf.gz.sha256 ================================================ 0af42f79a8ddcdc100b7d3a1653026fd2a6ba5af7d7a93db83c7f9f5d2788345 *third_party/ltp/bin/1/waitpid02.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid03.elf.gz.sha256 ================================================ dc62dd2dd6e618e6db288c378c9e48a6d1e8ec1c75c4b6971842706020311c21 *third_party/ltp/bin/1/waitpid03.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid06.elf.gz.sha256 ================================================ ce522b4946aa50508fb826f2c43c19e2253a60403ddd48ee5481cc551b0db979 *third_party/ltp/bin/1/waitpid06.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid07.elf.gz.sha256 ================================================ 0726074d264b78b63d59d943a6e2f8140a7f5fc332eda7335163e22e8f4584a3 *third_party/ltp/bin/1/waitpid07.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid08.elf.gz.sha256 ================================================ a027b9dd6e072d9cace6ad2a2b2f70d1f036a21a3baa7a0da34e40648cb0b65c *third_party/ltp/bin/1/waitpid08.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid09.elf.gz.sha256 ================================================ cd11d922727a8bdb73eb13ca19d71ab4e251a05ba5df73297fb8712ea599642b *third_party/ltp/bin/1/waitpid09.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid10.elf.gz.sha256 ================================================ 39f654111445c5d08a8a205acd25e8e0553e2790829ff3e34ba9a1bac94a44e1 *third_party/ltp/bin/1/waitpid10.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid11.elf.gz.sha256 ================================================ 962b495403cb0eca3a7ceac0d2c0e5b98622fd8c25344095736dd78a88b96df4 *third_party/ltp/bin/1/waitpid11.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid12.elf.gz.sha256 ================================================ 8632012d4eccae4ee8b8f32fe180de7c4e042f1bd488956fc139b0508386cff7 *third_party/ltp/bin/1/waitpid12.elf.gz ================================================ FILE: third_party/ltp/bin/1/waitpid13.elf.gz.sha256 ================================================ 73c1f5c1fa00177ca1c36aa9a98917e3295aee8099e6ef705f5a78d3a654565c *third_party/ltp/bin/1/waitpid13.elf.gz ================================================ FILE: third_party/ltp/bin/1/write01.elf.gz.sha256 ================================================ 2b59ab58f387f49ba98c510b5b94f303b8eb85282789f967e27bd5f82a16e78b *third_party/ltp/bin/1/write01.elf.gz ================================================ FILE: third_party/ltp/bin/1/write02.elf.gz.sha256 ================================================ 30452c744031eb9f5af8d7f0b4d1ef6c7103bc2e3e97632a2944fac389364d89 *third_party/ltp/bin/1/write02.elf.gz ================================================ FILE: third_party/ltp/bin/1/write04.elf.gz.sha256 ================================================ 3fdf2c8db8d4f93101c269043971f85791499cde0b4045d904c75a6a61b9986b *third_party/ltp/bin/1/write04.elf.gz ================================================ FILE: third_party/ltp/bin/1/write06.elf.gz.sha256 ================================================ 1ce321b4356d0c97da68c527d33fe3fe5a016e19f6041d68aebb14c645ca98a3 *third_party/ltp/bin/1/write06.elf.gz ================================================ FILE: third_party/ltp/bin/1/writev02.elf.gz.sha256 ================================================ ee155830ea50363e414d7bd0fde857637a415ab453a6693bd6d43ff7485cca1b *third_party/ltp/bin/1/writev02.elf.gz ================================================ FILE: third_party/ltp/bin/1/writev05.elf.gz.sha256 ================================================ ebb0fb7e020d038f8a288b51392f41b4f4f6b75d1f2fb6878bfda4f26b468f78 *third_party/ltp/bin/1/writev05.elf.gz ================================================ FILE: third_party/ltp/bin/1/writev06.elf.gz.sha256 ================================================ 3a2b1c281c5a211a334e1893ed84b721d6ff0c22994af2707283ab06d5a9d797 *third_party/ltp/bin/1/writev06.elf.gz ================================================ FILE: third_party/ltp/bin/2/access02.elf.gz.sha256 ================================================ 9368875704e12392ac53261299b3181f9c76474ef875f0b590f2e21d30901091 *third_party/ltp/bin/2/access02.elf.gz ================================================ FILE: third_party/ltp/bin/2/bind02.elf.gz.sha256 ================================================ 3620839d1d64a2c5f8dee342d22d438517cde0971ccfe7616ebd9c8cfaec078d *third_party/ltp/bin/2/bind02.elf.gz ================================================ FILE: third_party/ltp/bin/2/brk01.elf.gz.sha256 ================================================ c5afb56b324941ce049354500b293467f1c0cd6dc1d886864b9462371ce11432 *third_party/ltp/bin/2/brk01.elf.gz ================================================ FILE: third_party/ltp/bin/2/brk02.elf.gz.sha256 ================================================ fe429b657f1e8a65c40d566fca8da086cd0de2fdf59a4ac6b2f34d8d4d2141a6 *third_party/ltp/bin/2/brk02.elf.gz ================================================ FILE: third_party/ltp/bin/2/chdir04.elf.gz.sha256 ================================================ 7cdba32b464fe8c16494e08b18487481a5bb15e4c6448379e649bf42a96cc4c5 *third_party/ltp/bin/2/chdir04.elf.gz ================================================ FILE: third_party/ltp/bin/2/connect01.elf.gz.sha256 ================================================ 50d584df7e614760d7ebc22f6eed06eb7c7e932aa478da24ffeb2bcda782f213 *third_party/ltp/bin/2/connect01.elf.gz ================================================ FILE: third_party/ltp/bin/2/dup03.elf.gz.sha256 ================================================ 691a3caf3fd9ab1d7dfa4d032101aa40302c63df6a324db8b8f6f93b1e000a0c *third_party/ltp/bin/2/dup03.elf.gz ================================================ FILE: third_party/ltp/bin/2/dup06.elf.gz.sha256 ================================================ f489b9f96d25a3d2d10734d19935d98ee16ae735ef57825a3dc2135087483755 *third_party/ltp/bin/2/dup06.elf.gz ================================================ FILE: third_party/ltp/bin/2/dup205.elf.gz.sha256 ================================================ 8efa5bfc032f063cffdb5cd1d010c13f434bd29dd641db124b475857ca0dc650 *third_party/ltp/bin/2/dup205.elf.gz ================================================ FILE: third_party/ltp/bin/2/futex_wait03.elf.gz.sha256 ================================================ c1daf4bad52772eee5d0e83bd882573ce70989116e8a8da894f5a223712de654 *third_party/ltp/bin/2/futex_wait03.elf.gz ================================================ FILE: third_party/ltp/bin/2/futimesat01.elf.gz.sha256 ================================================ 17515a80781ce556b2e91f6b040d71adbcec9708d83cc8136e1c84c4476d6b79 *third_party/ltp/bin/2/futimesat01.elf.gz ================================================ FILE: third_party/ltp/bin/2/getdents02.elf.gz.sha256 ================================================ fe3a9277a16b094082957b75258d839c0da8b4cae56a4b7bd07f9205b252bd0d *third_party/ltp/bin/2/getdents02.elf.gz ================================================ FILE: third_party/ltp/bin/2/getrandom01.elf.gz.sha256 ================================================ 002976a6e49c9e73a57541353b25e5e0efe57ab99bd9e806263021e24a75a568 *third_party/ltp/bin/2/getrandom01.elf.gz ================================================ FILE: third_party/ltp/bin/2/getrandom04.elf.gz.sha256 ================================================ 66dd65f3346d021d27bda351de70b91bff80d59ac443f7060748d531df3bbbcf *third_party/ltp/bin/2/getrandom04.elf.gz ================================================ FILE: third_party/ltp/bin/2/hackbench.elf.gz.sha256 ================================================ 5f3061485393f0dac27de43f169f9b4be2ddee3cc278d1eff1dce152c0103baf *third_party/ltp/bin/2/hackbench.elf.gz ================================================ FILE: third_party/ltp/bin/2/mmap2.elf.gz.sha256 ================================================ f3b2d9ad3f7e8b6e90db1aa716e64ec97a6aa611242df33e5913fe354d0455a9 *third_party/ltp/bin/2/mmap2.elf.gz ================================================ FILE: third_party/ltp/bin/2/open02.elf.gz.sha256 ================================================ 8ade9edd57d039fe51bc4400ffbc7a545d247e909d2eb6d209c40a381f312899 *third_party/ltp/bin/2/open02.elf.gz ================================================ FILE: third_party/ltp/bin/2/open07.elf.gz.sha256 ================================================ bc8eb692b8ae633d1f768fa01c66be26c4bc16d931a3ed386a993ef7c4ab1db6 *third_party/ltp/bin/2/open07.elf.gz ================================================ FILE: third_party/ltp/bin/2/open08.elf.gz.sha256 ================================================ 132514ae5966874cf4c3855000ed1f3cbc1ca10861401a154c7d2303d641a41e *third_party/ltp/bin/2/open08.elf.gz ================================================ FILE: third_party/ltp/bin/2/open10.elf.gz.sha256 ================================================ 0b6b4a340ba9d9eed842712a8afe0ffea1e282be92163c7936bbee1f30e2bc57 *third_party/ltp/bin/2/open10.elf.gz ================================================ FILE: third_party/ltp/bin/2/openat01.elf.gz.sha256 ================================================ 2c0dd12a7a46a991509023eeb0332fd223cabfc7051dea9158b536925acf47dd *third_party/ltp/bin/2/openat01.elf.gz ================================================ FILE: third_party/ltp/bin/2/openfile.elf.gz.sha256 ================================================ 3ef52015346a4945909f8859ee182416dea977061b6592f55cf6fbcd2cc366c1 *third_party/ltp/bin/2/openfile.elf.gz ================================================ FILE: third_party/ltp/bin/2/pwrite01.elf.gz.sha256 ================================================ 8ad3c8196adf1f467185fb430a9409caecd7fb6f08ce0a178fca0deff1d20b61 *third_party/ltp/bin/2/pwrite01.elf.gz ================================================ FILE: third_party/ltp/bin/2/read02.elf.gz.sha256 ================================================ d1db0f7229f63bedc50dd43820031f407aed5c0cb694a780a3492aad7db3929f *third_party/ltp/bin/2/read02.elf.gz ================================================ FILE: third_party/ltp/bin/2/readlink03.elf.gz.sha256 ================================================ 02a8f7686cb1e184aa813be5b64bba08faa5e38dff334972ceb9ed63a5481b16 *third_party/ltp/bin/2/readlink03.elf.gz ================================================ FILE: third_party/ltp/bin/2/readlinkat01.elf.gz.sha256 ================================================ 02156788bd1c7a088bfc422a08d061c1ce67328b1ce0d853d13f740e09f3572b *third_party/ltp/bin/2/readlinkat01.elf.gz ================================================ FILE: third_party/ltp/bin/2/readlinkat02.elf.gz.sha256 ================================================ 18a5054b08bc84f925b8c47549b70881b0c5c24b361ac1b79168d5633f69f59f *third_party/ltp/bin/2/readlinkat02.elf.gz ================================================ FILE: third_party/ltp/bin/2/readv02.elf.gz.sha256 ================================================ ba52249f2f407d692f89859e4e5eb8715dde683094b775bbe973089b2d6b4d8d *third_party/ltp/bin/2/readv02.elf.gz ================================================ FILE: third_party/ltp/bin/2/realpath01.elf.gz.sha256 ================================================ b7656c9575ad27a75af02c9dd52894d8aa60a6f1fb4339751ebfb501ad8e62d2 *third_party/ltp/bin/2/realpath01.elf.gz ================================================ FILE: third_party/ltp/bin/2/recvfrom01.elf.gz.sha256 ================================================ 11ed12c8a25c2256dc1257e7d7ac62698e46576c021dd586b8b6c444e6836e43 *third_party/ltp/bin/2/recvfrom01.elf.gz ================================================ FILE: third_party/ltp/bin/2/recvmmsg01.elf.gz.sha256 ================================================ 86e8cf3758da39ba9dace496ecc052318bf91e7dbd69ababfe9dbceea1b8c4f7 *third_party/ltp/bin/2/recvmmsg01.elf.gz ================================================ FILE: third_party/ltp/bin/2/rt_sigaction02.elf.gz.sha256 ================================================ f0ab09ac7c784043389f72f290760f3fa241f73dd4c0efbbae53ec59be9baff3 *third_party/ltp/bin/2/rt_sigaction02.elf.gz ================================================ FILE: third_party/ltp/bin/2/rt_sigaction03.elf.gz.sha256 ================================================ 74f3e359bab69e5d0da50f949dc6a6a46a7cb6fcb3cee6bd9648c961dcdd3198 *third_party/ltp/bin/2/rt_sigaction03.elf.gz ================================================ FILE: third_party/ltp/bin/2/rt_sigprocmask02.elf.gz.sha256 ================================================ 579f1357990ddc7d78c151715104d026a8bcbe55c28e4d214e24e3d333f3d367 *third_party/ltp/bin/2/rt_sigprocmask02.elf.gz ================================================ FILE: third_party/ltp/bin/2/sched_yield01.elf.gz.sha256 ================================================ aca8190fb3366054fd6322b1eb186aea9ac325f86bcb7a34392813d29b46edac *third_party/ltp/bin/2/sched_yield01.elf.gz ================================================ FILE: third_party/ltp/bin/2/select01.elf.gz.sha256 ================================================ 8fa811cc572cc9bedcdb97da5395dee06fca33f52b52e8aae83744d47ea0343c *third_party/ltp/bin/2/select01.elf.gz ================================================ FILE: third_party/ltp/bin/2/select02.elf.gz.sha256 ================================================ 3975aa51447b1fe8e69015564ab6cfc7afd781e16322e0e60af10c16d0a1ca1a *third_party/ltp/bin/2/select02.elf.gz ================================================ FILE: third_party/ltp/bin/2/select04.elf.gz.sha256 ================================================ 9dfdeb0fd1a0a22dd0bc8f259ca54bc169f5809311547a90c45584f764b532dd *third_party/ltp/bin/2/select04.elf.gz ================================================ FILE: third_party/ltp/bin/2/send01.elf.gz.sha256 ================================================ 9d475bd6f436a877585f14fb58e62ce1afd22d808dfbd7f3d9db90679f0bcaeb *third_party/ltp/bin/2/send01.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile02.elf.gz.sha256 ================================================ 40478041a2d0c43ce106fbbe7385d04f911c52e384c80bf4c2f4cbcf2dbed4b0 *third_party/ltp/bin/2/sendfile02.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile03.elf.gz.sha256 ================================================ 1fa8abcd91ce4c3eb83b0bcf52ab463c405f3aa15cf9e7ea1350984047e5cd4a *third_party/ltp/bin/2/sendfile03.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile04.elf.gz.sha256 ================================================ d1a6ee7b75606789424ada66e18502fb0e92f0ebe72379334e3d5d9c90e7bd18 *third_party/ltp/bin/2/sendfile04.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile05.elf.gz.sha256 ================================================ 99c8bbc1bbdbf4f1d84860be2bd6f494d8e05ed6cf7902e471796ac958e1082b *third_party/ltp/bin/2/sendfile05.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile06.elf.gz.sha256 ================================================ bc09d9799121255f7bc3b557f159812b823ea42f34a6656c3bb33078d110897d *third_party/ltp/bin/2/sendfile06.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile07.elf.gz.sha256 ================================================ f2d8a64bd6694ce9925915c6adac1351971158652f2e22b615e02d3d61354d8f *third_party/ltp/bin/2/sendfile07.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile08.elf.gz.sha256 ================================================ 807d230350273ecaa427e4cdf7ca480a8f66c5af0947592d88aa29a94e49b427 *third_party/ltp/bin/2/sendfile08.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendfile09.elf.gz.sha256 ================================================ 88a3924ed1b9a5e7280d1e1c00bc669ee4df0dbe61628714c245d0a8126811c4 *third_party/ltp/bin/2/sendfile09.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendmmsg01.elf.gz.sha256 ================================================ 2cbba35b579b7fc29ba99e34cbfa919412360b9d485c510210fe9699dccdc729 *third_party/ltp/bin/2/sendmmsg01.elf.gz ================================================ FILE: third_party/ltp/bin/2/sendmmsg02.elf.gz.sha256 ================================================ 80f0012930e97cc8be9adeb53adf56e0246b98c401fdcc4d822bd54ccda076fb *third_party/ltp/bin/2/sendmmsg02.elf.gz ================================================ FILE: third_party/ltp/bin/2/sigaction01.elf.gz.sha256 ================================================ 3bc6239ece267972ea0e5509cae5650987c5bc886cb3afd6cb0225de5440eb94 *third_party/ltp/bin/2/sigaction01.elf.gz ================================================ FILE: third_party/ltp/bin/2/sigsuspend01.elf.gz.sha256 ================================================ f8a745528bef9159e15d7a625343ff2f86a97ab3d140be9d450ce597c16c5332 *third_party/ltp/bin/2/sigsuspend01.elf.gz ================================================ FILE: third_party/ltp/bin/2/socket01.elf.gz.sha256 ================================================ 401c551efc12b285571672dd3546a338f29dd3e35dc45059174518b7cc71a1d2 *third_party/ltp/bin/2/socket01.elf.gz ================================================ FILE: third_party/ltp/bin/2/socketpair01.elf.gz.sha256 ================================================ 7ba8a0d26d27a48e60b47e1f5af1620dc9ee9d32d8908d464e566fdb9ddadcc2 *third_party/ltp/bin/2/socketpair01.elf.gz ================================================ FILE: third_party/ltp/bin/2/stat03.elf.gz.sha256 ================================================ 8cb9128d2db2bcbb657a52878b24aeb6461f2c9120756761db0606a1bb873c73 *third_party/ltp/bin/2/stat03.elf.gz ================================================ FILE: third_party/ltp/bin/2/symlink05.elf.gz.sha256 ================================================ 357bc07ee6171331803990fbb63de629e184327f3155d63217f7a57e10c69f91 *third_party/ltp/bin/2/symlink05.elf.gz ================================================ FILE: third_party/ltp/bin/2/unlink07.elf.gz.sha256 ================================================ dc753d4a97f412901e87959ba35b1b49dbda73f4b47b694a8c645d73b6338774 *third_party/ltp/bin/2/unlink07.elf.gz ================================================ FILE: third_party/ltp/bin/2/unlinkat01.elf.gz.sha256 ================================================ c20bf0468e220a227186d3af685e1a049ea954ff078c558201af1418dd1dec5c *third_party/ltp/bin/2/unlinkat01.elf.gz ================================================ FILE: third_party/ltp/bin/2/waitpid04.elf.gz.sha256 ================================================ a3acaf72bb54f2f62dc107b933d7a7890cbdf122d882e7f050ff2a6526c1a1a6 *third_party/ltp/bin/2/waitpid04.elf.gz ================================================ FILE: third_party/ltp/bin/2/write03.elf.gz.sha256 ================================================ 31563d37978d8bdca450a5871b0919725e44b36385ec09d2a0a2d41417d6e410 *third_party/ltp/bin/2/write03.elf.gz ================================================ FILE: third_party/ltp/bin/2/write05.elf.gz.sha256 ================================================ 60c1271e3bcc8edd41db7be66784353963b7f39378d7ee8eb9c61c1debe6d268 *third_party/ltp/bin/2/write05.elf.gz ================================================ FILE: third_party/ltp/bin/2/writetest.elf.gz.sha256 ================================================ 66c8fe0246cff55b991dfa99cfe4dbf79496c150668f6a4b2824471ab9d017f7 *third_party/ltp/bin/2/writetest.elf.gz ================================================ FILE: third_party/ltp/bin/2/writev01.elf.gz.sha256 ================================================ 8a4c9747e04aca4c344a7a6355999e6f588407df0c76cd2a84ca96febd60a189 *third_party/ltp/bin/2/writev01.elf.gz ================================================ FILE: third_party/ltp/bin/2/writev07.elf.gz.sha256 ================================================ 685d5ca289154099710d50f6b3a5a41bb1dd6315e871549ec2fa2fda5b91d879 *third_party/ltp/bin/2/writev07.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll-ltp.elf.gz.sha256 ================================================ b585b40b3b0d2516c6cf7d20d11bf4a3ac89a60a1f660e0920d0a657bc7510a8 *third_party/ltp/bin/3/epoll-ltp.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_create01.elf.gz.sha256 ================================================ 3dc54ebcac58ea6376cec89ffaafba02edfdcbe6380764f481418379a6cebe31 *third_party/ltp/bin/3/epoll_create01.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_create02.elf.gz.sha256 ================================================ be269790557a320c38fbb3f5db1f9c50c09824e9d09729a3fa669574efc26418 *third_party/ltp/bin/3/epoll_create02.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_create1_01.elf.gz.sha256 ================================================ 29dc5e388dd33896370086a10f520b4dfb4f88f73fb6c5181dd9866e8458a2e1 *third_party/ltp/bin/3/epoll_create1_01.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_create1_02.elf.gz.sha256 ================================================ 81d077f43a02e073db04718997766a014729361e55dcbad61f37af777222f3fa *third_party/ltp/bin/3/epoll_create1_02.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_ctl01.elf.gz.sha256 ================================================ 559d2a2f969402510130212f9c9dc88d48ce55efc653eb155c15399dd5aa8915 *third_party/ltp/bin/3/epoll_ctl01.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_ctl02.elf.gz.sha256 ================================================ 288f7d07c7218c3c03893eeb1e32b9e514aeea8ca52dd78d2ff3450f5d6d61bb *third_party/ltp/bin/3/epoll_ctl02.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_ctl03.elf.gz.sha256 ================================================ 479bfe2e44cfc44c6476d0c895d0c12f723fd5e1c442e4c6e32769305a5a25b4 *third_party/ltp/bin/3/epoll_ctl03.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_ctl04.elf.gz.sha256 ================================================ 93fe3b4cf72cccf453c272645fd989e9fb75f5ae8ac5cdf82323b1f54a42b509 *third_party/ltp/bin/3/epoll_ctl04.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_ctl05.elf.gz.sha256 ================================================ 26d4923505f83f373f5191cd69f6117ebfeb82ec74648a2ea78ef1d91995f836 *third_party/ltp/bin/3/epoll_ctl05.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_pwait01.elf.gz.sha256 ================================================ 0774cf71a8f19ca4395be5e0f2fa605982f724c4d4ea1e077bdeacdaf242ec7a *third_party/ltp/bin/3/epoll_pwait01.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_pwait02.elf.gz.sha256 ================================================ 2b5ca980fbb6976f3565d832dad4ee6f522586889f1aeb67cf428d2e3e690762 *third_party/ltp/bin/3/epoll_pwait02.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_pwait03.elf.gz.sha256 ================================================ 7d11233252271fa946876419342ca1f49645325b69bfb245cd425886cf8b5f8f *third_party/ltp/bin/3/epoll_pwait03.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_pwait04.elf.gz.sha256 ================================================ c5e5d91950a6662c0f58399c3a5a7ef0713dcdf704368fda88f753e726e63368 *third_party/ltp/bin/3/epoll_pwait04.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_pwait05.elf.gz.sha256 ================================================ 631bb578c78cfd4428d4c26af02b245913ab0de5504d9a312e9b9a5312009eb6 *third_party/ltp/bin/3/epoll_pwait05.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_wait01.elf.gz.sha256 ================================================ b6dc4ee9817420327f4b9ccd9e252f57d91f337b4eec00531de1b8c0191ede7b *third_party/ltp/bin/3/epoll_wait01.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_wait02.elf.gz.sha256 ================================================ 7bc827e67a98e6371e632f5466cf04d5d5648f8d9e132fe2d4df27bb7eea1e97 *third_party/ltp/bin/3/epoll_wait02.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_wait03.elf.gz.sha256 ================================================ 9efa76c18b6fd754ad37ca27372fc65edafd7bf9cecd29edadab73d500763400 *third_party/ltp/bin/3/epoll_wait03.elf.gz ================================================ FILE: third_party/ltp/bin/3/epoll_wait04.elf.gz.sha256 ================================================ 5498ea4a38b6e02e842b0b30f95e50f80245d07690155fd78513a8d2c7d76255 *third_party/ltp/bin/3/epoll_wait04.elf.gz ================================================ FILE: third_party/ltp/bin/3/recvmmsg01.elf.gz.sha256 ================================================ 572131b6aa05185c680c0a5cf6d27ac147f8986f0fc265535e3a8e11da508e44 *third_party/ltp/bin/3/recvmmsg01.elf.gz ================================================ FILE: third_party/ltp/bin/3/sendmsg01.elf.gz.sha256 ================================================ 5e2565d2591a38baf96cf616f69cc1237740c25b200c9cdaa9c8dedfc6a104e7 *third_party/ltp/bin/3/sendmsg01.elf.gz ================================================ FILE: third_party/ltp/cpuinfo ================================================ processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 0 cpu cores : 8 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 1 cpu cores : 8 apicid : 2 initial apicid : 2 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 2 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 2 cpu cores : 8 apicid : 4 initial apicid : 4 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 3 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 3 cpu cores : 8 apicid : 6 initial apicid : 6 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 4 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 4 cpu cores : 8 apicid : 8 initial apicid : 8 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 5 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 4798.388 cache size : 16384 KB physical id : 0 siblings : 16 core id : 5 cpu cores : 8 apicid : 10 initial apicid : 10 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 6 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 4731.353 cache size : 16384 KB physical id : 0 siblings : 16 core id : 6 cpu cores : 8 apicid : 12 initial apicid : 12 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 7 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 7 cpu cores : 8 apicid : 14 initial apicid : 14 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 8 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 0 cpu cores : 8 apicid : 1 initial apicid : 1 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 9 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 1 cpu cores : 8 apicid : 3 initial apicid : 3 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 10 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 2 cpu cores : 8 apicid : 5 initial apicid : 5 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 11 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 3 cpu cores : 8 apicid : 7 initial apicid : 7 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 12 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 4904.594 cache size : 16384 KB physical id : 0 siblings : 16 core id : 4 cpu cores : 8 apicid : 9 initial apicid : 9 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 13 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 5 cpu cores : 8 apicid : 11 initial apicid : 11 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 14 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 3100.000 cache size : 16384 KB physical id : 0 siblings : 16 core id : 6 cpu cores : 8 apicid : 13 initial apicid : 13 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: processor : 15 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i9-9900 CPU @ 3.10GHz stepping : 13 microcode : 0xca cpu MHz : 4904.135 cache size : 16384 KB physical id : 0 siblings : 16 core id : 7 cpu cores : 8 apicid : 15 initial apicid : 15 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities vmx flags : vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs taa itlb_multihit srbds mmio_stale_data retbleed eibrs_pbrsb bogomips : 6202.33 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: ================================================ FILE: third_party/ltp/deploy-ltp ================================================ #!/bin/sh set -ex # e.g. deploy-ltp chmod01 T=/mnt/videos/website/justine.lol/ltp/bin L=/opt/ltp/testcases/bin/ V=1 mkdir -p $T/$V for f; do if [ ! -f $L/$f ]; then echo "not found: $L/$f" >&2 exit 1 fi cp $L/$f $T/$V/${f##*/}.elf rm -f $T/$V/${f##*/}.elf.gz gzip $T/$V/${f##*/}.elf sha256sum -b $T/$V/${f##*/}.elf.gz >$T/$V/${f##*/}.elf.gz.sha256 mkdir -p ~/blink/third_party/ltp/bin/$V cp $T/$V/${f##*/}.elf.gz.sha256 ~/blink/third_party/ltp/bin/$V/${f##*/}.elf.gz.sha256 sed -i -e 's!/mnt/videos/website/justine.lol/ltp/bin!third_party/ltp/bin!' \ ~/blink/third_party/ltp/bin/$V/${f##*/}.elf.gz.sha256 done syncweb ssh debian gsutil -m -h Cache-Control:public,max-age=31536000 cp -r -a public-read \ /mnt/videos/website/justine.lol/ltp/bin/$V/${f##*/}.elf.gz \ gs://justine/ltp/bin/$V/ ================================================ FILE: third_party/ltp/ltp.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ .PRECIOUS: third_party/ltp/%.gz third_party/ltp/%.gz: third_party/ltp/%.gz.sha256 o/tool/sha256sum curl -so $@ https://justine.storage.googleapis.com/ltp/$(subst third_party/ltp/,,$@) o/tool/sha256sum -c $< .PRECIOUS: third_party/ltp/bin/%.elf third_party/ltp/bin/%.elf: third_party/ltp/bin/%.elf.gz gzip -dc <$< >$@ chmod +x $@ o/$(MODE)/third_party/ltp/bin/%.elf.ok: \ third_party/ltp/bin/%.elf \ o/lib/ld-musl-x86_64.so.1 \ o/$(MODE)/blink/blink \ o/proc/cpuinfo \ o/proc/meminfo @mkdir -p $(@D) o/$(MODE)/blink/blink $< $(LTP_ARGS) @touch $@ o/$(MODE)/third_party/ltp/bin/1/growfiles.elf.ok: private LTP_ARGS = -f "$(TMPDIR)/gf" .PRECIOUS: o/proc/% o/proc/%: third_party/ltp/% @mkdir -p $(@D) cp -f $< $@ chmod +x $@ LTP_TESTS = \ o/$(MODE)/third_party/ltp/bin/2/hackbench.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/accept01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/accept4_01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/alarm03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/alarm05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/alarm06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/alarm07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/atof01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/bind01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/bind03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/brk02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/chown01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/clock_getres01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/clock_nanosleep04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/close01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/close02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/close_range02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/confstr01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/creat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/creat03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/dup03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup201.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup202.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup203.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup204.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/dup205.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup206.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup207.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup3_01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/dup3_02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/exit01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/exit02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/exit_group01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchdir01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchdir02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchmod01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchown01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchownat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl01_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl02_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl03_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl04_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl08.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl08_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl09_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl10.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl10_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl11.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl11_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl14.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl14_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl15.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl15_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl16.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl16_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl17.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl17_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl19.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl19_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl20.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl20_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl21.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl21_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl22.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl22_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl27.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl27_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl28.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl28_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl29.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fcntl29_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fdatasync01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fdatasync02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/flock01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/flock02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/flock03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/flock04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/flock06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork08.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork10.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork11.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fsync03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/ftruncate01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/ftruncate01_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/ftruncate03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/ftruncate03_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/futex_wait01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/futex_wait04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/futex_wake01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getcwd02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getcwd03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getdents01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/getdents02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getdomainname01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getegid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getegid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/geteuid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/geteuid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getgid03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/gethostname01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getitimer01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getpagesize01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getpgid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getpgrp01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getpid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getppid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getpriority02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/getrandom01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getrandom02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getrandom03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getrlimit02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getrusage01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getsid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/gettid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/gettimeofday01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getuid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/growfiles.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/hackbench.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/in6_01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/inode01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/kill06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/kill08.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/kill09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/link02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/link03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/link05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/listen01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/llseek01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/llseek02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/llseek03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/locktests.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/lseek01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/lseek02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/lseek07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap08.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap19.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmapstress04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mprotect02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mprotect03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/msync01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/msync02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/munmap01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/munmap02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/munmap03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/nanosleep02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fstat02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/open03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/open06.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/open07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/open09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe08.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe10.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe11.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pipe13.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/poll01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pread01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pread01_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pread02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pread02_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/preadv01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/preadv01_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pselect02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pselect02_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pselect03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pselect03_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/pwrite01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwrite01_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwrite02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwrite02_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwrite03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwrite03_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwrite04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwrite04_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwritev01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pwritev01_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/read01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/read02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/read03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/read04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/readdir01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/readv01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/recvmsg02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/rmdir01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/sbrk02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/select01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/select04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/set_robust_list01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/set_tid_address01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setpgid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setpgid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setpgrp01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setpgrp02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setsid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sigaction01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/sigaction02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/rt_sigaction02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/rt_sigaction03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/sigaltstack01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/sigaltstack02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/signal01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/signal02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/signal04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/signal06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/sigprocmask01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/rt_sigprocmask02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sigsuspend01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/socket01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/socket02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/socketpair01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/socketpair02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/stat02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/stat02_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/symlink01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/symlink02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/symlink04.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/symlink05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/symlinkat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/tkill01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/tkill02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/truncate02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/truncate02_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/unlink05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/wait01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/wait02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/wait401.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/wait402.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/wait403.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid03.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/waitpid04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid08.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid10.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid11.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid12.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/waitpid13.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/write01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/write02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/write03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/write04.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/write05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/write06.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/writetest.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/writev01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/writev02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/writev05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/writev06.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/writev07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/sendto01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setitimer02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/unlinkat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/futimesat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/unlink07.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/send01.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/sendmsg01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sched_yield01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/readlinkat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/readlinkat02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/readv02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/realpath01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/openat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/recvmmsg01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendmmsg01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendmmsg02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/recvfrom01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile03.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile04.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile05.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile06.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile07.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile08.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/sendfile09.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/openfile.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/connect01.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/chdir04.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll-ltp.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_create01.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_create02.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_create1_01.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_create1_02.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_ctl01.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_ctl02.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_ctl03.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_ctl04.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_ctl05.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_pwait01.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_pwait02.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_pwait04.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_pwait05.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_wait01.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_wait03.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_wait04.elf.ok ifneq ($(HOST_SYSTEM), FreeBSD) # These tests make the system get wrekt. LTP_TESTS += \ o/$(MODE)/third_party/ltp/bin/1/pause02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/creat05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fork09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/inode02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/open04.elf.ok endif ifneq ($(HOST_SYSTEM), FreeBSD) # Something weird about the sticky bit. LTP_TESTS += o/$(MODE)/third_party/ltp/bin/1/open01.elf.ok endif ifneq ($(HOST_SYSTEM), FreeBSD) # The FreeBSD manual states "The maximum number of seconds allowed for # it_interval and it_value in setitimer() is 100000000", but this test # needs the platform to support values like INT_MAX. LTP_TESTS += o/$(MODE)/third_party/ltp/bin/1/alarm02.elf.ok endif ifneq ($(HOST_SYSTEM), FreeBSD) # This passes but complains about an EXDEV errno mismatch (possibly with # procfs) and therefore would be expensive and/or tricky to polyfill. LTP_TESTS += o/$(MODE)/third_party/ltp/bin/1/linkat01.elf.ok endif # These tests won't pass unless Linux-specific rlimits are present, # RLIMIT_LOCKS, RLIMIT_MSGQUEUE, RLIMIT_RTTIME, etc. ifneq ($(HOST_SYSTEM), FreeBSD) LTP_TESTS += \ o/$(MODE)/third_party/ltp/bin/1/getrlimit01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getrlimit03.elf.ok endif # These tests require procfs which currently isn't simulated. ifneq ($(HOST_SYSTEM), FreeBSD) LTP_TESTS += \ o/$(MODE)/third_party/ltp/bin/1/clock_gettime04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/futex_wait02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/futex_wait03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/nanosleep04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getpgid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getppid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getuid03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getsid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getpid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pause03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pause01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fsync02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap12.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/kill03.elf.ok endif ifeq ($(shell id -u), 0) LTP_TESTS += \ o/$(MODE)/third_party/ltp/bin/1/setegid02.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/open08.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/open10.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/stat03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/rename09.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/access01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/access02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/access03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/autogroup01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/chmod07.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/chown02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/chown05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/clock_gettime01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchmod02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchmod04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchown02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/fchown05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/futex_wake04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getgid01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getgroups03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getrandom04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/hugemmap06.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mkdir05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap10.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap11.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/nice04.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/open02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/open11.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/open14.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/openat03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/readlink01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setgroups01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setgroups02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setgroups04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setpriority02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setrlimit03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/setsockopt03.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/stat01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/stat01_64.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/futex_wait05.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/poll02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/unlink08.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/bind02.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_pwait03.elf.ok \ o/$(MODE)/third_party/ltp/bin/3/epoll_wait02.elf.ok endif # TODO: Cygwin doesn't properly raise an EACCES errno. ifneq ($(HOST_OS), Cygwin) LTP_TESTS += o/$(MODE)/third_party/ltp/bin/2/readlink03.elf.ok endif ifneq ($(HOST_OS), Cygwin) # partial failure only on cygwin # chmod01.c:50: TFAIL: stat(testfile) mode=0000 # chmod01.c:50: TFAIL: stat(testdir_1) mode=0000 # chmod01.c:50: TFAIL: stat(testdir_1) mode=0777 # chmod01.c:50: TFAIL: stat(testdir_1) mode=4777 LTP_TESTS += o/$(MODE)/third_party/ltp/bin/1/chmod01.elf.ok endif ################################################################################ # MEDIUM TESTS LTP_TESTS_MEDIUM = \ o/$(MODE)/third_party/ltp/bin/1/clock_nanosleep02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/getcwd04.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/gettimeofday02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/kill02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap-corruption01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmap001.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/mmapstress01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/nanosleep01.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/rename14.elf.ok \ o/$(MODE)/third_party/ltp/bin/2/mmap2.elf.ok ifeq ($(shell id -u), 0) LTP_TESTS_MEDIUM += \ o/$(MODE)/third_party/ltp/bin/2/select02.elf.ok \ o/$(MODE)/third_party/ltp/bin/1/pty06.elf.ok endif ################################################################################ o/$(MODE)/third_party/ltp: $(LTP_TESTS) @mkdir -p $(@D) @touch $@ o/$(MODE)/third_party/ltp/medium: $(LTP_TESTS_MEDIUM) @mkdir -p $(@D) @touch $@ ================================================ FILE: third_party/ltp/meminfo ================================================ MemTotal: 1147256 kB MemFree: 819664 kB MemAvailable: 814180 kB Buffers: 2108 kB Cached: 128936 kB SwapCached: 0 kB Active: 105240 kB Inactive: 76048 kB Active(anon): 56492 kB Inactive(anon): 16656 kB Active(file): 48748 kB Inactive(file): 59392 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 1888252 kB SwapFree: 1888252 kB Dirty: 24 kB Writeback: 0 kB AnonPages: 50252 kB Mapped: 25052 kB Shmem: 22904 kB Slab: 61316 kB SReclaimable: 24848 kB SUnreclaim: 36468 kB KernelStack: 3984 kB PageTables: 3712 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 2461880 kB Committed_AS: 279548 kB VmallocTotal: 34359738367 kB VmallocUsed: 179168 kB VmallocChunk: 34359310332 kB Percpu: 22528 kB HardwareCorrupted: 0 kB AnonHugePages: 12288 kB CmaTotal: 0 kB CmaFree: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 65408 kB DirectMap2M: 1138688 kB DirectMap1G: 0 kB ================================================ FILE: third_party/musl/README.md ================================================ # Musl Libc This folder downloads prebuilt binaries from the [Musl Libc](https://www.musl-libc.org/) project. ## Changes None. ## Build The binaries were compiled on Alpine Linux using: ``` export CC="cc -fno-omit-frame-pointer -Wl,-z,common-page-size=65536,-z,max-page-size=65536" ./configure --enable-debug make -j16 ``` ================================================ FILE: third_party/musl/lib/1/ld-musl-x86_64.so.1.gz.sha256 ================================================ 07fa95292e7c861e1d99ab28572a8aadc76b745c1db6c64c60990c114f6af82c *third_party/musl/lib/1/ld-musl-x86_64.so.1.gz ================================================ FILE: third_party/musl/musl.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ .PRECIOUS: third_party/musl/%.gz third_party/musl/%.gz: third_party/musl/%.gz.sha256 o/tool/sha256sum curl -so $@ https://justine.storage.googleapis.com/musl/$(subst third_party/musl/,,$@) o/tool/sha256sum -c $< .PRECIOUS: third_party/musl/% third_party/musl/%: third_party/musl/%.gz gzip -dc <$< >$@ chmod +x $@ o/lib/ld-musl-x86_64.so.1: third_party/musl/lib/1/ld-musl-x86_64.so.1 @mkdir -p $(@D) cp -f $< $@ chmod +x $@ ================================================ FILE: third_party/qemu/4/qemu-aarch64.gz.sha256 ================================================ 92cee22c128bc356818fac36ef9a43c7548d2aeea1e25cc3b9f5b269abd2f5f6 *third_party/qemu/4/qemu-aarch64.gz ================================================ FILE: third_party/qemu/4/qemu-aarch64_be.gz.sha256 ================================================ f0e89d14992bdfb6b1913459e673198dc087875ac0622208b12073662fa9f0c2 *third_party/qemu/4/qemu-aarch64_be.gz ================================================ FILE: third_party/qemu/4/qemu-alpha.gz.sha256 ================================================ 1f9e6eccd09e12b3aa8b5c1a1947603e3ba8d1c4599dde34dceb1215895925fb *third_party/qemu/4/qemu-alpha.gz ================================================ FILE: third_party/qemu/4/qemu-arm.gz.sha256 ================================================ c08bc8e7a2569392b0eabffe521615d0e755fdd3bb48b8b6716afb8fd8b0588d *third_party/qemu/4/qemu-arm.gz ================================================ FILE: third_party/qemu/4/qemu-armeb.gz.sha256 ================================================ 6c1214789f287855d67957999ca3a61a7f25b4d0a27b948a98751803942d3ae4 *third_party/qemu/4/qemu-armeb.gz ================================================ FILE: third_party/qemu/4/qemu-cris.gz.sha256 ================================================ 14e789b9ee15415ab034d5bda25db3085d9327b703811a86a96cb7f779469ebb *third_party/qemu/4/qemu-cris.gz ================================================ FILE: third_party/qemu/4/qemu-hexagon.gz.sha256 ================================================ e7031aaf2889cc52d96a00d817bc87aea8db5b2df9b25b7d1ca8bc3e504d0fe5 *third_party/qemu/4/qemu-hexagon.gz ================================================ FILE: third_party/qemu/4/qemu-hppa.gz.sha256 ================================================ a1396a75e75c795d4fb72a003be466a8d126e7e2cca6aabaf3c26a4a347e4d31 *third_party/qemu/4/qemu-hppa.gz ================================================ FILE: third_party/qemu/4/qemu-i386.gz.sha256 ================================================ 1ad12c52b2bbb2ae336283b2292f5cda2551b778ce2f63b949fde85e17771b9c *third_party/qemu/4/qemu-i386.gz ================================================ FILE: third_party/qemu/4/qemu-loongarch64.gz.sha256 ================================================ b78f0e6f5df9b10d2d13984bb20162e4ee9841e1c7543f7316a803abdb201768 *third_party/qemu/4/qemu-loongarch64.gz ================================================ FILE: third_party/qemu/4/qemu-m68k.gz.sha256 ================================================ bdffa53e495e77171d84b439fa38cd240c0f1295e1ac8e526a2b7a464494570a *third_party/qemu/4/qemu-m68k.gz ================================================ FILE: third_party/qemu/4/qemu-microblaze.gz.sha256 ================================================ aacce2d5e6f8a515522135f533ad57b3383d9aff25235fc263beedfb6e45f7ff *third_party/qemu/4/qemu-microblaze.gz ================================================ FILE: third_party/qemu/4/qemu-microblazeel.gz.sha256 ================================================ d26748f4a8e7e23e93e47156f70c4e26e6187f741a0aeba438263411bb52b4c1 *third_party/qemu/4/qemu-microblazeel.gz ================================================ FILE: third_party/qemu/4/qemu-mips.gz.sha256 ================================================ 145e87b5b2ca717cfa91dbb320e2306d3f3b8c10407eb07c2e402d835d0d176a *third_party/qemu/4/qemu-mips.gz ================================================ FILE: third_party/qemu/4/qemu-mips64.gz.sha256 ================================================ dc148b117b080182439caa827afed9d89bdc706ec59cc55536efe86aeafe9669 *third_party/qemu/4/qemu-mips64.gz ================================================ FILE: third_party/qemu/4/qemu-mips64el.gz.sha256 ================================================ 041d9399696f4d9c1a8a5799c21d686f178a85437054d6c0f5e0c1e345983a67 *third_party/qemu/4/qemu-mips64el.gz ================================================ FILE: third_party/qemu/4/qemu-mipsel.gz.sha256 ================================================ 0f25801c9dc3262aee3b1d95bdf213bd45cf6af1ec469998a0dc4a524d0d73ae *third_party/qemu/4/qemu-mipsel.gz ================================================ FILE: third_party/qemu/4/qemu-mipsn32.gz.sha256 ================================================ 5624c6a18eaab48c261173a711f999570ad6cddea42e5fcf520138f9c66acc12 *third_party/qemu/4/qemu-mipsn32.gz ================================================ FILE: third_party/qemu/4/qemu-mipsn32el.gz.sha256 ================================================ 39032a5efc0167dc4166e8d335ecac27e413f1b6d4dbfa0d2c998eb3cc81693c *third_party/qemu/4/qemu-mipsn32el.gz ================================================ FILE: third_party/qemu/4/qemu-nios2.gz.sha256 ================================================ 278d87635b3a39cf01e67d7926451c85f911010c45e40b0685b07704adbe4c5f *third_party/qemu/4/qemu-nios2.gz ================================================ FILE: third_party/qemu/4/qemu-or1k.gz.sha256 ================================================ a31f7252474f64f2a803cf228945378909ed707b68bba01a0c8176beaafbe3c5 *third_party/qemu/4/qemu-or1k.gz ================================================ FILE: third_party/qemu/4/qemu-ppc.gz.sha256 ================================================ 0621e2d7577bf784cff0b44bb6158e957c3ab8143931e9275b8c7ff18fdd67a5 *third_party/qemu/4/qemu-ppc.gz ================================================ FILE: third_party/qemu/4/qemu-ppc64.gz.sha256 ================================================ 33e734b5054209fcd48a6d18ade6d6c6a59a245e1414dbaef5043a374f9eb8f1 *third_party/qemu/4/qemu-ppc64.gz ================================================ FILE: third_party/qemu/4/qemu-ppc64le.gz.sha256 ================================================ 49e2dd1c85af1a12ff6a73b5564c7616ee114b589db495433ed4d2799de43718 *third_party/qemu/4/qemu-ppc64le.gz ================================================ FILE: third_party/qemu/4/qemu-riscv32.gz.sha256 ================================================ f31f3c5dd3c086a3e432252904af3e874dcb2c61f65ac4b8dc010b041d8c58a1 *third_party/qemu/4/qemu-riscv32.gz ================================================ FILE: third_party/qemu/4/qemu-riscv64.gz.sha256 ================================================ f1731902f27677d74a137c0c4a50de6e4c96490b170c9a3a080ee59a38979be6 *third_party/qemu/4/qemu-riscv64.gz ================================================ FILE: third_party/qemu/4/qemu-s390x.gz.sha256 ================================================ ce7cde2b19d7a23800468fa94f1ce4290102f77480b1b152e47c26d5f5a08091 *third_party/qemu/4/qemu-s390x.gz ================================================ FILE: third_party/qemu/4/qemu-sh4.gz.sha256 ================================================ ea0606d9c4ab96261c47626134b56067658c973c25237c764a541232cafc6383 *third_party/qemu/4/qemu-sh4.gz ================================================ FILE: third_party/qemu/4/qemu-sh4eb.gz.sha256 ================================================ eef7d69fbd8bf8e022086d6ffba07186e37bf35e2f5ad414c31b6a83960f5bad *third_party/qemu/4/qemu-sh4eb.gz ================================================ FILE: third_party/qemu/4/qemu-sparc.gz.sha256 ================================================ 20e3b8f70bc9385ff97fdcb4b8bfb082aab34457869104da6d2068f5fcd69d6f *third_party/qemu/4/qemu-sparc.gz ================================================ FILE: third_party/qemu/4/qemu-sparc32plus.gz.sha256 ================================================ fb8902e14cf0ead708fb3d0abc9114a84f597b0fb05f393e4db65b11b4ef4135 *third_party/qemu/4/qemu-sparc32plus.gz ================================================ FILE: third_party/qemu/4/qemu-sparc64.gz.sha256 ================================================ 7c596da70fd4483b0eb3e08bc10e9ee6774fe9b59399396fca4bce1a686576de *third_party/qemu/4/qemu-sparc64.gz ================================================ FILE: third_party/qemu/4/qemu-x86_64.gz.sha256 ================================================ 1b1d3b50eeb85a98fcf7a06a15306e5d1d3f90ddfa64251051f4a92bc166ddeb *third_party/qemu/4/qemu-x86_64.gz ================================================ FILE: third_party/qemu/4/qemu-xtensa.gz.sha256 ================================================ b8ebc4457e25a52338193294903a7ff759aeebea9eb258eb9b33c926a13d395c *third_party/qemu/4/qemu-xtensa.gz ================================================ FILE: third_party/qemu/4/qemu-xtensaeb.gz.sha256 ================================================ 4ec6a562fc4eea1f0452fce83277fdbfb4c817f4a0aaa1ecc2804f1907e8dc72 *third_party/qemu/4/qemu-xtensaeb.gz ================================================ FILE: third_party/qemu/README.md ================================================ # Qemu This folder contains prebuilt binaries of Qemu 7.2.0-rc4. Qemu is similar to Blink except it's bigger and it's been around longer. As such, we've found Qemu enormously useful as a testing tool for Blink. That's because Qemu is able to emulate multiple hardware architectures from the comfort of an x86-64 workstation. That helps us quickly verify our tinier, nimbler emulator for x86-64 binaries will work once shipped! ## Local Changes None. ## License Unlike Bilnk with observes the ISC license, Qemu is licensed GPL. You have the freedom to obtain the Qemu source code from the internet and reproduce our build process using the following instructions. ## Build Process These binaries were compiled as follows: ``` cd ~/vendor/qemu-7.2.0-rc4 ./configure --disable-system --enable-linux-user --disable-bsd-user --static \ --prefix=/opt/qemu-static-best --disable-stack-protector --enable-seccomp \ --disable-selinux --disable-glusterfs --disable-debug-info --cc=/usr/bin/gcc \ --extra-cflags='-fno-stack-protector' \ --extra-ldflags='-Wl,-z,norelro -Wl,-z,noseparate-code -Wl,-z,common-page-size=65536 -Wl,-z,max-page-size=65536' && make -j5 && make install ``` On the following system: ``` $ uname -a Linux debian 6.1.0-rc4+ #2 SMP PREEMPT_DYNAMIC Thu Nov 10 20:53:21 PST 2022 x86_64 GNU/Linux ``` ## Deploy Process Our operations team used the following script to make these binaries freely available on Google Cloud Storage. ```sh #!/bin/sh set -ex T=/mnt/videos/website/justine.lol/qemu Q=/opt/qemu-static-best V=4 mkdir -p $T/$V mkdir -p ~/blink/third_party/qemu/$V for f in $(ls -1 $Q/bin | grep -v -- -system- | grep -v daemon); do cp $Q/bin/$f $T/$V/${f##*/} strip $T/$V/${f##*/} rm -f $T/$V/${f##*/}.gz gzip $T/$V/${f##*/} sha256sum -b $T/$V/${f##*/}.gz >$T/$V/${f##*/}.gz.sha256 cp $T/$V/${f##*/}.gz.sha256 ~/blink/third_party/qemu/$V/${f##*/}.gz.sha256 sed -i -e 's!/mnt/videos/website/justine.lol!third_party!' \ ~/blink/third_party/qemu/$V/${f##*/}.gz.sha256 ssh debian gsutil -m -h Cache-Control:public,max-age=31536000 cp -r -a public-read \ /mnt/videos/website/justine.lol/qemu/$V/${f##*/}.gz \ gs://justine/qemu/$V/ done rm -rf /mnt/videos/website/justine.lol/qemu ``` ================================================ FILE: third_party/qemu/qemu.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ third_party/qemu/%.gz: third_party/qemu/%.gz.sha256 o/tool/sha256sum curl -so $@ https://justine.storage.googleapis.com/qemu/$(subst third_party/qemu/,,$@) o/tool/sha256sum -c $< o/third_party/qemu/4/qemu-x86_64: third_party/qemu/4/qemu-x86_64.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-aarch64: third_party/qemu/4/qemu-aarch64.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-aarch64_be: third_party/qemu/4/qemu-aarch64_be.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-arm: third_party/qemu/4/qemu-arm.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-i386: third_party/qemu/4/qemu-i386.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-m68k: third_party/qemu/4/qemu-m68k.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-microblaze: third_party/qemu/4/qemu-microblaze.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-riscv64: third_party/qemu/4/qemu-riscv64.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-mips: third_party/qemu/4/qemu-mips.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-mipsel: third_party/qemu/4/qemu-mipsel.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-mips64: third_party/qemu/4/qemu-mips64.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-mips64el: third_party/qemu/4/qemu-mips64el.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-ppc: third_party/qemu/4/qemu-ppc.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-ppc64: third_party/qemu/4/qemu-ppc64.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-ppc64le: third_party/qemu/4/qemu-ppc64le.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-s390x: third_party/qemu/4/qemu-s390x.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-alpha: third_party/qemu/4/qemu-alpha.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-armeb: third_party/qemu/4/qemu-armeb.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-cris: third_party/qemu/4/qemu-cris.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-hexagon: third_party/qemu/4/qemu-hexagon.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-hppa: third_party/qemu/4/qemu-hppa.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-loongarch64: third_party/qemu/4/qemu-loongarch64.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-microblazeel: third_party/qemu/4/qemu-microblazeel.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-mipsn32: third_party/qemu/4/qemu-mipsn32.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-mipsn32el: third_party/qemu/4/qemu-mipsn32el.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-nios2: third_party/qemu/4/qemu-nios2.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-or1k: third_party/qemu/4/qemu-or1k.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-riscv32: third_party/qemu/4/qemu-riscv32.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-sh4: third_party/qemu/4/qemu-sh4.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-sh4eb: third_party/qemu/4/qemu-sh4eb.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-sparc: third_party/qemu/4/qemu-sparc.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-sparc32plus: third_party/qemu/4/qemu-sparc32plus.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-sparc64: third_party/qemu/4/qemu-sparc64.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-xtensa: third_party/qemu/4/qemu-xtensa.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ o/third_party/qemu/4/qemu-xtensaeb: third_party/qemu/4/qemu-xtensaeb.gz @mkdir -p $(@D) gzip -dc <$< >$@ chmod +x $@ ================================================ FILE: third_party/sectorlisp/LICENSE ================================================ Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2021 Alain Greppin Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: third_party/sectorlisp/README.md ================================================ # Running SectorLISP in Blinkenlights [SectorLISP](https://justine.lol/sectorlisp2/) is an tiniest garbage collected programming environment in the world. It's written as an i8086 BIOS program that's compatible with the original IBM PC. You can run SectorLISP in Blink, by passing the `-r` (REAL MODE) flag. ## Running SectorLISP If you build Blink, then you can use the binaries provided for your convenience in this folder. ```sh make -j8 o//blink # easy mode o//blink/blinkenlights -r third_party/sectorlisp/sectorlisp-friendly.bin # professional mode o//blink/blinkenlights -r third_party/sectorlisp/sectorlisp.bin ``` Then press `c` to continue. The teletypewriter should become highlighted, which means it's waiting for keystrokes. ## LISP Hello World You can then type in code like the following, which interns an atom: ```lisp (QUOTE HI) ``` The above code followed by the `ENTER` key will display: ```lisp HI ``` For the purposes of readability in this tutorial, the above workflow will be described as follows: ```lisp >> (QUOTE HI) HI ``` ## Keyboard Control Once you've pressed `c` (CONTINUE) the program TTY takes over control. You can drop back into the debugger by pressing `CTRL-C`. For example, if you want to exit Blink entirely while using SectorLISP, you'd press `CTRL-C` (INTERRUPT) followed by `q` (QUIT). One thing you may have noticed, is that SectorLISP's interning algorithm is slow. You can speed up or slow down execution at any time, by pressing `CTRL-C` (INTERRUPT) and, once in debugger mode, use `CTRL-T` (TURBO) or `ALT-T` (SLOWMO) as many times as desired. Then, execution may be resumed by `c` (CONTINUE) which hands control back over to the SectorLISP program. An alternative to pressing `c` (CONTINUE) is to press `s` (STEP). This will allow you to go instruction by instruction. Be careful if you run into an `INT` instruction, since `INT $0x16` for example, is your BIOS keyboard service. In stepping mode, Blink will read one keystroke, and then drop back into debugger control mode. ## LISP Data Structures Here's an example of how you can build data structures: ```lisp > (CONS (QUOTE A) (QUOTE B)) (A∙B) ``` ## Recursive Functions SectorLISP is purely expressional. It also doesn't have macros, which are what make the modern LISP syntax most people are used to possible. You instead need to write LISP the old fashioned way, as it is written in John McCarthy's original paper. Here's an example of a recursive function which finds the first atom in the tree `((A) B C)`, which is `A`. ```lisp >> ((LAMBDA (FF X) (FF X)) (QUOTE (LAMBDA (X) (COND ((ATOM X) X) ((QUOTE T) (FF (CAR X)))))) (QUOTE ((A) B C))) A ``` The friendly version of SectorLISP makes it possible to break giant expressions like the above into smaller pieces. For example, the actual function from the S-expression above could be defined as follows: ```lisp (DEFINE FF . (LAMBDA (X) (COND ((ATOM X) X) ((QUOTE T) (FF (CAR X)))))) ``` The friendly version also has the advantage of not exhibiting undefined behavior upon mistyped keystrokes! ## On Real Mode We call real mode "real" because it puts your virtual machine in a mode that simulates non-virtualized memory ops. This adds a certain level of fun when programming, because it makes things so much simpler than long mode, which mandates that all memory operations be indirected through a 4-level radix trie. The i8086 is still able to virtualize memory using segment registers: - `%cs` (CODE SEGMENT) - `%ds` (DATA SEGMENT) - `%ss` (STACK SEGMENT) - `%es` (EXTRA SEGMENT) BIOS programs are loaded to the address 0x7c00. What SectorLISP does is it sets all the segments to the load address, which effectively redefines `NULL` to be equal to the base of the program image. ================================================ FILE: third_party/xterm.js/LICENSE ================================================ xterm.js was downloaded from: https://cdn.jsdelivr.net/npm/xterm@5.1.0/lib/xterm.min.js https://cdn.jsdelivr.net/npm/xterm@5.1.0/css/xterm.css Copyright (c) 2017-2019, The xterm.js authors (https://github.com/xtermjs/xterm.js) Copyright (c) 2014-2016, SourceLair Private Company (https://www.sourcelair.com) Copyright (c) 2012-2013, Christopher Jeffrey (https://github.com/chjj/) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/xterm.js/xterm.css ================================================ /** * Copyright (c) 2014 The xterm.js authors. All rights reserved. * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) * https://github.com/chjj/term.js * @license MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Originally forked from (with the author's permission): * Fabrice Bellard's javascript vt100 for jslinux: * http://bellard.org/jslinux/ * Copyright (c) 2011 Fabrice Bellard * The original design remains. The terminal itself * has been extended to include xterm CSI codes, among * other features. */ /** * Default styles for xterm.js */ .xterm { cursor: text; position: relative; user-select: none; -ms-user-select: none; -webkit-user-select: none; } .xterm.focus, .xterm:focus { outline: none; } .xterm .xterm-helpers { position: absolute; top: 0; /** * The z-index of the helpers must be higher than the canvases in order for * IMEs to appear on top. */ z-index: 5; } .xterm .xterm-helper-textarea { padding: 0; border: 0; margin: 0; /* Move textarea out of the screen to the far left, so that the cursor is not visible */ position: absolute; opacity: 0; left: -9999em; top: 0; width: 0; height: 0; z-index: -5; /** Prevent wrapping so the IME appears against the textarea at the correct position */ white-space: nowrap; overflow: hidden; resize: none; } .xterm .composition-view { /* TODO: Composition position got messed up somewhere */ background: #000; color: #FFF; display: none; position: absolute; white-space: nowrap; z-index: 1; } .xterm .composition-view.active { display: block; } .xterm .xterm-viewport { /* On OS X this is required in order for the scroll bar to appear fully opaque */ background-color: #000; overflow-y: scroll; cursor: default; position: absolute; right: 0; left: 0; top: 0; bottom: 0; } .xterm .xterm-screen { position: relative; } .xterm .xterm-screen canvas { position: absolute; left: 0; top: 0; } .xterm .xterm-scroll-area { visibility: hidden; } .xterm-char-measure-element { display: inline-block; visibility: hidden; position: absolute; top: 0; left: -9999em; line-height: normal; } .xterm.enable-mouse-events { /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ cursor: default; } .xterm.xterm-cursor-pointer, .xterm .xterm-cursor-pointer { cursor: pointer; } .xterm.column-select.focus { /* Column selection mode */ cursor: crosshair; } .xterm .xterm-accessibility, .xterm .xterm-message { position: absolute; left: 0; top: 0; bottom: 0; z-index: 10; color: transparent; } .xterm .live-region { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; } .xterm-dim { opacity: 0.5; } .xterm-underline-1 { text-decoration: underline; } .xterm-underline-2 { text-decoration: double underline; } .xterm-underline-3 { text-decoration: wavy underline; } .xterm-underline-4 { text-decoration: dotted underline; } .xterm-underline-5 { text-decoration: dashed underline; } .xterm-strikethrough { text-decoration: line-through; } .xterm-screen .xterm-decoration-container .xterm-decoration { z-index: 6; position: absolute; } .xterm-decoration-overview-ruler { z-index: 7; position: absolute; top: 0; right: 0; pointer-events: none; } .xterm-decoration-top { z-index: 2; position: relative; } ================================================ FILE: tool/config/clock_settime.c ================================================ #include int main(int argc, char *argv[]) { clock_settime(-1, 0); } ================================================ FILE: tool/config/config.mk ================================================ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #── vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi ──────────────────────┘ o/$(MODE)/tool/config/%.com: tool/config/%.c @mkdir -p $(@D) $(CC) -o $@ $< $(LDLIBS) o/$(MODE)/tool/config/zlib.com: private LDLIBS += -lz o/$(MODE)/tool/config/libunwind.com: private LDLIBS += -lunwind -lucontext -llzma ================================================ FILE: tool/config/dev_urandom.c ================================================ // tests for non-buggy sysctl(KERN_ARND) #include #include #include #ifdef _WIN32 #error posix /dev does not exist on windows. #endif /* * assuming the system is working correctly there's a 1 in * 235716896562095165800448 chance this check should flake */ #define BYTES 9 #define TRIES 16 static ssize_t GetRandom(unsigned char *p, size_t n) { int fd; ssize_t rc; if ((fd = open("/dev/urandom", O_RDONLY)) == -1) return -1; rc = read(fd, p, n); close(fd); return rc; } int main(int argc, char *argv[]) { size_t i, j; int haszero, fails = 0; unsigned char x[BYTES]; for (i = 0; i < TRIES; ++i) { memset(x, 0, sizeof(x)); if (GetRandom(x, sizeof(x)) != sizeof(x)) return 1; for (haszero = j = 0; j < BYTES; ++j) { if (!x[j]) haszero = 1; } if (haszero) ++fails; } if (fails < TRIES) { return 0; } else { return 2; } } ================================================ FILE: tool/config/dup3.c ================================================ // checks for dup3() system call #include #include #include #include int main(int argc, char *argv[]) { char path[128]; snprintf(path, 128, "/tmp/blink.config.%d", getpid()); if (open(path, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600) != 3) return 1; if (fcntl(3, F_GETFD) != FD_CLOEXEC) return 2; if (dup3(3, 4, 0) != 4) return 3; if (fcntl(4, F_GETFD) != 0) return 4; if (dup3(3, 4, O_CLOEXEC) != 4) return 5; if (fcntl(4, F_GETFD) != FD_CLOEXEC) return 6; if (unlink(path)) return 7; return 0; } ================================================ FILE: tool/config/epoll_pwait1.c ================================================ // Checks for RHEL6+ level epoll() support. #include int main(int argc, char *argv[]) { epoll_create(-1); epoll_create1(-1); epoll_pwait(-1, 0, 0, 0, 0); return 0; } ================================================ FILE: tool/config/epoll_pwait2.c ================================================ #include int main(int argc, char *argv[]) { epoll_pwait2(-1, 0, 0, 0, 0); return 0; } ================================================ FILE: tool/config/f_getown_ex.c ================================================ // checks if F_GETOWN_EX will break build #include int main(int argc, char *argv[]) { unsigned long magnums[] = { F_GETOWN_EX, // F_SETOWN_EX, // F_OWNER_TID, // F_OWNER_PID, // F_OWNER_PGRP, // }; (void)magnums; } ================================================ FILE: tool/config/fdatasync.c ================================================ // checks for fdatasync() system call #include #include #include #include int main(int argc, char *argv[]) { char path[128]; int fd, rc; snprintf(path, 128, "/tmp/blink.config.%d", getpid()); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd == -1) return 1; rc = fdatasync(fd); if (rc == -1) return 2; if (rc) return 3; close(fd); if (unlink(path)) return 4; return 0; } ================================================ FILE: tool/config/fexecve.c ================================================ // checks for fexecve #include int main(int argc, char *argv[]) { char *const args[] = {0}; char *const envs[] = {0}; fexecve(0, args, envs); return 0; } ================================================ FILE: tool/config/fork.c ================================================ // checks if fork() works #include #include int main(int argc, char *argv[]) { int ws; pid_t pid, rc; pid = fork(); if (pid == -1) return 1; if (!pid) _exit(42); rc = wait(&ws); if (rc == -1) return 2; if (rc != pid) return 3; if (!WIFEXITED(ws)) return 4; if (WEXITSTATUS(ws) != 42) return 5; return 0; } ================================================ FILE: tool/config/getdomainname.c ================================================ // checks if getdomainname() works #include #include int main(int argc, char *argv[]) { int rc; char buf[256]; memset(buf, 0, 256); rc = getdomainname(buf, 256); if (rc == -1) return 1; // library failed if (rc) return 2; // library broken if (strlen(buf) > 255) return 4; // library broken return 0; } ================================================ FILE: tool/config/getentropy.c ================================================ // checks for getentropy() with bsd style include #include /* * assuming the system is working correctly there's a 1 in * 235716896562095165800448 chance this check should flake */ #define BYTES 9 #define TRIES 16 int main(int argc, char *argv[]) { int rc; size_t i, j; int haszero, fails = 0; for (i = 0; i < TRIES; ++i) { unsigned char x[BYTES] = {0}; rc = getentropy(x, sizeof(x)); if (rc == -1) return 1; if (rc) return 2; for (haszero = j = 0; j < BYTES; ++j) { if (!x[j]) haszero = 1; } if (haszero) ++fails; } if (fails < TRIES) { return 0; } else { return 3; } } ================================================ FILE: tool/config/getrandom.c ================================================ // tests for getrandom() #include /* * assuming the system is working correctly there's a 1 in * 235716896562095165800448 chance this check should flake */ #define BYTES 9 #define TRIES 16 int main(int argc, char *argv[]) { ssize_t rc; size_t i, j; int haszero, fails = 0; for (i = 0; i < TRIES; ++i) { unsigned char x[BYTES] = {0}; rc = getrandom(x, BYTES, 0); if (rc == -1) return 1; if (rc != BYTES) return 2; for (haszero = j = 0; j < BYTES; ++j) { if (!x[j]) haszero = 1; } if (haszero) ++fails; } if (fails < TRIES) { return 0; } else { return 3; } } ================================================ FILE: tool/config/kern_arnd.c ================================================ // tests for non-buggy sysctl(KERN_ARND) #include // order sometimes matters #include #include #include /* * "On FreeBSD old implementations returned longs, newer versions * support variable sizes up to 256 byte. The code below would not work * properly when the sysctl returns long and we want to request * something not a multiple of longs, which should never be the case." * -Quoth the OpenSSL source code * * "On NetBSD before 4.0 KERN_ARND was an alias for KERN_URND, and only * filled in an int, leaving the rest uninitialized. Since NetBSD 4.0 it * returns a variable number of bytes with the current version * supporting up to 256 bytes." -Quoth the OpenSSL source code. */ /* * assuming the system is working correctly there's a 1 in * 235716896562095165800448 chance this check should flake */ #define BYTES 9 #define TRIES 16 int main(int argc, char *argv[]) { int haszero; int fails = 0; size_t i, j, m; unsigned char x[BYTES]; int mib[2] = {CTL_KERN, KERN_ARND}; for (i = 0; i < TRIES; ++i) { memset(x, 0, sizeof(x)); m = sizeof(x); if (sysctl(mib, 2, &x, &m, 0, 0) == -1) return 1; if (m != sizeof(x)) return 2; for (haszero = j = 0; j < BYTES; ++j) { if (!x[j]) haszero = 1; } if (haszero) ++fails; } if (fails < TRIES) { return 0; } else { return 3; } } ================================================ FILE: tool/config/libunwind.c ================================================ // checks for libunwind backtrace support #define UNW_LOCAL_ONLY #ifdef __x86_64__ #include #else #include #endif #include #include #define APPEND(...) o += snprintf(b + o, n - o, __VA_ARGS__) const char *GetBacktrace(void) { static char b[2048]; int o = 0; char sym[256]; int n = sizeof(b); unw_cursor_t cursor; unw_context_t context; unw_word_t offset, pc; unw_getcontext(&context); unw_init_local(&cursor, &context); APPEND("backtrace"); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &pc); if (!pc) break; APPEND("\n\t%lx ", pc); if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { APPEND("%s+%ld", sym, offset); } else { APPEND(""); } } return b; } const char *MyApp(void) { return GetBacktrace(); } const char *(*MyAppPtr)(void) = MyApp; int main(int argc, char *argv[]) { const char *bt; bt = MyAppPtr(); if (!strstr(bt, "MyApp")) return 1; if (!strstr(bt, "main")) return 2; return 0; } ================================================ FILE: tool/config/lm.c ================================================ // checks that -lm won't break the build #include double three(void) { return 3; } double (*f)(void) = three; int main(int argc, char *argv[]) { if (pow(f(), f()) != 27.) return 1; return 0; } ================================================ FILE: tool/config/lrt.c ================================================ // checks that -lrt won't break the build #include int main(int argc, char *argv[]) { struct timespec ts; if (clock_getres(CLOCK_REALTIME, &ts)) return 1; if (clock_gettime(CLOCK_REALTIME, &ts)) return 1; return 0; } ================================================ FILE: tool/config/map_anonymous.c ================================================ // checks for MAP_ANONYMOUS feature #include #include int main(int argc, char *argv[]) { void *p; p = mmap(0, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) return 1; return 0; } ================================================ FILE: tool/config/map_shared.c ================================================ // checks if mmap(MAP_SHARED) works #include #include #include #include int main(int argc, char *argv[]) { FILE *f; void *map; int ws, *x; pid_t pid, rc; if (!(f = tmpfile())) return 1; if (ftruncate(fileno(f), sizeof(int))) return 2; map = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fileno(f), 0); if (map == MAP_FAILED) return 3; x = (int *)map; pid = fork(); if (pid == -1) return 4; if (!pid) { *x = 42; msync(map, sizeof(int), MS_INVALIDATE); _exit(0); } rc = wait(&ws); if (rc == -1) return 5; if (rc != pid) return 6; if (!WIFEXITED(ws)) return 7; if (WEXITSTATUS(ws)) return 8; if (*x != 42) return 9; return 0; } ================================================ FILE: tool/config/memccpy.c ================================================ // checks for memccpy() xsi extension #include int main(int argc, char *argv[]) { char buf[16]; if (memccpy(buf, "hi", '\0', sizeof(buf)) != buf + 3) return 1; if (strcmp(buf, "hi")) return 2; return 0; } ================================================ FILE: tool/config/mkfifo.c ================================================ // tests for mkfifo() support // e.g. not provided by cosmopolitan libc #include #include #include #include #include #include int main(int argc, char *argv[]) { char path[128]; snprintf(path, 128, "/tmp/blink.config.%d", getpid()); if (mkfifo(path, 0644)) return 2; if (unlink(path)) return 3; return 0; } ================================================ FILE: tool/config/mkfifoat.c ================================================ // tests for mkfifoat() support // not present on MacOS until 13+ c. 2022 #include #include #include #include #include #include int main(int argc, char *argv[]) { char path[128]; snprintf(path, 128, "/tmp/blink.config.%d", getpid()); if (mkfifoat(AT_FDCWD, path, 0644)) return 2; if (unlink(path)) return 3; return 0; } ================================================ FILE: tool/config/noop.c ================================================ // c program that does nothing int main() { return 0; } ================================================ FILE: tool/config/pipe2.c ================================================ // checks for pipe2() system call #include #include int main(int argc, char *argv[]) { int fds[2]; if (pipe2(fds, 0)) return 1; if (fcntl(fds[0], F_GETFD) != 0) return 2; if (fcntl(fds[1], F_GETFD) != 0) return 3; if (pipe2(fds, O_CLOEXEC)) return 4; if (fcntl(fds[0], F_GETFD) != FD_CLOEXEC) return 5; if (fcntl(fds[1], F_GETFD) != FD_CLOEXEC) return 6; return 0; } ================================================ FILE: tool/config/preadv.c ================================================ // tests for preadv() and pwritev() support // missing on MacOS (before 2020), Cygwin, Haiku, etc. #include #include int main(int argc, char *argv[]) { FILE *f; char x, y; struct iovec vx, vy; if (!(f = tmpfile())) return 1; x = 123; vx.iov_base = &x; vx.iov_len = 1; if (pwritev(fileno(f), &vx, 1, 5) != 1) return 2; vy.iov_base = &y; vy.iov_len = 1; if (preadv(fileno(f), &vy, 1, 5) != 1) return 3; if (y != 123) return 4; fclose(f); return 0; } ================================================ FILE: tool/config/pthread.c ================================================ // checks posix threads works #include void *Worker(void *arg) { return arg; } int main(int argc, char *argv[]) { pthread_t th; void *arg, *res; arg = (void *)argv; if (pthread_create(&th, 0, Worker, arg)) return 1; if (pthread_join(th, &res)) return 2; if (res != arg) return 3; return 0; } ================================================ FILE: tool/config/pthread_process_shared.c ================================================ // test for interprocess mutexes and condition variables // clang-format off #include #include #include #include #include #include int main(int argc, char *argv[]) { int ws; FILE *f; pid_t pid; pthread_condattr_t ca; pthread_mutexattr_t ma; struct Shared { atomic_int state; pthread_cond_t cond; pthread_mutex_t lock; } *s; if (!(f = tmpfile())) return 0; if (ftruncate(fileno(f), 4096)) return 1; if ((s = (struct Shared *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) return 2; if (pthread_condattr_init(&ca)) return 3; if (pthread_mutexattr_init(&ma)) return 4; if (pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED)) return 5; if (pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED)) return 6; if (pthread_cond_init(&s->cond, &ca)) return 7; if (pthread_mutex_init(&s->lock, &ma)) return 8; if (pthread_mutexattr_destroy(&ma)) return 9; if (pthread_condattr_destroy(&ca)) return 10; if ((pid = fork()) == -1) return 11; if (!pid) { alarm(2); if (pthread_mutex_lock(&s->lock)) return 12; s->state = 1; if (pthread_cond_wait(&s->cond, &s->lock)) return 13; if (pthread_mutex_unlock(&s->lock)) return 14; while (s->state != 2); if (pthread_mutex_lock(&s->lock)) return 15; if (pthread_cond_signal(&s->cond)) return 16; if (pthread_mutex_unlock(&s->lock)) return 17; _exit(0); } alarm(2); while (s->state != 1); if (pthread_mutex_lock(&s->lock)) return 18; if (pthread_cond_signal(&s->cond)) return 19; if (pthread_mutex_unlock(&s->lock)) return 20; if (pthread_mutex_lock(&s->lock)) return 21; s->state = 2; if (pthread_cond_wait(&s->cond, &s->lock)) return 22; if (pthread_mutex_unlock(&s->lock)) return 23; if (wait(&ws) != pid) return 24; if (!WIFEXITED(ws)) return 25; if (WEXITSTATUS(ws)) return 26; if (pthread_mutex_destroy(&s->lock)) return 27; if (pthread_cond_destroy(&s->cond)) return 28; return 0; } ================================================ FILE: tool/config/pthread_setcancelstate.c ================================================ // checks if pthread_setcancelstate is available and usable #include void *Worker(void *arg) { return arg; } int main(int argc, char *argv[]) { if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0)) return 1; if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0)) return 1; return 0; } ================================================ FILE: tool/config/realpath.c ================================================ // checks that realpath() won't break build #include #include int main(int argc, char *argv[]) { char path[PATH_MAX]; if (!realpath("/tmp", path)) return 1; return 0; } ================================================ FILE: tool/config/rtlgenrandom.c ================================================ // tests for RtlGenRandom() #include #include // Required for __MINGW64_VERSION_MAJOR, not using __MINGW32__ since old MinGW32 also defines it. See https://github.com/cpredef/predef/blob/master/Compilers.md#mingw-and-mingw-w64. #ifndef __MINGW64_VERSION_MAJOR #include #endif bool __stdcall SystemFunction036(void *, __LONG32); int main(int argc, char *argv[]) { long x = 0; if (!SystemFunction036(&x, sizeof(x))) return 1; if (!x) return 2; return 0; } ================================================ FILE: tool/config/sa_len.c ================================================ // checks for bsd style sockaddr length field #include int main(int argc, char *argv[]) { struct sockaddr sa; sa.sa_len = 1; (void)sa; return 0; } ================================================ FILE: tool/config/sched_getaffinity.c ================================================ // checks for sched_getaffinity() #include int main(int argc, char *argv[]) { int rc; cpu_set_t cs; CPU_ZERO(&cs); rc = sched_getaffinity(0, sizeof(cs), &cs); if (rc == -1) return 1; // system call failed if (rc) return 2; // libc wrapper broken if (!CPU_COUNT(&cs)) return 3; // system call broken return 0; } ================================================ FILE: tool/config/sched_h.c ================================================ // checks for sched.h header #include int main(int argc, char *argv[]) { return 0; } ================================================ FILE: tool/config/sched_yield.c ================================================ // checks for sched_yield() support #include int main(int argc, char *argv[]) { if (sched_yield()) return 1; return 0; } ================================================ FILE: tool/config/scm_credentials.c ================================================ // checks that SCM_CREDENTIALS won't break the build #include #include int main(int argc, char *argv[]) { struct ucred ucred; ucred.pid = SCM_CREDENTIALS; ucred.uid = SCM_CREDENTIALS; ucred.gid = SCM_CREDENTIALS; (void)ucred; return 0; } ================================================ FILE: tool/config/seekdir.c ================================================ // checks for telldir() and seekdir() support #include #include int main(int argc, char *argv[]) { DIR *d; long spot; char name[256]; struct dirent *e; if (!(d = opendir("/tmp"))) return 1; // read first entry, saving this position if ((spot = telldir(d)) == -1) return 2; if (!(e = readdir(d))) return 3; strcpy(name, e->d_name); // read second entry, ensuring it's different if (!(e = readdir(d))) return 4; if (!strcmp(name, e->d_name)) return 5; // read the first entry again, ensuring it's what we remember seekdir(d, spot); if (!(e = readdir(d))) return 6; if (strcmp(name, e->d_name)) return 7; return 0; } ================================================ FILE: tool/config/sendto_zero.c ================================================ // checks if sendto(0.0.0.0) will copy address from connect() #include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { pid_t pid; int rc, ws; socklen_t socklen; char buf[8] = {0}; struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; socklen = sizeof(addr); if (socket(AF_INET, SOCK_DGRAM, 0) != 3) return 1; if (bind(3, (struct sockaddr *)&addr, sizeof(addr))) return 2; if (getsockname(3, (struct sockaddr *)&addr, &socklen)) return 3; if ((pid = fork()) == -1) return 4; if (!pid) { alarm(5); if (read(3, buf, 8) != 2) _exit(5); if (strcmp(buf, "hi")) _exit(6); _exit(0); } if (close(3)) return 7; if (socket(AF_INET, SOCK_DGRAM, 0) != 3) return 8; if (connect(3, (struct sockaddr *)&addr, sizeof(addr))) return 9; addr.sin_addr.s_addr = 0; if (sendto(3, "hi", 2, 0, (struct sockaddr *)&addr, sizeof(addr)) != 2) { // OpenBSD 7.2 fails with EISCONN here. perror("sendto"); return 10; } if (wait(&ws) != pid) return 11; return WEXITSTATUS(ws); } ================================================ FILE: tool/config/setgroups.c ================================================ // checks setgroups() won't break build #include #include int main(int argc, char *argv[]) { (void)setgroups(0, 0); return 0; } ================================================ FILE: tool/config/setresuid.c ================================================ // checks that setresuid() won't break the build #include int main(int argc, char *argv[]) { int rc = setresuid(-1, -1, -1); // noop by definition if (rc == -1) return 1; // failed if (rc) return 2; // broken return 0; } ================================================ FILE: tool/config/setreuid.c ================================================ // checks that setreuid() won't break the build #include int main(int argc, char *argv[]) { int rc = setreuid(-1, -1); // noop by definition if (rc == -1) return 1; // failed if (rc) return 2; // broken return 0; } ================================================ FILE: tool/config/siocgifconf.c ================================================ // checks if we can enumerate network interfaces #include #include #include char buf[16384]; int main(int argc, char *argv[]) { int rc; struct ifreq *ifreq; struct ifconf ifconf; unsigned long magnums_we_care_about[] = { IFNAMSIZ, // SIOCGIFADDR, // SIOCGIFNETMASK, // SIOCGIFBRDADDR, // SIOCGIFDSTADDR, // }; ifconf.ifc_buf = buf; ifconf.ifc_len = sizeof(buf); socket(AF_INET, SOCK_DGRAM, 0); rc = ioctl(3, SIOCGIFCONF, &ifconf); if (rc) return 1; if (!ifconf.ifc_len) return 2; ifreq = ifconf.ifc_req; (void)ifreq; return 0; } ================================================ FILE: tool/config/sockatmark.c ================================================ // checks if sockatmark is available #include int main(int argc, char *argv[]) { int rc; socket(AF_INET, SOCK_STREAM, 0); if (sockatmark(3) == -1) return 1; return 0; } ================================================ FILE: tool/config/stdatomic.c ================================================ // checks for c11 atomics #include atomic_int x; int main(int argc, char *argv[]) { if (atomic_exchange_explicit(&x, 123, memory_order_relaxed) != 0) return 1; if (atomic_exchange_explicit(&x, 456, memory_order_relaxed) != 123) return 2; return 0; } ================================================ FILE: tool/config/strchrnul.c ================================================ // checks for strchrnul() support #include int main(int argc, char *argv[]) { char s[] = "abc"; if (strchrnul(s, 'a') != s) return 1; if (strchrnul(s, 'b') != s + 1) return 2; if (strchrnul(s, 'c') != s + 2) return 3; if (strchrnul(s, 'd') != s + 3) return 4; if (strchrnul(s, 'e') != s + 3) return 5; return 0; } ================================================ FILE: tool/config/struct_timezone.c ================================================ // checks if struct timezone is specified #include int main(int argc, char *argv[]) { struct timezone tz; tz.tz_minuteswest = 1; tz.tz_dsttime = 1; (void)tz; return 0; } ================================================ FILE: tool/config/sync.c ================================================ // check for sync() xsi extension #include void DontCallMeBro(void) { sync(); } int main(int argc, char *argv[]) { return 0; } ================================================ FILE: tool/config/sys_getentropy.c ================================================ // checks for getentropy() with apple style include #include /* * assuming the system is working correctly there's a 1 in * 235716896562095165800448 chance this check should flake */ #define BYTES 9 #define TRIES 16 int main(int argc, char *argv[]) { int rc; size_t i, j; int haszero, fails = 0; for (i = 0; i < TRIES; ++i) { unsigned char x[BYTES] = {0}; rc = getentropy(x, sizeof(x)); if (rc == -1) return 1; if (rc) return 2; for (haszero = j = 0; j < BYTES; ++j) { if (!x[j]) haszero = 1; } if (haszero) ++fails; } if (fails < TRIES) { return 0; } else { return 3; } } ================================================ FILE: tool/config/sys_getrandom.c ================================================ // tests for syscall(SYS_getrandom) #include #include /* * assuming the system is working correctly there's a 1 in * 235716896562095165800448 chance this check should flake */ #define BYTES 9 #define TRIES 16 int main(int argc, char *argv[]) { ssize_t rc; size_t i, j; int haszero, fails = 0; for (i = 0; i < TRIES; ++i) { unsigned char x[BYTES] = {0}; rc = syscall(SYS_getrandom, x, BYTES, 0); if (rc == -1) return 1; if (rc != BYTES) return 2; for (haszero = j = 0; j < BYTES; ++j) { if (!x[j]) haszero = 1; } if (haszero) ++fails; } if (fails < TRIES) { return 0; } else { return 3; } } ================================================ FILE: tool/config/sys_mount_h.c ================================================ #include // ordering matters on openbsd // checks for sys/mount.h header #include int main(int argc, char *argv[]) { return 0; } ================================================ FILE: tool/config/sysctl.c ================================================ // tests for bsd sysctl() system call #include // ordering sometimes matters #include #include int features_we_care_about[] = { CTL_HW, // CTL_KERN, // KERN_BOOTTIME, // HW_NCPU, // #ifdef HW_MEMSIZE HW_MEMSIZE, #else HW_PHYSMEM, #endif }; int main(int argc, char *argv[]) { struct timeval x; size_t n = sizeof(x); int mib[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(mib, 2, &x, &n, 0, 0) == -1) return 1; return 0; } ================================================ FILE: tool/config/sysinfo.c ================================================ // tests for linux sysinfo() system call #include int main(int argc, char *argv[]) { struct sysinfo si; if (sysinfo(&si)) return 1; return 0; } ================================================ FILE: tool/config/vasprintf.c ================================================ // checks for vasprintf() function // available in gnu/bsd/mac/cygwin #include #include #include #include char *xasprintf(const char *fmt, ...) { int rc; char *s; va_list va; va_start(va, fmt); rc = vasprintf(&s, fmt, va); va_end(va); if (rc == -1) exit(1); // vasprintf failed if (rc != strlen(s)) exit(2); // vasprintf broken return s; } int main(int argc, char *argv[]) { char *s; s = xasprintf("hello %d", 123); if (strcmp(s, "hello 123")) exit(3); free(s); return 0; } ================================================ FILE: tool/config/wait4.c ================================================ // checks if wait4() will break build #include #include #include int main(int argc, char *argv[]) { int ws; pid_t rc; struct rusage ru; rc = wait4(-1, &ws, -1, &ru); if (rc != (pid_t)-1) return 1; if (errno != EINVAL) return 2; return 0; } ================================================ FILE: tool/config/wcwidth.c ================================================ // checks for wcwidth() support #include int main(int argc, char *argv[]) { if (wcwidth(0) != 0) return 1; if (wcwidth(32) != 1) return 2; if (wcwidth(0x672c) != 2) return 3; return 0; } ================================================ FILE: tool/config/zlib.c ================================================ // checks if system provides a working zlib #include #include #include #define unassert(x) \ do { \ if (!(x)) { \ exit(__COUNTER__ + 1); \ } \ } while (0) void *Deflate(const void *data, unsigned size, unsigned *out_size) { void *res; uLong bound; z_stream zs = {0}; bound = compressBound(size); unassert(res = malloc(bound)); unassert(deflateInit2(&zs, 4, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) == Z_OK); zs.next_in = (z_const Bytef *)data; zs.avail_in = size; zs.avail_out = bound; zs.next_out = (Bytef *)res; unassert(deflate(&zs, Z_FINISH) == Z_STREAM_END); unassert(deflateEnd(&zs) == Z_OK); unassert(res = realloc(res, zs.total_out)); *out_size = zs.total_out; return res; } void Inflate(void *out, unsigned outsize, const void *in, unsigned insize) { z_stream zs; zs.next_in = (z_const Bytef *)in; zs.avail_in = insize; zs.total_in = insize; zs.next_out = (Bytef *)out; zs.avail_out = outsize; zs.total_out = outsize; zs.zalloc = Z_NULL; zs.zfree = Z_NULL; unassert(inflateInit2(&zs, -MAX_WBITS) == Z_OK); unassert(inflate(&zs, Z_FINISH) == Z_STREAM_END); unassert(inflateEnd(&zs) == Z_OK); } int main(int argc, char *argv[]) { char plain[64]; void *compressed; const char *golden; unsigned compressed_size; memset(plain, 0, sizeof(plain)); compressed = Deflate("hello world", 12, &compressed_size); Inflate(plain, sizeof(plain), compressed, compressed_size); unassert(!strcmp(plain, "hello world")); free(compressed); return 0; } ================================================ FILE: tool/dispatch.py ================================================ #!/usr/bin/env python3 import os import sys DISPATCH = '''\ /*000*/ OpAlubAdd, /*001*/ OpAluw, /*002*/ OpAlubFlipAdd, etc... '''.split('\n') COUNT = [0 for _ in range(0x500)] for arg in sys.argv[1:]: with open(arg) as f: for line in f: line = line.strip() if not line: continue count, op = line.split() count = int(count) op = int(op) COUNT[op] += count toto = sum(COUNT) S = [] for op in range(len(DISPATCH)): S.append((COUNT[op], op)) S.sort(reverse=True) RANK = {} for i, (_, op) in enumerate(S): RANK[op] = i + 1 REPORT = [] for op in range(len(DISPATCH)): if COUNT[op]: print("%-40s // #%-4d (%.6f%%)" % (DISPATCH[op], RANK[op], COUNT[op] / float(toto) * 100)) else: print("%-40s //" % (DISPATCH[op])) ================================================ FILE: tool/fastsize.sh ================================================ #!/bin/sh m=${1:-tiny} F=" o/$m/x86_64/blink/blink " make -j8 $F m=$m || exit for f in $F; do cp $f $f.strip done o/third_party/gcc/x86_64/bin/x86_64-linux-musl-strip o/$m/x86_64/blink/blink.strip for f in $F; do ls -hal $f.strip done ================================================ FILE: tool/flock.c ================================================ #include #include #include int main(int argc, char *argv[]) { if (argc != 3) return 1; if (strcmp(argv[1], "-x")) return 2; if (flock(atoi(argv[2]), LOCK_EX)) return 3; return 0; } ================================================ FILE: tool/release-cosmo.sh ================================================ #!/bin/sh m=tiny echo -n 'did you update blink/tunables.h and ape/ape.s? [n] ' read didit if [ "$didit" != "y" ]; then exit 1 fi set -ex ./configure make -j8 check # create the linux arm64 build make m=$m -j8 o/$m/aarch64/blink/blink o/third_party/gcc/aarch64/bin/aarch64-linux-musl-strip \ o/$m/aarch64/blink/blink gzip -c9 o/$m/aarch64/blink/blink \ >o/$m/aarch64/blink/blink-aarch64.gz cp o/$m/aarch64/blink/blink-aarch64.gz \ ~/cosmo/ape/blink-aarch64.gz # create the apple arm64 build rsync -avz --exclude=o \ --exclude='*.xz' \ --exclude='*.gz' \ --exclude='*.dbg' \ --exclude='*.com' \ --exclude='*.dbg' \ --exclude='*.elf' \ ~/blink silicon: ssh silicon cd blink \&\& \ /usr/local/bin/make m=$m -j8 o/$m/blink/blink \; \ /usr/local/bin/make m=$m -j8 o/$m/blink/blink \&\& \ strip o/$m/blink/blink \&\& \ gzip -c9 o/$m/blink/blink \>o/$m/blink/blink.gz scp silicon:blink/o/$m/blink/blink.gz \ /home/jart/cosmo/ape/blink-darwin-arm64.gz # smoke test the release ( cd ~/cosmo make -j8 o//test/libc/thread/pthread_create_test.com ) scp ~/cosmo/o//test/libc/thread/pthread_create_test.com silicon: ssh silicon ./pthread_create_test.com scp ~/cosmo/o//test/libc/thread/pthread_create_test.com pi: ssh pi ./pthread_create_test.com # we're finished o//blink/blink -v ls -hal \ ~/cosmo/ape/blink-aarch64.gz \ ~/cosmo/ape/blink-darwin-arm64.gz ================================================ FILE: tool/release-linux.sh ================================================ #!/bin/bash set -ex v=1.1 d=/mnt/videos/blink-$v [ ! -d $d ] mkdir -p $d ./configure --static --enable-vfs make -j32 \ o//x86_64/blink/blink \ o//x86_64/blink/blinkenlights \ o//aarch64/blink/blink \ o//aarch64/blink/blinkenlights \ o//arm/blink/blink \ o//arm/blink/blinkenlights \ o//i486/blink/blink \ o//i486/blink/blinkenlights \ o//mips/blink/blink \ o//mips/blink/blinkenlights \ o//mipsel/blink/blink \ o//mipsel/blink/blinkenlights \ o//mips64/blink/blink \ o//mips64/blink/blinkenlights \ o//mips64el/blink/blink \ o//mips64el/blink/blinkenlights \ o//powerpc/blink/blink \ o//powerpc/blink/blinkenlights \ o//powerpc64le/blink/blink \ o//powerpc64le/blink/blinkenlights \ o//s390x/blink/blink \ o//s390x/blink/blinkenlights pdf() { groff -Tps -man $1 >$2.ps ps2pdf $2.ps $2.pdf } git archive --format=tar.gz -o $d/blink-$v.tar.gz --prefix=blink-$v/ master pdf blink/blink.1 $d/blink-$v pdf blink/blinkenlights.1 $d/blinkenlights-$v gzip -9 $d/blink-$v-linux-x86_64.elf.gz gzip -9 $d/blinkenlights-$v-linux-x86_64.elf.gz gzip -9 $d/blink-$v-linux-aarch64.elf.gz gzip -9 $d/blinkenlights-$v-linux-aarch64.elf.gz gzip -9 $d/blink-$v-linux-arm.elf.gz gzip -9 $d/blinkenlights-$v-linux-arm.elf.gz gzip -9 $d/blink-$v-linux-i486.elf.gz gzip -9 $d/blinkenlights-$v-linux-i486.elf.gz gzip -9 $d/blink-$v-linux-mips.elf.gz gzip -9 $d/blinkenlights-$v-linux-mips.elf.gz gzip -9 $d/blink-$v-linux-mipsel.elf.gz gzip -9 $d/blinkenlights-$v-linux-mipsel.elf.gz gzip -9 $d/blink-$v-linux-mips64.elf.gz gzip -9 $d/blinkenlights-$v-linux-mips64.elf.gz gzip -9 $d/blink-$v-linux-mips64el.elf.gz gzip -9 $d/blinkenlights-$v-linux-mips64el.elf.gz gzip -9 $d/blink-$v-linux-powerpc.elf.gz gzip -9 $d/blinkenlights-$v-linux-powerpc.elf.gz gzip -9 $d/blink-$v-linux-powerpc64le.elf.gz gzip -9 $d/blinkenlights-$v-linux-powerpc64le.elf.gz gzip -9 $d/blink-$v-linux-s390x.elf.gz gzip -9 $d/blinkenlights-$v-linux-s390x.elf.gz ================================================ FILE: tool/sha256sum.c ================================================ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include #include #include #include #include #include #include #include #include // this file should not have dependencies, because everything will be // re-downloaded if the o/tool/sha256sum artifact becomes invalidated #define PROG "sha256sum" #define USAGE \ "\ Usage: " PROG " [-?hbctw] [PATH...]\n\ -h help\n\ -c check mode\n\ -b binary mode\n\ -t textual mode\n\ -w warning mode\n" #define ROTR(a, b) (((a) >> (b)) | ((a) << (32 - (b)))) #define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) #define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #define EP0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define EP1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define SIG0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3)) #define SIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10)) struct Sha256Ctx { uint8_t data[64]; uint32_t datalen; uint64_t bitlen; uint32_t state[8]; }; static const uint32_t kSha256Tab[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, // 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, // 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, // 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, // 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, // 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, // 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, // 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, // 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, // 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, // 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, // 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, // 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, // 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, // 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, // 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, // }; static bool g_warn; static char g_mode; static bool g_check; static int g_mismatches; static void Sha256Transform(uint32_t state[8], const uint8_t data[64]) { unsigned i; uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64]; for (i = 0; i < 16; ++i, data += 4) { m[i] = (uint32_t)data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; } for (; i < 64; ++i) { m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; } a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; for (i = 0; i < 64; ++i) { t1 = h + EP1(e) + CH(e, f, g) + kSha256Tab[i] + m[i]; t2 = EP0(a) + MAJ(a, b, c); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; } state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; } static void Sha256Init(struct Sha256Ctx *ctx) { ctx->datalen = 0; ctx->bitlen = 0; ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; ctx->state[2] = 0x3c6ef372; ctx->state[3] = 0xa54ff53a; ctx->state[4] = 0x510e527f; ctx->state[5] = 0x9b05688c; ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; } static void Sha256Update(struct Sha256Ctx *ctx, const uint8_t *data, long size) { long i; for (i = 0; i < size; ++i) { ctx->data[ctx->datalen] = data[i]; ctx->datalen++; if (ctx->datalen == 64) { Sha256Transform(ctx->state, ctx->data); ctx->bitlen += 512; ctx->datalen = 0; } } } static void Sha256Final(struct Sha256Ctx *ctx, uint8_t *hash) { long i; i = ctx->datalen; ctx->data[i++] = 0x80; if (ctx->datalen < 56) { memset(ctx->data + i, 0, 56 - i); } else { memset(ctx->data + i, 0, 64 - i); Sha256Transform(ctx->state, ctx->data); memset(ctx->data, 0, 56); } ctx->bitlen += ctx->datalen * 8; ctx->data[63] = ctx->bitlen; ctx->data[62] = ctx->bitlen >> 8; ctx->data[61] = ctx->bitlen >> 16; ctx->data[60] = ctx->bitlen >> 24; ctx->data[59] = ctx->bitlen >> 32; ctx->data[58] = ctx->bitlen >> 40; ctx->data[57] = ctx->bitlen >> 48; ctx->data[56] = ctx->bitlen >> 56; Sha256Transform(ctx->state, ctx->data); for (i = 0; i < 4; ++i) { hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff; hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff; hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff; hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff; hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff; hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff; hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff; hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff; } } static char *FormatUint32(char *p, uint32_t x) { char t; size_t i, a, b; i = 0; do { p[i++] = x % 10 + '0'; x = x / 10; } while (x > 0); p[i] = '\0'; if (i) { for (a = 0, b = i - 1; a < b; ++a, --b) { t = p[a]; p[a] = p[b]; p[b] = t; } } return p + i; } static char *FormatInt32(char *p, int32_t x) { if (x < 0) *p++ = '-', x = -(uint32_t)x; return FormatUint32(p, x); } static size_t StrCat(char *dst, const char *src, size_t dsize) { size_t m, n = dsize; const char *p = dst; const char *q = src; while (n-- != 0 && *dst != '\0') dst++; m = dst - p; n = dsize - m; if (n-- == 0) { return m + strlen(src); } while (*src != '\0') { if (n != 0) { *dst++ = *src; n--; } src++; } *dst = '\0'; return m + (src - q); } static void GetOpts(int argc, char *argv[]) { int opt; g_mode = ' '; while ((opt = getopt(argc, argv, "?hbctw")) != -1) { switch (opt) { case 'w': g_warn = true; break; case 'c': g_check = true; break; case 't': g_mode = ' '; break; case 'b': g_mode = '*'; break; case 'h': case '?': (void)write(1, USAGE, sizeof(USAGE) - 1); exit(0); default: (void)write(2, USAGE, sizeof(USAGE) - 1); exit(64); } } } static void Write(int fd, const char *s, ...) { va_list va; char buf[512]; buf[0] = 0; va_start(va, s); do { StrCat(buf, s, sizeof(buf)); } while ((s = va_arg(va, const char *))); va_end(va); (void)write(fd, buf, strlen(buf)); } static bool IsModeCharacter(char c) { switch (c) { case ' ': case '*': return true; default: return false; } } static bool IsSupportedPath(const char *path) { size_t i; for (i = 0;; ++i) { switch (path[i]) { case 0: if (i) return true; // fallthrough case '\r': case '\n': case '\\': Write(2, PROG, ": ", path, ": unsupported path\n", NULL); return false; default: break; } } } static bool GetDigest(const char *path, FILE *f, uint8_t digest[32]) { size_t got; uint8_t buf[512]; struct Sha256Ctx ctx; Sha256Init(&ctx); while ((got = fread(buf, 1, sizeof(buf), f))) { Sha256Update(&ctx, buf, got); } if (ferror(f)) { Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL); return false; } Sha256Final(&ctx, digest); return true; } static char *CopyHex(char *s, const void *p, size_t n) { const char *d, *e; for (d = (const char *)p, e = d + n; d < e; ++d) { *s++ = "0123456789abcdef"[(*d >> 4) & 15]; *s++ = "0123456789abcdef"[(*d >> 0) & 15]; } *s = 0; return s; } static bool ProduceDigest(const char *path, FILE *f) { char hexdigest[65]; char mode[2] = {g_mode}; unsigned char digest[32]; if (!IsSupportedPath(path)) return false; if (!GetDigest(path, f, digest)) return false; CopyHex(hexdigest, digest, 32); Write(1, hexdigest, " ", mode, path, "\n", NULL); return true; } static char *Chomp(char *line) { size_t i; if (line) { for (i = strlen(line); i--;) { if (line[i] == '\r' || line[i] == '\n') { line[i] = '\0'; } else { break; } } } return line; } static int HexToInt(int c) { if ('0' <= c && c <= '9') { return c - '0'; } else if ('a' <= c && c <= 'f') { return c - 'a' + 10; } else if ('A' <= c && c <= 'F') { return c - 'A' + 10; } else { return -1; } } static bool CheckDigests(const char *path, FILE *f) { FILE *f2; bool k = true; int a, b, i, line; const char *path2, *status; uint8_t wantdigest[32], gotdigest[32]; char buf[64 + 2 + PATH_MAX + 1 + 1], *p; for (line = 0; fgets(buf, sizeof(buf), f); ++line) { if (!*Chomp(buf)) continue; for (p = buf, i = 0; i < 32; ++i) { if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine; if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine; wantdigest[i] = a << 4 | b; } if (*p++ != ' ') goto InvalidLine; if (!IsModeCharacter(*p++)) goto InvalidLine; path2 = p; if (!*path2) goto InvalidLine; if (!IsSupportedPath(path2)) continue; if ((f2 = fopen(path2, "rb"))) { if (GetDigest(path2, f2, gotdigest)) { if (!memcmp(wantdigest, gotdigest, 32)) { status = "OK"; } else { status = "FAILED"; ++g_mismatches; k = false; } Write(1, path2, ": ", status, "\n", NULL); } else { k = false; } fclose(f2); } else { Write(2, PROG, ": ", path2, ": ", strerror(errno), "\n", NULL); k = false; } continue; InvalidLine: if (g_warn) { char linestr[12]; FormatInt32(linestr, line + 1); Write(2, PROG, ": ", path, ":", linestr, ": ", "improperly formatted checksum line", "\n", NULL); } } if (ferror(f)) { Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL); k = false; } return k; } static bool Process(const char *path, FILE *f) { if (g_check) { return CheckDigests(path, f); } else { return ProduceDigest(path, f); } } int main(int argc, char *argv[]) { int i; FILE *f; bool k = true; GetOpts(argc, argv); if (optind == argc) { f = stdin; k &= Process("-", f); } else { for (i = optind; i < argc; ++i) { if ((f = fopen(argv[i], "rb"))) { k &= Process(argv[i], f); fclose(f); } else { Write(2, PROG, ": ", argv[i], ": ", strerror(errno), "\n", NULL); k = false; } } } if (g_mismatches) { char ibuf[12]; FormatInt32(ibuf, g_mismatches); Write(2, PROG, ": WARNING: ", ibuf, " computed checksum did NOT match\n", NULL); } return !k; } ================================================ FILE: tool/size.sh ================================================ #!/bin/sh m=${1:-tiny} F=" o/$m/blink/blink o/$m/x86_64/blink/blink o/$m/aarch64/blink/blink o/$m/i486/blink/blink " make -j8 $F m=$m || exit for f in $F; do cp $f $f.strip done strip o/$m/blink/blink.strip o/third_party/gcc/x86_64/bin/x86_64-linux-musl-strip o/$m/x86_64/blink/blink.strip o/third_party/gcc/aarch64/bin/aarch64-linux-musl-strip o/$m/aarch64/blink/blink.strip o/third_party/gcc/i486/bin/i486-linux-musl-strip o/$m/i486/blink/blink.strip for f in $F; do ls -hal $f.strip done ================================================ FILE: tool/stdatomic/stdatomic.h ================================================ #ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ #define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) /** * @fileoverview Cosmopolitan C11 Atomics Library * * - Forty-two different ways to say MOV. * - Fourteen different ways to say XCHG. * - Twenty different ways to say LOCK CMPXCHG. * * @see libc/atomic.h */ #if __STDC_VERSION__ + 0 < 201112 #define _Atomic(TYPE) TYPE volatile #endif #define atomic_bool _Atomic(_Bool) #define atomic_bool32 _Atomic(__INT32_TYPE__) #define atomic_char _Atomic(char) #define atomic_schar _Atomic(signed char) #define atomic_uchar _Atomic(unsigned char) #define atomic_short _Atomic(short) #define atomic_ushort _Atomic(unsigned short) #define atomic_int _Atomic(int) #define atomic_uint _Atomic(unsigned int) #define atomic_long _Atomic(long) #define atomic_ulong _Atomic(unsigned long) #define atomic_llong _Atomic(long long) #define atomic_ullong _Atomic(unsigned long long) #define atomic_char16_t _Atomic(__CHAR16_TYPE__) #define atomic_char32_t _Atomic(__CHAR32_TYPE__) #define atomic_wchar_t _Atomic(__WCHAR_TYPE__) #define atomic_intptr_t _Atomic(__INTPTR_TYPE__) #define atomic_uintptr_t _Atomic(__UINTPTR_TYPE__) #define atomic_size_t _Atomic(__SIZE_TYPE__) #define atomic_ptrdiff_t _Atomic(__PTRDIFF_TYPE__) #define atomic_int_fast8_t _Atomic(__INT_FAST8_TYPE__) #define atomic_uint_fast8_t _Atomic(__UINT_FAST8_TYPE__) #define atomic_int_fast16_t _Atomic(__INT_FAST16_TYPE__) #define atomic_uint_fast16_t _Atomic(__UINT_FAST16_TYPE__) #define atomic_int_fast32_t _Atomic(__INT_FAST32_TYPE__) #define atomic_uint_fast32_t _Atomic(__UINT_FAST32_TYPE__) #define atomic_int_fast64_t _Atomic(__INT_FAST64_TYPE__) #define atomic_uint_fast64_t _Atomic(__UINT_FAST64_TYPE__) #define atomic_int_least8_t _Atomic(__INT_LEAST8_TYPE__) #define atomic_uint_least8_t _Atomic(__UINT_LEAST8_TYPE__) #define atomic_int_least16_t _Atomic(__INT_LEAST16_TYPE__) #define atomic_uint_least16_t _Atomic(__UINT_LEAST16_TYPE__) #define atomic_int_least32_t _Atomic(__INT_LEAST32_TYPE__) #define atomic_uint_least32_t _Atomic(__UINT_LEAST32_TYPE__) #define atomic_int_least64_t _Atomic(__INT_LEAST64_TYPE__) #define atomic_uint_least64_t _Atomic(__UINT_LEAST64_TYPE__) #ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE #define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE #define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE #define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE #define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE #define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE #define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE #define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE #define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE #else #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE #define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE #define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE #define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE #define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE #define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE #define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE #define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE #define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE #endif #define memory_order int #define memory_order_relaxed 0 #define memory_order_consume 1 #define memory_order_acquire 2 #define memory_order_release 3 #define memory_order_acq_rel 4 #define memory_order_seq_cst 5 #define ATOMIC_VAR_INIT(...) __VA_ARGS__ #define atomic_is_lock_free(obj) ((void)(obj), sizeof(obj) <= sizeof(void *)) #define atomic_flag atomic_bool #define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0) #define atomic_flag_test_and_set_explicit(x, order) \ atomic_exchange_explicit(x, 1, order) #define atomic_flag_clear_explicit(x, order) atomic_store_explicit(x, 0, order) #define atomic_compare_exchange_strong(pObject, pExpected, desired) \ atomic_compare_exchange_strong_explicit( \ pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst) #define atomic_compare_exchange_weak(pObject, pExpected, desired) \ atomic_compare_exchange_weak_explicit( \ pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst) #define atomic_exchange(pObject, desired) \ atomic_exchange_explicit(pObject, desired, memory_order_seq_cst) #define atomic_fetch_add(pObject, operand) \ atomic_fetch_add_explicit(pObject, operand, memory_order_seq_cst) #define atomic_fetch_and(pObject, operand) \ atomic_fetch_and_explicit(pObject, operand, memory_order_seq_cst) #define atomic_fetch_or(pObject, operand) \ atomic_fetch_or_explicit(pObject, operand, memory_order_seq_cst) #define atomic_fetch_sub(pObject, operand) \ atomic_fetch_sub_explicit(pObject, operand, memory_order_seq_cst) #define atomic_fetch_xor(pObject, operand) \ atomic_fetch_xor_explicit(pObject, operand, memory_order_seq_cst) #define atomic_load(pObject) atomic_load_explicit(pObject, memory_order_seq_cst) #define atomic_store(pObject, desired) \ atomic_store_explicit(pObject, desired, memory_order_seq_cst) #define atomic_flag_test_and_set(x) \ atomic_flag_test_and_set_explicit(x, memory_order_seq_cst) #define atomic_flag_clear(x) atomic_flag_clear_explicit(x, memory_order_seq_cst) #if defined(__CLANG_ATOMIC_BOOL_LOCK_FREE) #define atomic_init(obj, value) __c11_atomic_init(obj, value) #define atomic_thread_fence(order) __c11_atomic_thread_fence(order) #define atomic_signal_fence(order) __c11_atomic_signal_fence(order) #define atomic_compare_exchange_strong_explicit(object, expected, desired, \ success, failure) \ __c11_atomic_compare_exchange_strong(object, expected, desired, success, \ failure) #define atomic_compare_exchange_weak_explicit(object, expected, desired, \ success, failure) \ __c11_atomic_compare_exchange_weak(object, expected, desired, success, \ failure) #define atomic_exchange_explicit(object, desired, order) \ __c11_atomic_exchange(object, desired, order) #define atomic_fetch_add_explicit(object, operand, order) \ __c11_atomic_fetch_add(object, operand, order) #define atomic_fetch_and_explicit(object, operand, order) \ __c11_atomic_fetch_and(object, operand, order) #define atomic_fetch_or_explicit(object, operand, order) \ __c11_atomic_fetch_or(object, operand, order) #define atomic_fetch_sub_explicit(object, operand, order) \ __c11_atomic_fetch_sub(object, operand, order) #define atomic_fetch_xor_explicit(object, operand, order) \ __c11_atomic_fetch_xor(object, operand, order) #define atomic_load_explicit(object, order) __c11_atomic_load(object, order) #define atomic_store_explicit(object, desired, order) \ __c11_atomic_store(object, desired, order) #elif (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 #define atomic_init(obj, value) ((void)(*(obj) = (value))) #define atomic_thread_fence(order) __atomic_thread_fence(order) #define atomic_signal_fence(order) __atomic_signal_fence(order) #define atomic_compare_exchange_strong_explicit(pObject, pExpected, desired, \ success, failure) \ __atomic_compare_exchange_n(pObject, pExpected, desired, 0, success, failure) #define atomic_compare_exchange_weak_explicit(pObject, pExpected, desired, \ success, failure) \ __atomic_compare_exchange_n(pObject, pExpected, desired, 1, success, failure) #define atomic_exchange_explicit(pObject, desired, order) \ __atomic_exchange_n(pObject, desired, order) #define atomic_fetch_add_explicit(pObject, operand, order) \ __atomic_fetch_add(pObject, operand, order) #define atomic_fetch_and_explicit(pObject, operand, order) \ __atomic_fetch_and(pObject, operand, order) #define atomic_fetch_or_explicit(pObject, operand, order) \ __atomic_fetch_or(pObject, operand, order) #define atomic_fetch_sub_explicit(pObject, operand, order) \ __atomic_fetch_sub(pObject, operand, order) #define atomic_fetch_xor_explicit(pObject, operand, order) \ __atomic_fetch_xor(pObject, operand, order) #define atomic_load_explicit(pObject, order) __atomic_load_n(pObject, order) #define atomic_store_explicit(pObject, desired, order) \ __atomic_store_n(pObject, desired, order) #elif (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 401 #define atomic_init(obj, value) ((void)(*(obj) = (value))) #define atomic_thread_fence(order) __sync_synchronize() #define atomic_signal_fence(order) __asm__ volatile("" ::: "memory") #define __atomic_apply_stride(object, operand) \ (((__typeof__(*(object)))0) + (operand)) #define atomic_compare_exchange_strong_explicit(object, expected, desired, \ success_order, failure_order) \ __extension__({ \ __typeof__(expected) __ep = (expected); \ __typeof__(*__ep) __e = *__ep; \ (void)(success_order); \ (void)(failure_order); \ (*__ep = __sync_val_compare_and_swap(object, __e, desired)) == __e; \ }) #define atomic_compare_exchange_weak_explicit(object, expected, desired, \ success_order, failure_order) \ atomic_compare_exchange_strong_explicit(object, expected, desired, \ success_order, failure_order) #if __has_builtin(__sync_swap) #define atomic_exchange_explicit(object, desired, order) \ ((void)(order), __sync_swap(object, desired)) #else #define atomic_exchange_explicit(object, desired, order) \ __extension__({ \ __typeof__(object) __o = (object); \ __typeof__(desired) __d = (desired); \ (void)(order); \ __sync_synchronize(); \ __sync_lock_test_and_set(__o, __d); \ }) #endif #define atomic_fetch_add_explicit(object, operand, order) \ ((void)(order), \ __sync_fetch_and_add(object, __atomic_apply_stride(object, operand))) #define atomic_fetch_and_explicit(object, operand, order) \ ((void)(order), __sync_fetch_and_and(object, operand)) #define atomic_fetch_or_explicit(object, operand, order) \ ((void)(order), __sync_fetch_and_or(object, operand)) #define atomic_fetch_sub_explicit(object, operand, order) \ ((void)(order), \ __sync_fetch_and_sub(object, __atomic_apply_stride(object, operand))) #define atomic_fetch_xor_explicit(object, operand, order) \ ((void)(order), __sync_fetch_and_xor(object, operand)) #define atomic_load_explicit(object, order) \ ((void)(order), __sync_fetch_and_add(object, 0)) #define atomic_store_explicit(object, desired, order) \ ((void)atomic_exchange_explicit(object, desired, order)) #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) #define atomic_init(obj, value) ((void)(*(obj) = (value))) #define atomic_thread_fence(order) __asm__ volatile("mfence" ::: "memory") #define atomic_signal_fence(order) __asm__ volatile("" ::: "memory") #define atomic_compare_exchange_strong_explicit(object, expected, desired, \ success_order, failure_order) \ __extension__({ \ char DidIt; \ __typeof__(object) IfThing = (object); \ __typeof__(IfThing) IsEqualToMe = (expected); \ __typeof__(*IfThing) ReplaceItWithMe = (desired), ax; \ (void)(success_order); \ (void)(failure_order); \ __asm__ volatile("lock cmpxchg\t%3,(%1)\n\t" \ "setz\t%b0" \ : "=q"(DidIt), "=r"(IfThing), "+a"(ax) \ : "r"(ReplaceItWithMe), "2"(*IsEqualToMe) \ : "memory", "cc"); \ *IsEqualToMe = ax; \ DidIt; \ }) #define atomic_compare_exchange_weak_explicit(object, expected, desired, \ success_order, failure_order) \ atomic_compare_exchange_strong_explicit(object, expected, desired, \ success_order, failure_order) #define atomic_exchange_explicit(object, desired, order) \ __extension__({ \ __typeof__(object) __o = (object); \ __typeof__(*__o) __d = (desired); \ (void)(order); \ __asm__ volatile("xchg\t%0,%1" : "=r"(__d), "+m"(*__o) : "0"(__d)); \ __d; \ }) #define atomic_fetch_add_explicit(object, operand, order) \ __extension__({ \ __typeof__(object) __o = (object); \ __typeof__(*__o) __d = (desired); \ (void)(order); \ __asm__ volatile("lock xadd\t%0,%1" : "=r"(__d), "+m"(*__o) : "0"(__d)); \ __d; \ }) #define atomic_fetch_sub_explicit(object, operand, order) \ atomic_fetch_add_explicit(object, -(operand), order) #define atomic_load_explicit(object, order) \ atomic_fetch_add_explicit(object, 0, order) #define atomic_store_explicit(object, desired, order) \ ((void)atomic_exchange_explicit(object, desired, order)) #else /* non-gcc or old gcc w/o x86 */ #error "atomic operations not supported with this compiler and/or architecture" #endif #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ */